| author | |
| committer | |
| log | 3a600297ca3f99ee57630c44900eec1fe7c92804 |
| tree | 9642e53df266077c0ee76c1a045366f8f805fe95 |
| parent | 4a82c2d124881512548254f5cdff3009b2f424df |
| parent | 634e8713c394bacfe080d03256d1dd4f9a43dd8c |
19 files changed, 794 insertions(+), 150 deletions(-)
src-self-hosted/main.zig+8-6| ... | ... | @@ -3,24 +3,27 @@ const io = @import("std").io; |
| 3 | 3 | const os = @import("std").os; |
| 4 | 4 | const heap = @import("std").mem; |
| 5 | 5 | |
| 6 | // TODO: OutSteam and InStream interface | |
| 7 | // TODO: move allocator to heap namespace | |
| 8 | 6 | // TODO: sync up CLI with c++ code |
| 7 | // TODO: concurrency | |
| 9 | 8 | |
| 10 | 9 | error InvalidArgument; |
| 11 | 10 | error MissingArg0; |
| 12 | 11 | |
| 13 | 12 | var arg0: []u8 = undefined; |
| 14 | 13 | |
| 14 | var stderr_file: io.File = undefined; | |
| 15 | const stderr = &stderr_file.out_stream; | |
| 16 | ||
| 15 | 17 | pub fn main() -> %void { |
| 18 | stderr_file = %return io.getStdErr(); | |
| 16 | 19 | if (internal_main()) |_| { |
| 17 | 20 | return; |
| 18 | 21 | } else |err| { |
| 19 | 22 | if (err == error.InvalidArgument) { |
| 20 | io.stderr.printf("\n") %% return err; | |
| 21 | printUsage(&io.stderr) %% return err; | |
| 23 | stderr.print("\n") %% return err; | |
| 24 | printUsage(stderr) %% return err; | |
| 22 | 25 | } else { |
| 23 | io.stderr.printf("{}\n", err) %% return err; | |
| 26 | stderr.print("{}\n", err) %% return err; | |
| 24 | 27 | } |
| 25 | 28 | return err; |
| 26 | 29 | } |
| ... | ... | @@ -266,7 +269,6 @@ fn printUsage(outstream: &io.OutStream) -> %void { |
| 266 | 269 | \\ --test-cmd-bin appends test binary path to test cmd args |
| 267 | 270 | \\ |
| 268 | 271 | ); |
| 269 | %return outstream.flush(); | |
| 270 | 272 | } |
| 271 | 273 | |
| 272 | 274 | const ZIG_ZEN = |
src/all_types.hpp+34| ... | ... | @@ -1211,6 +1211,8 @@ enum BuiltinFnId { |
| 1211 | 1211 | BuiltinFnIdMaxValue, |
| 1212 | 1212 | BuiltinFnIdMinValue, |
| 1213 | 1213 | BuiltinFnIdMemberCount, |
| 1214 | BuiltinFnIdMemberType, | |
| 1215 | BuiltinFnIdMemberName, | |
| 1214 | 1216 | BuiltinFnIdTypeof, |
| 1215 | 1217 | BuiltinFnIdAddWithOverflow, |
| 1216 | 1218 | BuiltinFnIdSubWithOverflow, |
| ... | ... | @@ -1261,6 +1263,7 @@ enum BuiltinFnId { |
| 1261 | 1263 | BuiltinFnIdAlignCast, |
| 1262 | 1264 | BuiltinFnIdOpaqueType, |
| 1263 | 1265 | BuiltinFnIdSetAlignStack, |
| 1266 | BuiltinFnIdArgType, | |
| 1264 | 1267 | }; |
| 1265 | 1268 | |
| 1266 | 1269 | struct BuiltinFnEntry { |
| ... | ... | @@ -1366,6 +1369,12 @@ enum BuildMode { |
| 1366 | 1369 | BuildModeSafeRelease, |
| 1367 | 1370 | }; |
| 1368 | 1371 | |
| 1372 | enum EmitFileType { | |
| 1373 | EmitFileTypeBinary, | |
| 1374 | EmitFileTypeAssembly, | |
| 1375 | EmitFileTypeLLVMIr, | |
| 1376 | }; | |
| 1377 | ||
| 1369 | 1378 | struct LinkLib { |
| 1370 | 1379 | Buf *name; |
| 1371 | 1380 | Buf *path; |
| ... | ... | @@ -1449,6 +1458,7 @@ struct CodeGen { |
| 1449 | 1458 | TypeTableEntry *entry_arg_tuple; |
| 1450 | 1459 | } builtin_types; |
| 1451 | 1460 | |
| 1461 | EmitFileType emit_file_type; | |
| 1452 | 1462 | ZigTarget zig_target; |
| 1453 | 1463 | LLVMTargetDataRef target_data_ref; |
| 1454 | 1464 | unsigned pointer_size_bytes; |
| ... | ... | @@ -1837,6 +1847,8 @@ enum IrInstructionId { |
| 1837 | 1847 | IrInstructionIdMemcpy, |
| 1838 | 1848 | IrInstructionIdSlice, |
| 1839 | 1849 | IrInstructionIdMemberCount, |
| 1850 | IrInstructionIdMemberType, | |
| 1851 | IrInstructionIdMemberName, | |
| 1840 | 1852 | IrInstructionIdBreakpoint, |
| 1841 | 1853 | IrInstructionIdReturnAddress, |
| 1842 | 1854 | IrInstructionIdFrameAddress, |
| ... | ... | @@ -1875,6 +1887,7 @@ enum IrInstructionId { |
| 1875 | 1887 | IrInstructionIdAlignCast, |
| 1876 | 1888 | IrInstructionIdOpaqueType, |
| 1877 | 1889 | IrInstructionIdSetAlignStack, |
| 1890 | IrInstructionIdArgType, | |
| 1878 | 1891 | }; |
| 1879 | 1892 | |
| 1880 | 1893 | struct IrInstruction { |
| ... | ... | @@ -2399,6 +2412,20 @@ struct IrInstructionMemberCount { |
| 2399 | 2412 | IrInstruction *container; |
| 2400 | 2413 | }; |
| 2401 | 2414 | |
| 2415 | struct IrInstructionMemberType { | |
| 2416 | IrInstruction base; | |
| 2417 | ||
| 2418 | IrInstruction *container_type; | |
| 2419 | IrInstruction *member_index; | |
| 2420 | }; | |
| 2421 | ||
| 2422 | struct IrInstructionMemberName { | |
| 2423 | IrInstruction base; | |
| 2424 | ||
| 2425 | IrInstruction *container_type; | |
| 2426 | IrInstruction *member_index; | |
| 2427 | }; | |
| 2428 | ||
| 2402 | 2429 | struct IrInstructionBreakpoint { |
| 2403 | 2430 | IrInstruction base; |
| 2404 | 2431 | }; |
| ... | ... | @@ -2675,6 +2702,13 @@ struct IrInstructionSetAlignStack { |
| 2675 | 2702 | IrInstruction *align_bytes; |
| 2676 | 2703 | }; |
| 2677 | 2704 | |
| 2705 | struct IrInstructionArgType { | |
| 2706 | IrInstruction base; | |
| 2707 | ||
| 2708 | IrInstruction *fn_type; | |
| 2709 | IrInstruction *arg_index; | |
| 2710 | }; | |
| 2711 | ||
| 2678 | 2712 | static const size_t slice_ptr_index = 0; |
| 2679 | 2713 | static const size_t slice_len_index = 1; |
| 2680 | 2714 |
src/analyze.cpp+140-111| ... | ... | @@ -1366,119 +1366,140 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { |
| 1366 | 1366 | enum_type->data.enumeration.union_size_bytes = biggest_size_in_bits / 8; |
| 1367 | 1367 | enum_type->data.enumeration.most_aligned_union_member = most_aligned_union_member; |
| 1368 | 1368 | |
| 1369 | if (!enum_type->data.enumeration.is_invalid) { | |
| 1370 | TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count); | |
| 1371 | TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type); | |
| 1372 | enum_type->data.enumeration.tag_type = tag_type_entry; | |
| 1373 | ||
| 1374 | uint64_t align_of_tag_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref); | |
| 1375 | ||
| 1376 | if (most_aligned_union_member) { | |
| 1377 | // create llvm type for union | |
| 1378 | uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits; | |
| 1379 | LLVMTypeRef union_type_ref; | |
| 1380 | if (padding_in_bits > 0) { | |
| 1381 | TypeTableEntry *u8_type = get_int_type(g, false, 8); | |
| 1382 | TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8); | |
| 1383 | LLVMTypeRef union_element_types[] = { | |
| 1384 | most_aligned_union_member->type_ref, | |
| 1385 | padding_array->type_ref, | |
| 1386 | }; | |
| 1387 | union_type_ref = LLVMStructType(union_element_types, 2, false); | |
| 1388 | } else { | |
| 1389 | union_type_ref = most_aligned_union_member->type_ref; | |
| 1390 | } | |
| 1391 | enum_type->data.enumeration.union_type_ref = union_type_ref; | |
| 1369 | if (enum_type->data.enumeration.is_invalid) | |
| 1370 | return; | |
| 1392 | 1371 | |
| 1393 | assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type_ref) >= biggest_align_in_bits); | |
| 1394 | assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type_ref) >= biggest_size_in_bits); | |
| 1372 | if (enum_type->zero_bits) { | |
| 1373 | enum_type->type_ref = LLVMVoidType(); | |
| 1395 | 1374 | |
| 1396 | if (align_of_tag_in_bits >= biggest_align_in_bits) { | |
| 1397 | enum_type->data.enumeration.gen_tag_index = 0; | |
| 1398 | enum_type->data.enumeration.gen_union_index = 1; | |
| 1399 | } else { | |
| 1400 | enum_type->data.enumeration.gen_union_index = 0; | |
| 1401 | enum_type->data.enumeration.gen_tag_index = 1; | |
| 1402 | } | |
| 1375 | uint64_t debug_size_in_bits = 0; | |
| 1376 | uint64_t debug_align_in_bits = 0; | |
| 1377 | ZigLLVMDIType **di_root_members = nullptr; | |
| 1378 | size_t debug_member_count = 0; | |
| 1379 | ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, | |
| 1380 | ZigLLVMFileToScope(import->di_file), | |
| 1381 | buf_ptr(&enum_type->name), | |
| 1382 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 1383 | debug_size_in_bits, | |
| 1384 | debug_align_in_bits, | |
| 1385 | 0, nullptr, di_root_members, (int)debug_member_count, 0, nullptr, ""); | |
| 1403 | 1386 | |
| 1404 | // create llvm type for root struct | |
| 1405 | LLVMTypeRef root_struct_element_types[2]; | |
| 1406 | root_struct_element_types[enum_type->data.enumeration.gen_tag_index] = tag_type_entry->type_ref; | |
| 1407 | root_struct_element_types[enum_type->data.enumeration.gen_union_index] = union_type_ref; | |
| 1408 | LLVMStructSetBody(enum_type->type_ref, root_struct_element_types, 2, false); | |
| 1409 | ||
| 1410 | // create debug type for tag | |
| 1411 | uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref); | |
| 1412 | uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref); | |
| 1413 | ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder, | |
| 1414 | ZigLLVMTypeToScope(enum_type->di_type), "AnonEnum", | |
| 1415 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 1416 | tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count, | |
| 1417 | tag_type_entry->di_type, ""); | |
| 1418 | ||
| 1419 | // create debug type for union | |
| 1420 | ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder, | |
| 1421 | ZigLLVMTypeToScope(enum_type->di_type), "AnonUnion", | |
| 1422 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 1423 | biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types, | |
| 1424 | gen_field_count, 0, ""); | |
| 1425 | ||
| 1426 | // create debug types for members of root struct | |
| 1427 | uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref, | |
| 1428 | enum_type->data.enumeration.gen_tag_index); | |
| 1429 | ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder, | |
| 1430 | ZigLLVMTypeToScope(enum_type->di_type), "tag_field", | |
| 1431 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 1432 | tag_debug_size_in_bits, | |
| 1433 | tag_debug_align_in_bits, | |
| 1434 | tag_offset_in_bits, | |
| 1435 | 0, tag_di_type); | |
| 1436 | ||
| 1437 | uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref, | |
| 1438 | enum_type->data.enumeration.gen_union_index); | |
| 1439 | ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder, | |
| 1440 | ZigLLVMTypeToScope(enum_type->di_type), "union_field", | |
| 1441 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 1442 | biggest_size_in_bits, | |
| 1443 | biggest_align_in_bits, | |
| 1444 | union_offset_in_bits, | |
| 1445 | 0, union_di_type); | |
| 1446 | ||
| 1447 | // create debug type for root struct | |
| 1448 | ZigLLVMDIType *di_root_members[2]; | |
| 1449 | di_root_members[enum_type->data.enumeration.gen_tag_index] = tag_member_di_type; | |
| 1450 | di_root_members[enum_type->data.enumeration.gen_union_index] = union_member_di_type; | |
| 1451 | ||
| 1452 | uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, enum_type->type_ref); | |
| 1453 | uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, enum_type->type_ref); | |
| 1454 | ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, | |
| 1455 | ZigLLVMFileToScope(import->di_file), | |
| 1456 | buf_ptr(&enum_type->name), | |
| 1457 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 1458 | debug_size_in_bits, | |
| 1459 | debug_align_in_bits, | |
| 1460 | 0, nullptr, di_root_members, 2, 0, nullptr, ""); | |
| 1461 | ||
| 1462 | ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, replacement_di_type); | |
| 1463 | enum_type->di_type = replacement_di_type; | |
| 1387 | ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, replacement_di_type); | |
| 1388 | enum_type->di_type = replacement_di_type; | |
| 1389 | return; | |
| 1390 | } | |
| 1391 | ||
| 1392 | TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count); | |
| 1393 | TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type); | |
| 1394 | enum_type->data.enumeration.tag_type = tag_type_entry; | |
| 1395 | ||
| 1396 | uint64_t align_of_tag_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref); | |
| 1397 | ||
| 1398 | if (most_aligned_union_member) { | |
| 1399 | // create llvm type for union | |
| 1400 | uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits; | |
| 1401 | LLVMTypeRef union_type_ref; | |
| 1402 | if (padding_in_bits > 0) { | |
| 1403 | TypeTableEntry *u8_type = get_int_type(g, false, 8); | |
| 1404 | TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8); | |
| 1405 | LLVMTypeRef union_element_types[] = { | |
| 1406 | most_aligned_union_member->type_ref, | |
| 1407 | padding_array->type_ref, | |
| 1408 | }; | |
| 1409 | union_type_ref = LLVMStructType(union_element_types, 2, false); | |
| 1464 | 1410 | } else { |
| 1465 | // create llvm type for root struct | |
| 1466 | enum_type->type_ref = tag_type_entry->type_ref; | |
| 1467 | ||
| 1468 | // create debug type for tag | |
| 1469 | uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref); | |
| 1470 | uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref); | |
| 1471 | ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder, | |
| 1472 | ZigLLVMFileToScope(import->di_file), buf_ptr(&enum_type->name), | |
| 1473 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 1474 | tag_debug_size_in_bits, | |
| 1475 | tag_debug_align_in_bits, | |
| 1476 | di_enumerators, field_count, | |
| 1477 | tag_type_entry->di_type, ""); | |
| 1411 | union_type_ref = most_aligned_union_member->type_ref; | |
| 1412 | } | |
| 1413 | enum_type->data.enumeration.union_type_ref = union_type_ref; | |
| 1414 | ||
| 1415 | assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type_ref) >= biggest_align_in_bits); | |
| 1416 | assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type_ref) >= biggest_size_in_bits); | |
| 1478 | 1417 | |
| 1479 | ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, tag_di_type); | |
| 1480 | enum_type->di_type = tag_di_type; | |
| 1418 | if (align_of_tag_in_bits >= biggest_align_in_bits) { | |
| 1419 | enum_type->data.enumeration.gen_tag_index = 0; | |
| 1420 | enum_type->data.enumeration.gen_union_index = 1; | |
| 1421 | } else { | |
| 1422 | enum_type->data.enumeration.gen_union_index = 0; | |
| 1423 | enum_type->data.enumeration.gen_tag_index = 1; | |
| 1481 | 1424 | } |
| 1425 | ||
| 1426 | // create llvm type for root struct | |
| 1427 | LLVMTypeRef root_struct_element_types[2]; | |
| 1428 | root_struct_element_types[enum_type->data.enumeration.gen_tag_index] = tag_type_entry->type_ref; | |
| 1429 | root_struct_element_types[enum_type->data.enumeration.gen_union_index] = union_type_ref; | |
| 1430 | LLVMStructSetBody(enum_type->type_ref, root_struct_element_types, 2, false); | |
| 1431 | ||
| 1432 | // create debug type for tag | |
| 1433 | uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref); | |
| 1434 | uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref); | |
| 1435 | ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder, | |
| 1436 | ZigLLVMTypeToScope(enum_type->di_type), "AnonEnum", | |
| 1437 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 1438 | tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count, | |
| 1439 | tag_type_entry->di_type, ""); | |
| 1440 | ||
| 1441 | // create debug type for union | |
| 1442 | ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder, | |
| 1443 | ZigLLVMTypeToScope(enum_type->di_type), "AnonUnion", | |
| 1444 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 1445 | biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types, | |
| 1446 | gen_field_count, 0, ""); | |
| 1447 | ||
| 1448 | // create debug types for members of root struct | |
| 1449 | uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref, | |
| 1450 | enum_type->data.enumeration.gen_tag_index); | |
| 1451 | ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder, | |
| 1452 | ZigLLVMTypeToScope(enum_type->di_type), "tag_field", | |
| 1453 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 1454 | tag_debug_size_in_bits, | |
| 1455 | tag_debug_align_in_bits, | |
| 1456 | tag_offset_in_bits, | |
| 1457 | 0, tag_di_type); | |
| 1458 | ||
| 1459 | uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref, | |
| 1460 | enum_type->data.enumeration.gen_union_index); | |
| 1461 | ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder, | |
| 1462 | ZigLLVMTypeToScope(enum_type->di_type), "union_field", | |
| 1463 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 1464 | biggest_size_in_bits, | |
| 1465 | biggest_align_in_bits, | |
| 1466 | union_offset_in_bits, | |
| 1467 | 0, union_di_type); | |
| 1468 | ||
| 1469 | // create debug type for root struct | |
| 1470 | ZigLLVMDIType *di_root_members[2]; | |
| 1471 | di_root_members[enum_type->data.enumeration.gen_tag_index] = tag_member_di_type; | |
| 1472 | di_root_members[enum_type->data.enumeration.gen_union_index] = union_member_di_type; | |
| 1473 | ||
| 1474 | uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, enum_type->type_ref); | |
| 1475 | uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, enum_type->type_ref); | |
| 1476 | ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, | |
| 1477 | ZigLLVMFileToScope(import->di_file), | |
| 1478 | buf_ptr(&enum_type->name), | |
| 1479 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 1480 | debug_size_in_bits, | |
| 1481 | debug_align_in_bits, | |
| 1482 | 0, nullptr, di_root_members, 2, 0, nullptr, ""); | |
| 1483 | ||
| 1484 | ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, replacement_di_type); | |
| 1485 | enum_type->di_type = replacement_di_type; | |
| 1486 | } else { | |
| 1487 | // create llvm type for root struct | |
| 1488 | enum_type->type_ref = tag_type_entry->type_ref; | |
| 1489 | ||
| 1490 | // create debug type for tag | |
| 1491 | uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref); | |
| 1492 | uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref); | |
| 1493 | ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder, | |
| 1494 | ZigLLVMFileToScope(import->di_file), buf_ptr(&enum_type->name), | |
| 1495 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 1496 | tag_debug_size_in_bits, | |
| 1497 | tag_debug_align_in_bits, | |
| 1498 | di_enumerators, field_count, | |
| 1499 | tag_type_entry->di_type, ""); | |
| 1500 | ||
| 1501 | ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, tag_di_type); | |
| 1502 | enum_type->di_type = tag_di_type; | |
| 1482 | 1503 | } |
| 1483 | 1504 | } |
| 1484 | 1505 | |
| ... | ... | @@ -1875,9 +1896,11 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) { |
| 1875 | 1896 | enum_type->data.enumeration.zero_bits_known = true; |
| 1876 | 1897 | |
| 1877 | 1898 | // also compute abi_alignment |
| 1878 | TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count); | |
| 1879 | uint32_t align_of_tag_in_bytes = LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref); | |
| 1880 | enum_type->data.enumeration.abi_alignment = max(align_of_tag_in_bytes, biggest_align_bytes); | |
| 1899 | if (!enum_type->zero_bits) { | |
| 1900 | TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count); | |
| 1901 | uint32_t align_of_tag_in_bytes = LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref); | |
| 1902 | enum_type->data.enumeration.abi_alignment = max(align_of_tag_in_bytes, biggest_align_bytes); | |
| 1903 | } | |
| 1881 | 1904 | } |
| 1882 | 1905 | |
| 1883 | 1906 | static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) { |
| ... | ... | @@ -3440,8 +3463,14 @@ void find_libc_lib_path(CodeGen *g) { |
| 3440 | 3463 | zig_panic("Unable to determine libc lib path."); |
| 3441 | 3464 | } |
| 3442 | 3465 | } |
| 3466 | ||
| 3443 | 3467 | if (!g->libc_static_lib_dir || buf_len(g->libc_static_lib_dir) == 0) { |
| 3444 | zig_panic("Unable to determine libc static lib path."); | |
| 3468 | if ((g->zig_target.os == ZigLLVM_Win32) && (g->msvc_lib_dir != NULL)) { | |
| 3469 | return; | |
| 3470 | } | |
| 3471 | else { | |
| 3472 | zig_panic("Unable to determine libc static lib path."); | |
| 3473 | } | |
| 3445 | 3474 | } |
| 3446 | 3475 | } |
| 3447 | 3476 |
src/c_tokenizer.cpp+4-1| ... | ... | @@ -91,6 +91,9 @@ |
| 91 | 91 | IDENT_START: \ |
| 92 | 92 | case DIGIT |
| 93 | 93 | |
| 94 | #define LINE_ENDING \ | |
| 95 | '\r': \ | |
| 96 | case '\n' | |
| 94 | 97 | |
| 95 | 98 | static void begin_token(CTokenize *ctok, CTokId id) { |
| 96 | 99 | assert(ctok->cur_tok == nullptr); |
| ... | ... | @@ -191,7 +194,7 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) { |
| 191 | 194 | case '\\': |
| 192 | 195 | ctok->state = CTokStateBackslash; |
| 193 | 196 | break; |
| 194 | case '\n': | |
| 197 | case LINE_ENDING: | |
| 195 | 198 | goto found_end_of_macro; |
| 196 | 199 | case IDENT_START: |
| 197 | 200 | ctok->state = CTokStateIdentifier; |
src/codegen.cpp+67-11| ... | ... | @@ -189,6 +189,10 @@ void codegen_set_is_test(CodeGen *g, bool is_test_build) { |
| 189 | 189 | g->is_test_build = is_test_build; |
| 190 | 190 | } |
| 191 | 191 | |
| 192 | void codegen_set_emit_file_type(CodeGen *g, EmitFileType emit_file_type) { | |
| 193 | g->emit_file_type = emit_file_type; | |
| 194 | } | |
| 195 | ||
| 192 | 196 | void codegen_set_is_static(CodeGen *g, bool is_static) { |
| 193 | 197 | g->is_static = is_static; |
| 194 | 198 | } |
| ... | ... | @@ -3380,6 +3384,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 3380 | 3384 | case IrInstructionIdEmbedFile: |
| 3381 | 3385 | case IrInstructionIdIntType: |
| 3382 | 3386 | case IrInstructionIdMemberCount: |
| 3387 | case IrInstructionIdMemberType: | |
| 3388 | case IrInstructionIdMemberName: | |
| 3383 | 3389 | case IrInstructionIdAlignOf: |
| 3384 | 3390 | case IrInstructionIdFnProto: |
| 3385 | 3391 | case IrInstructionIdTestComptime: |
| ... | ... | @@ -3397,6 +3403,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 3397 | 3403 | case IrInstructionIdPtrTypeOf: |
| 3398 | 3404 | case IrInstructionIdOpaqueType: |
| 3399 | 3405 | case IrInstructionIdSetAlignStack: |
| 3406 | case IrInstructionIdArgType: | |
| 3400 | 3407 | zig_unreachable(); |
| 3401 | 3408 | case IrInstructionIdReturn: |
| 3402 | 3409 | return ir_render_return(g, executable, (IrInstructionReturn *)instruction); |
| ... | ... | @@ -4493,24 +4500,70 @@ static void do_code_gen(CodeGen *g) { |
| 4493 | 4500 | LLVMVerifyModule(g->module, LLVMAbortProcessAction, &error); |
| 4494 | 4501 | #endif |
| 4495 | 4502 | |
| 4496 | codegen_add_time_event(g, "LLVM Emit Object"); | |
| 4503 | codegen_add_time_event(g, "LLVM Emit Output"); | |
| 4497 | 4504 | |
| 4498 | 4505 | char *err_msg = nullptr; |
| 4499 | 4506 | Buf *o_basename = buf_create_from_buf(g->root_out_name); |
| 4500 | const char *o_ext = target_o_file_ext(&g->zig_target); | |
| 4501 | buf_append_str(o_basename, o_ext); | |
| 4507 | ||
| 4508 | switch (g->emit_file_type) { | |
| 4509 | case EmitFileTypeBinary: | |
| 4510 | { | |
| 4511 | const char *o_ext = target_o_file_ext(&g->zig_target); | |
| 4512 | buf_append_str(o_basename, o_ext); | |
| 4513 | break; | |
| 4514 | } | |
| 4515 | case EmitFileTypeAssembly: | |
| 4516 | { | |
| 4517 | const char *asm_ext = target_asm_file_ext(&g->zig_target); | |
| 4518 | buf_append_str(o_basename, asm_ext); | |
| 4519 | break; | |
| 4520 | } | |
| 4521 | case EmitFileTypeLLVMIr: | |
| 4522 | { | |
| 4523 | const char *llvm_ir_ext = target_llvm_ir_file_ext(&g->zig_target); | |
| 4524 | buf_append_str(o_basename, llvm_ir_ext); | |
| 4525 | break; | |
| 4526 | } | |
| 4527 | default: | |
| 4528 | zig_unreachable(); | |
| 4529 | } | |
| 4530 | ||
| 4502 | 4531 | Buf *output_path = buf_alloc(); |
| 4503 | 4532 | os_path_join(g->cache_dir, o_basename, output_path); |
| 4504 | 4533 | ensure_cache_dir(g); |
| 4505 | if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path), | |
| 4506 | LLVMObjectFile, &err_msg, g->build_mode == BuildModeDebug)) | |
| 4507 | { | |
| 4508 | zig_panic("unable to write object file %s: %s", buf_ptr(output_path), err_msg); | |
| 4509 | } | |
| 4510 | 4534 | |
| 4511 | validate_inline_fns(g); | |
| 4535 | switch (g->emit_file_type) { | |
| 4536 | case EmitFileTypeBinary: | |
| 4537 | if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path), | |
| 4538 | ZigLLVM_EmitBinary, &err_msg, g->build_mode == BuildModeDebug)) | |
| 4539 | { | |
| 4540 | zig_panic("unable to write object file %s: %s", buf_ptr(output_path), err_msg); | |
| 4541 | } | |
| 4542 | validate_inline_fns(g); | |
| 4543 | g->link_objects.append(output_path); | |
| 4544 | break; | |
| 4545 | ||
| 4546 | case EmitFileTypeAssembly: | |
| 4547 | if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path), | |
| 4548 | ZigLLVM_EmitAssembly, &err_msg, g->build_mode == BuildModeDebug)) | |
| 4549 | { | |
| 4550 | zig_panic("unable to write assembly file %s: %s", buf_ptr(output_path), err_msg); | |
| 4551 | } | |
| 4552 | validate_inline_fns(g); | |
| 4553 | break; | |
| 4554 | ||
| 4555 | case EmitFileTypeLLVMIr: | |
| 4556 | if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path), | |
| 4557 | ZigLLVM_EmitLLVMIr, &err_msg, g->build_mode == BuildModeDebug)) | |
| 4558 | { | |
| 4559 | zig_panic("unable to write llvm-ir file %s: %s", buf_ptr(output_path), err_msg); | |
| 4560 | } | |
| 4561 | validate_inline_fns(g); | |
| 4562 | break; | |
| 4512 | 4563 | |
| 4513 | g->link_objects.append(output_path); | |
| 4564 | default: | |
| 4565 | zig_unreachable(); | |
| 4566 | } | |
| 4514 | 4567 | } |
| 4515 | 4568 | |
| 4516 | 4569 | static const uint8_t int_sizes_in_bits[] = { |
| ... | ... | @@ -4816,7 +4869,9 @@ static void define_builtin_fns(CodeGen *g) { |
| 4816 | 4869 | create_builtin_fn(g, BuiltinFnIdMaxValue, "maxValue", 1); |
| 4817 | 4870 | create_builtin_fn(g, BuiltinFnIdMinValue, "minValue", 1); |
| 4818 | 4871 | create_builtin_fn(g, BuiltinFnIdMemberCount, "memberCount", 1); |
| 4819 | create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1); | |
| 4872 | create_builtin_fn(g, BuiltinFnIdMemberType, "memberType", 2); | |
| 4873 | create_builtin_fn(g, BuiltinFnIdMemberName, "memberName", 2); | |
| 4874 | create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1); // TODO rename to TypeOf | |
| 4820 | 4875 | create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4); |
| 4821 | 4876 | create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4); |
| 4822 | 4877 | create_builtin_fn(g, BuiltinFnIdMulWithOverflow, "mulWithOverflow", 4); |
| ... | ... | @@ -4863,6 +4918,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 4863 | 4918 | create_builtin_fn(g, BuiltinFnIdAlignCast, "alignCast", 2); |
| 4864 | 4919 | create_builtin_fn(g, BuiltinFnIdOpaqueType, "OpaqueType", 0); |
| 4865 | 4920 | create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1); |
| 4921 | create_builtin_fn(g, BuiltinFnIdArgType, "ArgType", 2); | |
| 4866 | 4922 | } |
| 4867 | 4923 | |
| 4868 | 4924 | static const char *bool_to_str(bool b) { |
src/codegen.hpp+1| ... | ... | @@ -23,6 +23,7 @@ void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len); |
| 23 | 23 | void codegen_set_is_test(CodeGen *codegen, bool is_test); |
| 24 | 24 | void codegen_set_each_lib_rpath(CodeGen *codegen, bool each_lib_rpath); |
| 25 | 25 | |
| 26 | void codegen_set_emit_file_type(CodeGen *g, EmitFileType emit_file_type); | |
| 26 | 27 | void codegen_set_is_static(CodeGen *codegen, bool is_static); |
| 27 | 28 | void codegen_set_strip(CodeGen *codegen, bool strip); |
| 28 | 29 | void codegen_set_errmsg_color(CodeGen *codegen, ErrColor err_color); |
src/ir.cpp+303| ... | ... | @@ -411,6 +411,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionMemberCount *) { |
| 411 | 411 | return IrInstructionIdMemberCount; |
| 412 | 412 | } |
| 413 | 413 | |
| 414 | static constexpr IrInstructionId ir_instruction_id(IrInstructionMemberType *) { | |
| 415 | return IrInstructionIdMemberType; | |
| 416 | } | |
| 417 | ||
| 418 | static constexpr IrInstructionId ir_instruction_id(IrInstructionMemberName *) { | |
| 419 | return IrInstructionIdMemberName; | |
| 420 | } | |
| 421 | ||
| 414 | 422 | static constexpr IrInstructionId ir_instruction_id(IrInstructionBreakpoint *) { |
| 415 | 423 | return IrInstructionIdBreakpoint; |
| 416 | 424 | } |
| ... | ... | @@ -567,6 +575,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSetAlignStack *) |
| 567 | 575 | return IrInstructionIdSetAlignStack; |
| 568 | 576 | } |
| 569 | 577 | |
| 578 | static constexpr IrInstructionId ir_instruction_id(IrInstructionArgType *) { | |
| 579 | return IrInstructionIdArgType; | |
| 580 | } | |
| 581 | ||
| 570 | 582 | template<typename T> |
| 571 | 583 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 572 | 584 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -1779,6 +1791,32 @@ static IrInstruction *ir_build_member_count(IrBuilder *irb, Scope *scope, AstNod |
| 1779 | 1791 | return &instruction->base; |
| 1780 | 1792 | } |
| 1781 | 1793 | |
| 1794 | static IrInstruction *ir_build_member_type(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 1795 | IrInstruction *container_type, IrInstruction *member_index) | |
| 1796 | { | |
| 1797 | IrInstructionMemberType *instruction = ir_build_instruction<IrInstructionMemberType>(irb, scope, source_node); | |
| 1798 | instruction->container_type = container_type; | |
| 1799 | instruction->member_index = member_index; | |
| 1800 | ||
| 1801 | ir_ref_instruction(container_type, irb->current_basic_block); | |
| 1802 | ir_ref_instruction(member_index, irb->current_basic_block); | |
| 1803 | ||
| 1804 | return &instruction->base; | |
| 1805 | } | |
| 1806 | ||
| 1807 | static IrInstruction *ir_build_member_name(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 1808 | IrInstruction *container_type, IrInstruction *member_index) | |
| 1809 | { | |
| 1810 | IrInstructionMemberName *instruction = ir_build_instruction<IrInstructionMemberName>(irb, scope, source_node); | |
| 1811 | instruction->container_type = container_type; | |
| 1812 | instruction->member_index = member_index; | |
| 1813 | ||
| 1814 | ir_ref_instruction(container_type, irb->current_basic_block); | |
| 1815 | ir_ref_instruction(member_index, irb->current_basic_block); | |
| 1816 | ||
| 1817 | return &instruction->base; | |
| 1818 | } | |
| 1819 | ||
| 1782 | 1820 | static IrInstruction *ir_build_breakpoint(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 1783 | 1821 | IrInstructionBreakpoint *instruction = ir_build_instruction<IrInstructionBreakpoint>(irb, scope, source_node); |
| 1784 | 1822 | return &instruction->base; |
| ... | ... | @@ -2263,6 +2301,19 @@ static IrInstruction *ir_build_set_align_stack(IrBuilder *irb, Scope *scope, Ast |
| 2263 | 2301 | return &instruction->base; |
| 2264 | 2302 | } |
| 2265 | 2303 | |
| 2304 | static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 2305 | IrInstruction *fn_type, IrInstruction *arg_index) | |
| 2306 | { | |
| 2307 | IrInstructionArgType *instruction = ir_build_instruction<IrInstructionArgType>(irb, scope, source_node); | |
| 2308 | instruction->fn_type = fn_type; | |
| 2309 | instruction->arg_index = arg_index; | |
| 2310 | ||
| 2311 | ir_ref_instruction(fn_type, irb->current_basic_block); | |
| 2312 | ir_ref_instruction(arg_index, irb->current_basic_block); | |
| 2313 | ||
| 2314 | return &instruction->base; | |
| 2315 | } | |
| 2316 | ||
| 2266 | 2317 | static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) { |
| 2267 | 2318 | return nullptr; |
| 2268 | 2319 | } |
| ... | ... | @@ -2710,6 +2761,22 @@ static IrInstruction *ir_instruction_membercount_get_dep(IrInstructionMemberCoun |
| 2710 | 2761 | } |
| 2711 | 2762 | } |
| 2712 | 2763 | |
| 2764 | static IrInstruction *ir_instruction_membertype_get_dep(IrInstructionMemberType *instruction, size_t index) { | |
| 2765 | switch (index) { | |
| 2766 | case 0: return instruction->container_type; | |
| 2767 | case 1: return instruction->member_index; | |
| 2768 | default: return nullptr; | |
| 2769 | } | |
| 2770 | } | |
| 2771 | ||
| 2772 | static IrInstruction *ir_instruction_membername_get_dep(IrInstructionMemberName *instruction, size_t index) { | |
| 2773 | switch (index) { | |
| 2774 | case 0: return instruction->container_type; | |
| 2775 | case 1: return instruction->member_index; | |
| 2776 | default: return nullptr; | |
| 2777 | } | |
| 2778 | } | |
| 2779 | ||
| 2713 | 2780 | static IrInstruction *ir_instruction_breakpoint_get_dep(IrInstructionBreakpoint *instruction, size_t index) { |
| 2714 | 2781 | return nullptr; |
| 2715 | 2782 | } |
| ... | ... | @@ -2992,6 +3059,14 @@ static IrInstruction *ir_instruction_setalignstack_get_dep(IrInstructionSetAlign |
| 2992 | 3059 | } |
| 2993 | 3060 | } |
| 2994 | 3061 | |
| 3062 | static IrInstruction *ir_instruction_argtype_get_dep(IrInstructionArgType *instruction, size_t index) { | |
| 3063 | switch (index) { | |
| 3064 | case 0: return instruction->fn_type; | |
| 3065 | case 1: return instruction->arg_index; | |
| 3066 | default: return nullptr; | |
| 3067 | } | |
| 3068 | } | |
| 3069 | ||
| 2995 | 3070 | static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) { |
| 2996 | 3071 | switch (instruction->id) { |
| 2997 | 3072 | case IrInstructionIdInvalid: |
| ... | ... | @@ -3118,6 +3193,10 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t |
| 3118 | 3193 | return ir_instruction_slice_get_dep((IrInstructionSlice *) instruction, index); |
| 3119 | 3194 | case IrInstructionIdMemberCount: |
| 3120 | 3195 | return ir_instruction_membercount_get_dep((IrInstructionMemberCount *) instruction, index); |
| 3196 | case IrInstructionIdMemberType: | |
| 3197 | return ir_instruction_membertype_get_dep((IrInstructionMemberType *) instruction, index); | |
| 3198 | case IrInstructionIdMemberName: | |
| 3199 | return ir_instruction_membername_get_dep((IrInstructionMemberName *) instruction, index); | |
| 3121 | 3200 | case IrInstructionIdBreakpoint: |
| 3122 | 3201 | return ir_instruction_breakpoint_get_dep((IrInstructionBreakpoint *) instruction, index); |
| 3123 | 3202 | case IrInstructionIdReturnAddress: |
| ... | ... | @@ -3194,6 +3273,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t |
| 3194 | 3273 | return ir_instruction_opaquetype_get_dep((IrInstructionOpaqueType *) instruction, index); |
| 3195 | 3274 | case IrInstructionIdSetAlignStack: |
| 3196 | 3275 | return ir_instruction_setalignstack_get_dep((IrInstructionSetAlignStack *) instruction, index); |
| 3276 | case IrInstructionIdArgType: | |
| 3277 | return ir_instruction_argtype_get_dep((IrInstructionArgType *) instruction, index); | |
| 3197 | 3278 | } |
| 3198 | 3279 | zig_unreachable(); |
| 3199 | 3280 | } |
| ... | ... | @@ -4352,6 +4433,36 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4352 | 4433 | |
| 4353 | 4434 | return ir_build_member_count(irb, scope, node, arg0_value); |
| 4354 | 4435 | } |
| 4436 | case BuiltinFnIdMemberType: | |
| 4437 | { | |
| 4438 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | |
| 4439 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); | |
| 4440 | if (arg0_value == irb->codegen->invalid_instruction) | |
| 4441 | return arg0_value; | |
| 4442 | ||
| 4443 | AstNode *arg1_node = node->data.fn_call_expr.params.at(1); | |
| 4444 | IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); | |
| 4445 | if (arg1_value == irb->codegen->invalid_instruction) | |
| 4446 | return arg1_value; | |
| 4447 | ||
| 4448 | ||
| 4449 | return ir_build_member_type(irb, scope, node, arg0_value, arg1_value); | |
| 4450 | } | |
| 4451 | case BuiltinFnIdMemberName: | |
| 4452 | { | |
| 4453 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | |
| 4454 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); | |
| 4455 | if (arg0_value == irb->codegen->invalid_instruction) | |
| 4456 | return arg0_value; | |
| 4457 | ||
| 4458 | AstNode *arg1_node = node->data.fn_call_expr.params.at(1); | |
| 4459 | IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); | |
| 4460 | if (arg1_value == irb->codegen->invalid_instruction) | |
| 4461 | return arg1_value; | |
| 4462 | ||
| 4463 | ||
| 4464 | return ir_build_member_name(irb, scope, node, arg0_value, arg1_value); | |
| 4465 | } | |
| 4355 | 4466 | case BuiltinFnIdBreakpoint: |
| 4356 | 4467 | return ir_build_breakpoint(irb, scope, node); |
| 4357 | 4468 | case BuiltinFnIdReturnAddress: |
| ... | ... | @@ -4629,6 +4740,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4629 | 4740 | |
| 4630 | 4741 | return ir_build_set_align_stack(irb, scope, node, arg0_value); |
| 4631 | 4742 | } |
| 4743 | case BuiltinFnIdArgType: | |
| 4744 | { | |
| 4745 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | |
| 4746 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); | |
| 4747 | if (arg0_value == irb->codegen->invalid_instruction) | |
| 4748 | return arg0_value; | |
| 4749 | ||
| 4750 | AstNode *arg1_node = node->data.fn_call_expr.params.at(1); | |
| 4751 | IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); | |
| 4752 | if (arg1_value == irb->codegen->invalid_instruction) | |
| 4753 | return arg1_value; | |
| 4754 | ||
| 4755 | return ir_build_arg_type(irb, scope, node, arg0_value, arg1_value); | |
| 4756 | } | |
| 4632 | 4757 | } |
| 4633 | 4758 | zig_unreachable(); |
| 4634 | 4759 | } |
| ... | ... | @@ -11643,6 +11768,62 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru |
| 11643 | 11768 | buf_ptr(&child_type->name), buf_ptr(field_name))); |
| 11644 | 11769 | return ira->codegen->builtin_types.entry_invalid; |
| 11645 | 11770 | } |
| 11771 | } else if (child_type->id == TypeTableEntryIdErrorUnion) { | |
| 11772 | if (buf_eql_str(field_name, "Child")) { | |
| 11773 | bool ptr_is_const = true; | |
| 11774 | bool ptr_is_volatile = false; | |
| 11775 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, | |
| 11776 | create_const_type(ira->codegen, child_type->data.error.child_type), | |
| 11777 | ira->codegen->builtin_types.entry_type, | |
| 11778 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile); | |
| 11779 | } else { | |
| 11780 | ir_add_error(ira, &field_ptr_instruction->base, | |
| 11781 | buf_sprintf("type '%s' has no member called '%s'", | |
| 11782 | buf_ptr(&child_type->name), buf_ptr(field_name))); | |
| 11783 | return ira->codegen->builtin_types.entry_invalid; | |
| 11784 | } | |
| 11785 | } else if (child_type->id == TypeTableEntryIdMaybe) { | |
| 11786 | if (buf_eql_str(field_name, "Child")) { | |
| 11787 | bool ptr_is_const = true; | |
| 11788 | bool ptr_is_volatile = false; | |
| 11789 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, | |
| 11790 | create_const_type(ira->codegen, child_type->data.maybe.child_type), | |
| 11791 | ira->codegen->builtin_types.entry_type, | |
| 11792 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile); | |
| 11793 | } else { | |
| 11794 | ir_add_error(ira, &field_ptr_instruction->base, | |
| 11795 | buf_sprintf("type '%s' has no member called '%s'", | |
| 11796 | buf_ptr(&child_type->name), buf_ptr(field_name))); | |
| 11797 | return ira->codegen->builtin_types.entry_invalid; | |
| 11798 | } | |
| 11799 | } else if (child_type->id == TypeTableEntryIdFn) { | |
| 11800 | if (buf_eql_str(field_name, "ReturnType")) { | |
| 11801 | bool ptr_is_const = true; | |
| 11802 | bool ptr_is_volatile = false; | |
| 11803 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, | |
| 11804 | create_const_type(ira->codegen, child_type->data.fn.fn_type_id.return_type), | |
| 11805 | ira->codegen->builtin_types.entry_type, | |
| 11806 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile); | |
| 11807 | } else if (buf_eql_str(field_name, "is_var_args")) { | |
| 11808 | bool ptr_is_const = true; | |
| 11809 | bool ptr_is_volatile = false; | |
| 11810 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, | |
| 11811 | create_const_bool(ira->codegen, child_type->data.fn.fn_type_id.is_var_args), | |
| 11812 | ira->codegen->builtin_types.entry_bool, | |
| 11813 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile); | |
| 11814 | } else if (buf_eql_str(field_name, "arg_count")) { | |
| 11815 | bool ptr_is_const = true; | |
| 11816 | bool ptr_is_volatile = false; | |
| 11817 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, | |
| 11818 | create_const_usize(ira->codegen, child_type->data.fn.fn_type_id.param_count), | |
| 11819 | ira->codegen->builtin_types.entry_usize, | |
| 11820 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile); | |
| 11821 | } else { | |
| 11822 | ir_add_error(ira, &field_ptr_instruction->base, | |
| 11823 | buf_sprintf("type '%s' has no member called '%s'", | |
| 11824 | buf_ptr(&child_type->name), buf_ptr(field_name))); | |
| 11825 | return ira->codegen->builtin_types.entry_invalid; | |
| 11826 | } | |
| 11646 | 11827 | } else { |
| 11647 | 11828 | ir_add_error(ira, &field_ptr_instruction->base, |
| 11648 | 11829 | buf_sprintf("type '%s' does not support field access", buf_ptr(&child_type->name))); |
| ... | ... | @@ -14240,6 +14421,90 @@ static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrIns |
| 14240 | 14421 | return ira->codegen->builtin_types.entry_num_lit_int; |
| 14241 | 14422 | } |
| 14242 | 14423 | |
| 14424 | static TypeTableEntry *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInstructionMemberType *instruction) { | |
| 14425 | IrInstruction *container_type_value = instruction->container_type->other; | |
| 14426 | TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value); | |
| 14427 | if (type_is_invalid(container_type)) | |
| 14428 | return ira->codegen->builtin_types.entry_invalid; | |
| 14429 | ||
| 14430 | uint64_t member_index; | |
| 14431 | IrInstruction *index_value = instruction->member_index->other; | |
| 14432 | if (!ir_resolve_usize(ira, index_value, &member_index)) | |
| 14433 | return ira->codegen->builtin_types.entry_invalid; | |
| 14434 | ||
| 14435 | if (container_type->id == TypeTableEntryIdStruct) { | |
| 14436 | if (member_index >= container_type->data.structure.src_field_count) { | |
| 14437 | ir_add_error(ira, index_value, | |
| 14438 | buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members", | |
| 14439 | member_index, buf_ptr(&container_type->name), container_type->data.structure.src_field_count)); | |
| 14440 | return ira->codegen->builtin_types.entry_invalid; | |
| 14441 | } | |
| 14442 | TypeStructField *field = &container_type->data.structure.fields[member_index]; | |
| 14443 | ||
| 14444 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | |
| 14445 | out_val->data.x_type = field->type_entry; | |
| 14446 | return ira->codegen->builtin_types.entry_type; | |
| 14447 | } else if (container_type->id == TypeTableEntryIdEnum) { | |
| 14448 | if (member_index >= container_type->data.enumeration.src_field_count) { | |
| 14449 | ir_add_error(ira, index_value, | |
| 14450 | buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members", | |
| 14451 | member_index, buf_ptr(&container_type->name), container_type->data.enumeration.src_field_count)); | |
| 14452 | return ira->codegen->builtin_types.entry_invalid; | |
| 14453 | } | |
| 14454 | TypeEnumField *field = &container_type->data.enumeration.fields[member_index]; | |
| 14455 | ||
| 14456 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | |
| 14457 | out_val->data.x_type = field->type_entry; | |
| 14458 | return ira->codegen->builtin_types.entry_type; | |
| 14459 | } else { | |
| 14460 | ir_add_error(ira, container_type_value, | |
| 14461 | buf_sprintf("type '%s' does not support @memberType", buf_ptr(&container_type->name))); | |
| 14462 | return ira->codegen->builtin_types.entry_invalid; | |
| 14463 | } | |
| 14464 | } | |
| 14465 | ||
| 14466 | static TypeTableEntry *ir_analyze_instruction_member_name(IrAnalyze *ira, IrInstructionMemberName *instruction) { | |
| 14467 | IrInstruction *container_type_value = instruction->container_type->other; | |
| 14468 | TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value); | |
| 14469 | if (type_is_invalid(container_type)) | |
| 14470 | return ira->codegen->builtin_types.entry_invalid; | |
| 14471 | ||
| 14472 | uint64_t member_index; | |
| 14473 | IrInstruction *index_value = instruction->member_index->other; | |
| 14474 | if (!ir_resolve_usize(ira, index_value, &member_index)) | |
| 14475 | return ira->codegen->builtin_types.entry_invalid; | |
| 14476 | ||
| 14477 | if (container_type->id == TypeTableEntryIdStruct) { | |
| 14478 | if (member_index >= container_type->data.structure.src_field_count) { | |
| 14479 | ir_add_error(ira, index_value, | |
| 14480 | buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members", | |
| 14481 | member_index, buf_ptr(&container_type->name), container_type->data.structure.src_field_count)); | |
| 14482 | return ira->codegen->builtin_types.entry_invalid; | |
| 14483 | } | |
| 14484 | TypeStructField *field = &container_type->data.structure.fields[member_index]; | |
| 14485 | ||
| 14486 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | |
| 14487 | init_const_str_lit(ira->codegen, out_val, field->name); | |
| 14488 | return out_val->type; | |
| 14489 | } else if (container_type->id == TypeTableEntryIdEnum) { | |
| 14490 | if (member_index >= container_type->data.enumeration.src_field_count) { | |
| 14491 | ir_add_error(ira, index_value, | |
| 14492 | buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members", | |
| 14493 | member_index, buf_ptr(&container_type->name), container_type->data.enumeration.src_field_count)); | |
| 14494 | return ira->codegen->builtin_types.entry_invalid; | |
| 14495 | } | |
| 14496 | TypeEnumField *field = &container_type->data.enumeration.fields[member_index]; | |
| 14497 | ||
| 14498 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | |
| 14499 | init_const_str_lit(ira->codegen, out_val, field->name); | |
| 14500 | return out_val->type; | |
| 14501 | } else { | |
| 14502 | ir_add_error(ira, container_type_value, | |
| 14503 | buf_sprintf("type '%s' does not support @memberName", buf_ptr(&container_type->name))); | |
| 14504 | return ira->codegen->builtin_types.entry_invalid; | |
| 14505 | } | |
| 14506 | } | |
| 14507 | ||
| 14243 | 14508 | static TypeTableEntry *ir_analyze_instruction_breakpoint(IrAnalyze *ira, IrInstructionBreakpoint *instruction) { |
| 14244 | 14509 | ir_build_breakpoint_from(&ira->new_irb, &instruction->base); |
| 14245 | 14510 | return ira->codegen->builtin_types.entry_void; |
| ... | ... | @@ -15346,6 +15611,35 @@ static TypeTableEntry *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, Ir |
| 15346 | 15611 | return ira->codegen->builtin_types.entry_void; |
| 15347 | 15612 | } |
| 15348 | 15613 | |
| 15614 | static TypeTableEntry *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstructionArgType *instruction) { | |
| 15615 | IrInstruction *fn_type_inst = instruction->fn_type->other; | |
| 15616 | TypeTableEntry *fn_type = ir_resolve_type(ira, fn_type_inst); | |
| 15617 | if (type_is_invalid(fn_type)) | |
| 15618 | return ira->codegen->builtin_types.entry_invalid; | |
| 15619 | ||
| 15620 | IrInstruction *arg_index_inst = instruction->arg_index->other; | |
| 15621 | uint64_t arg_index; | |
| 15622 | if (!ir_resolve_usize(ira, arg_index_inst, &arg_index)) | |
| 15623 | return ira->codegen->builtin_types.entry_invalid; | |
| 15624 | ||
| 15625 | if (fn_type->id != TypeTableEntryIdFn) { | |
| 15626 | ir_add_error(ira, fn_type_inst, buf_sprintf("expected function, found '%s'", buf_ptr(&fn_type->name))); | |
| 15627 | return ira->codegen->builtin_types.entry_invalid; | |
| 15628 | } | |
| 15629 | ||
| 15630 | FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; | |
| 15631 | if (arg_index >= fn_type_id->param_count) { | |
| 15632 | ir_add_error(ira, arg_index_inst, | |
| 15633 | buf_sprintf("arg index %" ZIG_PRI_u64 " out of bounds; '%s' has %" ZIG_PRI_usize " arguments", | |
| 15634 | arg_index, buf_ptr(&fn_type->name), fn_type_id->param_count)); | |
| 15635 | return ira->codegen->builtin_types.entry_invalid; | |
| 15636 | } | |
| 15637 | ||
| 15638 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | |
| 15639 | out_val->data.x_type = fn_type_id->param_info[arg_index].type; | |
| 15640 | return ira->codegen->builtin_types.entry_type; | |
| 15641 | } | |
| 15642 | ||
| 15349 | 15643 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { |
| 15350 | 15644 | switch (instruction->id) { |
| 15351 | 15645 | case IrInstructionIdInvalid: |
| ... | ... | @@ -15480,6 +15774,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 15480 | 15774 | return ir_analyze_instruction_slice(ira, (IrInstructionSlice *)instruction); |
| 15481 | 15775 | case IrInstructionIdMemberCount: |
| 15482 | 15776 | return ir_analyze_instruction_member_count(ira, (IrInstructionMemberCount *)instruction); |
| 15777 | case IrInstructionIdMemberType: | |
| 15778 | return ir_analyze_instruction_member_type(ira, (IrInstructionMemberType *)instruction); | |
| 15779 | case IrInstructionIdMemberName: | |
| 15780 | return ir_analyze_instruction_member_name(ira, (IrInstructionMemberName *)instruction); | |
| 15483 | 15781 | case IrInstructionIdBreakpoint: |
| 15484 | 15782 | return ir_analyze_instruction_breakpoint(ira, (IrInstructionBreakpoint *)instruction); |
| 15485 | 15783 | case IrInstructionIdReturnAddress: |
| ... | ... | @@ -15536,6 +15834,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 15536 | 15834 | return ir_analyze_instruction_opaque_type(ira, (IrInstructionOpaqueType *)instruction); |
| 15537 | 15835 | case IrInstructionIdSetAlignStack: |
| 15538 | 15836 | return ir_analyze_instruction_set_align_stack(ira, (IrInstructionSetAlignStack *)instruction); |
| 15837 | case IrInstructionIdArgType: | |
| 15838 | return ir_analyze_instruction_arg_type(ira, (IrInstructionArgType *)instruction); | |
| 15539 | 15839 | } |
| 15540 | 15840 | zig_unreachable(); |
| 15541 | 15841 | } |
| ... | ... | @@ -15687,6 +15987,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 15687 | 15987 | case IrInstructionIdBoolNot: |
| 15688 | 15988 | case IrInstructionIdSlice: |
| 15689 | 15989 | case IrInstructionIdMemberCount: |
| 15990 | case IrInstructionIdMemberType: | |
| 15991 | case IrInstructionIdMemberName: | |
| 15690 | 15992 | case IrInstructionIdAlignOf: |
| 15691 | 15993 | case IrInstructionIdReturnAddress: |
| 15692 | 15994 | case IrInstructionIdFrameAddress: |
| ... | ... | @@ -15716,6 +16018,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 15716 | 16018 | case IrInstructionIdTypeId: |
| 15717 | 16019 | case IrInstructionIdAlignCast: |
| 15718 | 16020 | case IrInstructionIdOpaqueType: |
| 16021 | case IrInstructionIdArgType: | |
| 15719 | 16022 | return false; |
| 15720 | 16023 | case IrInstructionIdAsm: |
| 15721 | 16024 | { |
src/ir_print.cpp+34| ... | ... | @@ -658,6 +658,22 @@ static void ir_print_member_count(IrPrint *irp, IrInstructionMemberCount *instru |
| 658 | 658 | fprintf(irp->f, ")"); |
| 659 | 659 | } |
| 660 | 660 | |
| 661 | static void ir_print_member_type(IrPrint *irp, IrInstructionMemberType *instruction) { | |
| 662 | fprintf(irp->f, "@memberType("); | |
| 663 | ir_print_other_instruction(irp, instruction->container_type); | |
| 664 | fprintf(irp->f, ", "); | |
| 665 | ir_print_other_instruction(irp, instruction->member_index); | |
| 666 | fprintf(irp->f, ")"); | |
| 667 | } | |
| 668 | ||
| 669 | static void ir_print_member_name(IrPrint *irp, IrInstructionMemberName *instruction) { | |
| 670 | fprintf(irp->f, "@memberName("); | |
| 671 | ir_print_other_instruction(irp, instruction->container_type); | |
| 672 | fprintf(irp->f, ", "); | |
| 673 | ir_print_other_instruction(irp, instruction->member_index); | |
| 674 | fprintf(irp->f, ")"); | |
| 675 | } | |
| 676 | ||
| 661 | 677 | static void ir_print_breakpoint(IrPrint *irp, IrInstructionBreakpoint *instruction) { |
| 662 | 678 | fprintf(irp->f, "@breakpoint()"); |
| 663 | 679 | } |
| ... | ... | @@ -954,6 +970,15 @@ static void ir_print_set_align_stack(IrPrint *irp, IrInstructionSetAlignStack *i |
| 954 | 970 | fprintf(irp->f, ")"); |
| 955 | 971 | } |
| 956 | 972 | |
| 973 | static void ir_print_arg_type(IrPrint *irp, IrInstructionArgType *instruction) { | |
| 974 | fprintf(irp->f, "@ArgType("); | |
| 975 | ir_print_other_instruction(irp, instruction->fn_type); | |
| 976 | fprintf(irp->f, ","); | |
| 977 | ir_print_other_instruction(irp, instruction->arg_index); | |
| 978 | fprintf(irp->f, ")"); | |
| 979 | } | |
| 980 | ||
| 981 | ||
| 957 | 982 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 958 | 983 | ir_print_prefix(irp, instruction); |
| 959 | 984 | switch (instruction->id) { |
| ... | ... | @@ -1139,6 +1164,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1139 | 1164 | case IrInstructionIdMemberCount: |
| 1140 | 1165 | ir_print_member_count(irp, (IrInstructionMemberCount *)instruction); |
| 1141 | 1166 | break; |
| 1167 | case IrInstructionIdMemberType: | |
| 1168 | ir_print_member_type(irp, (IrInstructionMemberType *)instruction); | |
| 1169 | break; | |
| 1170 | case IrInstructionIdMemberName: | |
| 1171 | ir_print_member_name(irp, (IrInstructionMemberName *)instruction); | |
| 1172 | break; | |
| 1142 | 1173 | case IrInstructionIdBreakpoint: |
| 1143 | 1174 | ir_print_breakpoint(irp, (IrInstructionBreakpoint *)instruction); |
| 1144 | 1175 | break; |
| ... | ... | @@ -1256,6 +1287,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1256 | 1287 | case IrInstructionIdSetAlignStack: |
| 1257 | 1288 | ir_print_set_align_stack(irp, (IrInstructionSetAlignStack *)instruction); |
| 1258 | 1289 | break; |
| 1290 | case IrInstructionIdArgType: | |
| 1291 | ir_print_arg_type(irp, (IrInstructionArgType *)instruction); | |
| 1292 | break; | |
| 1259 | 1293 | } |
| 1260 | 1294 | fprintf(irp->f, "\n"); |
| 1261 | 1295 | } |
src/link.cpp+1-1| ... | ... | @@ -894,7 +894,7 @@ void codegen_link(CodeGen *g, const char *out_file) { |
| 894 | 894 | Buf *o_file_path = g->link_objects.at(0); |
| 895 | 895 | int err; |
| 896 | 896 | if ((err = os_rename(o_file_path, &lj.out_file))) { |
| 897 | zig_panic("unable to rename object file into final output: %s", err_str(err)); | |
| 897 | zig_panic("unable to rename object file %s into final output %s: %s", buf_ptr(o_file_path), buf_ptr(&lj.out_file), err_str(err)); | |
| 898 | 898 | } |
| 899 | 899 | } |
| 900 | 900 | return; |
src/main.cpp+15| ... | ... | @@ -32,6 +32,7 @@ static int usage(const char *arg0) { |
| 32 | 32 | " --assembly $source add assembly file to build\n" |
| 33 | 33 | " --cache-dir $path override the cache directory\n" |
| 34 | 34 | " --color $auto|off|on enable or disable colored error messages\n" |
| 35 | " --emit $filetype emit a specific file format as compilation output\n" | |
| 35 | 36 | " --enable-timing-info print timing diagnostics\n" |
| 36 | 37 | " --libc-include-dir $path directory where libc stdlib.h resides\n" |
| 37 | 38 | " --name $name override output name\n" |
| ... | ... | @@ -269,6 +270,7 @@ int main(int argc, char **argv) { |
| 269 | 270 | |
| 270 | 271 | char *arg0 = argv[0]; |
| 271 | 272 | Cmd cmd = CmdInvalid; |
| 273 | EmitFileType emit_file_type = EmitFileTypeBinary; | |
| 272 | 274 | const char *in_file = nullptr; |
| 273 | 275 | const char *out_file = nullptr; |
| 274 | 276 | const char *out_file_h = nullptr; |
| ... | ... | @@ -535,6 +537,17 @@ int main(int argc, char **argv) { |
| 535 | 537 | fprintf(stderr, "--color options are 'auto', 'on', or 'off'\n"); |
| 536 | 538 | return usage(arg0); |
| 537 | 539 | } |
| 540 | } else if (strcmp(arg, "--emit") == 0) { | |
| 541 | if (strcmp(argv[i], "asm") == 0) { | |
| 542 | emit_file_type = EmitFileTypeAssembly; | |
| 543 | } else if (strcmp(argv[i], "bin") == 0) { | |
| 544 | emit_file_type = EmitFileTypeBinary; | |
| 545 | } else if (strcmp(argv[i], "llvm-ir") == 0) { | |
| 546 | emit_file_type = EmitFileTypeLLVMIr; | |
| 547 | } else { | |
| 548 | fprintf(stderr, "--emit options are 'asm', 'bin', or 'llvm-ir'\n"); | |
| 549 | return usage(arg0); | |
| 550 | } | |
| 538 | 551 | } else if (strcmp(arg, "--name") == 0) { |
| 539 | 552 | out_name = argv[i]; |
| 540 | 553 | } else if (strcmp(arg, "--libc-lib-dir") == 0) { |
| ... | ... | @@ -815,6 +828,8 @@ int main(int argc, char **argv) { |
| 815 | 828 | add_package(g, cur_pkg, g->root_package); |
| 816 | 829 | |
| 817 | 830 | if (cmd == CmdBuild) { |
| 831 | codegen_set_emit_file_type(g, emit_file_type); | |
| 832 | ||
| 818 | 833 | for (size_t i = 0; i < objects.length; i += 1) { |
| 819 | 834 | codegen_add_object(g, buf_create_from_str(objects.at(i))); |
| 820 | 835 | } |
src/target.cpp+8| ... | ... | @@ -581,6 +581,14 @@ const char *target_o_file_ext(ZigTarget *target) { |
| 581 | 581 | } |
| 582 | 582 | } |
| 583 | 583 | |
| 584 | const char *target_asm_file_ext(ZigTarget *target) { | |
| 585 | return ".s"; | |
| 586 | } | |
| 587 | ||
| 588 | const char *target_llvm_ir_file_ext(ZigTarget *target) { | |
| 589 | return ".ll"; | |
| 590 | } | |
| 591 | ||
| 584 | 592 | const char *target_exe_file_ext(ZigTarget *target) { |
| 585 | 593 | if (target->os == ZigLLVM_Win32) { |
| 586 | 594 | return ".exe"; |
src/target.hpp+2| ... | ... | @@ -73,6 +73,8 @@ void resolve_target_object_format(ZigTarget *target); |
| 73 | 73 | uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id); |
| 74 | 74 | |
| 75 | 75 | const char *target_o_file_ext(ZigTarget *target); |
| 76 | const char *target_asm_file_ext(ZigTarget *target); | |
| 77 | const char *target_llvm_ir_file_ext(ZigTarget *target); | |
| 76 | 78 | const char *target_exe_file_ext(ZigTarget *target); |
| 77 | 79 | |
| 78 | 80 | Buf *target_dynamic_linker(ZigTarget *target); |
src/zig_llvm.cpp+23-13| ... | ... | @@ -77,7 +77,7 @@ static const bool assertions_on = false; |
| 77 | 77 | #endif |
| 78 | 78 | |
| 79 | 79 | bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, |
| 80 | const char *filename, LLVMCodeGenFileType file_type, char **error_message, bool is_debug) | |
| 80 | const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug) | |
| 81 | 81 | { |
| 82 | 82 | std::error_code EC; |
| 83 | 83 | raw_fd_ostream dest(filename, EC, sys::fs::F_None); |
| ... | ... | @@ -135,18 +135,24 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM |
| 135 | 135 | MPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis())); |
| 136 | 136 | PMBuilder->populateModulePassManager(MPM); |
| 137 | 137 | |
| 138 | // Set output pass. | |
| 138 | 139 | TargetMachine::CodeGenFileType ft; |
| 139 | switch (file_type) { | |
| 140 | case LLVMAssemblyFile: | |
| 141 | ft = TargetMachine::CGFT_AssemblyFile; | |
| 142 | break; | |
| 143 | default: | |
| 144 | ft = TargetMachine::CGFT_ObjectFile; | |
| 145 | break; | |
| 146 | } | |
| 147 | if (target_machine->addPassesToEmitFile(MPM, dest, ft)) { | |
| 148 | *error_message = strdup("TargetMachine can't emit a file of this type"); | |
| 149 | return true; | |
| 140 | if (output_type != ZigLLVM_EmitLLVMIr) { | |
| 141 | switch (output_type) { | |
| 142 | case ZigLLVM_EmitAssembly: | |
| 143 | ft = TargetMachine::CGFT_AssemblyFile; | |
| 144 | break; | |
| 145 | case ZigLLVM_EmitBinary: | |
| 146 | ft = TargetMachine::CGFT_ObjectFile; | |
| 147 | break; | |
| 148 | default: | |
| 149 | abort(); | |
| 150 | } | |
| 151 | ||
| 152 | if (target_machine->addPassesToEmitFile(MPM, dest, ft)) { | |
| 153 | *error_message = strdup("TargetMachine can't emit a file of this type"); | |
| 154 | return true; | |
| 155 | } | |
| 150 | 156 | } |
| 151 | 157 | |
| 152 | 158 | // run per function optimization passes |
| ... | ... | @@ -158,7 +164,11 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM |
| 158 | 164 | |
| 159 | 165 | MPM.run(*module); |
| 160 | 166 | |
| 161 | dest.close(); | |
| 167 | if (output_type == ZigLLVM_EmitLLVMIr) { | |
| 168 | if (LLVMPrintModuleToFile(module_ref, filename, error_message)) { | |
| 169 | return true; | |
| 170 | } | |
| 171 | } | |
| 162 | 172 | |
| 163 | 173 | return false; |
| 164 | 174 | } |
src/zig_llvm.hpp+9-1| ... | ... | @@ -34,8 +34,16 @@ void ZigLLVMInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R); |
| 34 | 34 | char *ZigLLVMGetHostCPUName(void); |
| 35 | 35 | char *ZigLLVMGetNativeFeatures(void); |
| 36 | 36 | |
| 37 | // We use a custom enum here since LLVM does not expose LLVMIr as an emit | |
| 38 | // output through the same mechanism as assembly/binary. | |
| 39 | enum ZigLLVM_EmitOutputType { | |
| 40 | ZigLLVM_EmitAssembly, | |
| 41 | ZigLLVM_EmitBinary, | |
| 42 | ZigLLVM_EmitLLVMIr, | |
| 43 | }; | |
| 44 | ||
| 37 | 45 | bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, |
| 38 | const char *filename, LLVMCodeGenFileType file_type, char **error_message, bool is_debug); | |
| 46 | const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug); | |
| 39 | 47 | |
| 40 | 48 | LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, |
| 41 | 49 | unsigned NumArgs, unsigned CC, bool always_inline, const char *Name); |
std/heap.zig+12-4| ... | ... | @@ -17,8 +17,8 @@ pub var c_allocator = Allocator { |
| 17 | 17 | }; |
| 18 | 18 | |
| 19 | 19 | fn cAlloc(self: &Allocator, n: usize, alignment: usize) -> %[]u8 { |
| 20 | if (c.malloc(usize(n))) |mem| { | |
| 21 | @ptrCast(&u8, mem)[0..n] | |
| 20 | if (c.malloc(usize(n))) |buf| { | |
| 21 | @ptrCast(&u8, buf)[0..n] | |
| 22 | 22 | } else { |
| 23 | 23 | error.OutOfMemory |
| 24 | 24 | } |
| ... | ... | @@ -29,8 +29,8 @@ fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: usize) |
| 29 | 29 | old_mem[0..new_size] |
| 30 | 30 | } else { |
| 31 | 31 | const old_ptr = @ptrCast(&c_void, old_mem.ptr); |
| 32 | if (c.realloc(old_ptr, usize(new_size))) |mem| { | |
| 33 | @ptrCast(&u8, mem)[0..new_size] | |
| 32 | if (c.realloc(old_ptr, usize(new_size))) |buf| { | |
| 33 | @ptrCast(&u8, buf)[0..new_size] | |
| 34 | 34 | } else { |
| 35 | 35 | error.OutOfMemory |
| 36 | 36 | } |
| ... | ... | @@ -136,6 +136,14 @@ pub const IncrementingAllocator = struct { |
| 136 | 136 | } |
| 137 | 137 | }; |
| 138 | 138 | |
| 139 | test "c_allocator" { | |
| 140 | if (builtin.link_libc) { | |
| 141 | var slice = c_allocator.alloc(u8, 50) %% return; | |
| 142 | defer c_allocator.free(slice); | |
| 143 | slice = c_allocator.realloc(u8, slice, 100) %% return; | |
| 144 | } | |
| 145 | } | |
| 146 | ||
| 139 | 147 | test "IncrementingAllocator" { |
| 140 | 148 | const total_bytes = 100 * 1024 * 1024; |
| 141 | 149 | var inc_allocator = %%IncrementingAllocator.init(total_bytes); |
std/io.zig+2-2| ... | ... | @@ -308,7 +308,7 @@ pub const InStream = struct { |
| 308 | 308 | readFn: fn(self: &InStream, buffer: []u8) -> %usize, |
| 309 | 309 | |
| 310 | 310 | /// Replaces `buffer` contents by reading from the stream until it is finished. |
| 311 | /// If `buffer.len()` woould exceed `max_size`, `error.StreamTooLong` is returned and | |
| 311 | /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and | |
| 312 | 312 | /// the contents read from the stream are lost. |
| 313 | 313 | pub fn readAllBuffer(self: &InStream, buffer: &Buffer, max_size: usize) -> %void { |
| 314 | 314 | %return buffer.resize(0); |
| ... | ... | @@ -339,7 +339,7 @@ pub const InStream = struct { |
| 339 | 339 | var buf = Buffer.initNull(allocator); |
| 340 | 340 | defer buf.deinit(); |
| 341 | 341 | |
| 342 | %return self.readAllBuffer(self, &buf, max_size); | |
| 342 | %return self.readAllBuffer(&buf, max_size); | |
| 343 | 343 | return buf.toOwnedSlice(); |
| 344 | 344 | } |
| 345 | 345 |
test/behavior.zig+1| ... | ... | @@ -29,6 +29,7 @@ comptime { |
| 29 | 29 | _ = @import("cases/null.zig"); |
| 30 | 30 | _ = @import("cases/pub_enum/index.zig"); |
| 31 | 31 | _ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig"); |
| 32 | _ = @import("cases/reflection.zig"); | |
| 32 | 33 | _ = @import("cases/sizeof_and_typeof.zig"); |
| 33 | 34 | _ = @import("cases/slice.zig"); |
| 34 | 35 | _ = @import("cases/struct.zig"); |
test/cases/reflection.zig created+70| ... | ... | @@ -0,0 +1,70 @@ |
| 1 | const assert = @import("std").debug.assert; | |
| 2 | const mem = @import("std").mem; | |
| 3 | ||
| 4 | test "reflection: array, pointer, nullable, error union type child" { | |
| 5 | comptime { | |
| 6 | assert(([10]u8).Child == u8); | |
| 7 | assert((&u8).Child == u8); | |
| 8 | assert((%u8).Child == u8); | |
| 9 | assert((?u8).Child == u8); | |
| 10 | } | |
| 11 | } | |
| 12 | ||
| 13 | test "reflection: function return type, var args, and param types" { | |
| 14 | comptime { | |
| 15 | assert(@typeOf(dummy).ReturnType == i32); | |
| 16 | assert(!@typeOf(dummy).is_var_args); | |
| 17 | assert(@typeOf(dummy_varargs).is_var_args); | |
| 18 | assert(@typeOf(dummy).arg_count == 3); | |
| 19 | assert(@ArgType(@typeOf(dummy), 0) == bool); | |
| 20 | assert(@ArgType(@typeOf(dummy), 1) == i32); | |
| 21 | assert(@ArgType(@typeOf(dummy), 2) == f32); | |
| 22 | } | |
| 23 | } | |
| 24 | ||
| 25 | fn dummy(a: bool, b: i32, c: f32) -> i32 { 1234 } | |
| 26 | fn dummy_varargs(args: ...) {} | |
| 27 | ||
| 28 | test "reflection: struct member types and names" { | |
| 29 | comptime { | |
| 30 | assert(@memberCount(Foo) == 3); | |
| 31 | ||
| 32 | assert(@memberType(Foo, 0) == i32); | |
| 33 | assert(@memberType(Foo, 1) == bool); | |
| 34 | assert(@memberType(Foo, 2) == void); | |
| 35 | ||
| 36 | assert(mem.eql(u8, @memberName(Foo, 0), "one")); | |
| 37 | assert(mem.eql(u8, @memberName(Foo, 1), "two")); | |
| 38 | assert(mem.eql(u8, @memberName(Foo, 2), "three")); | |
| 39 | } | |
| 40 | } | |
| 41 | ||
| 42 | test "reflection: enum member types and names" { | |
| 43 | comptime { | |
| 44 | assert(@memberCount(Bar) == 4); | |
| 45 | ||
| 46 | assert(@memberType(Bar, 0) == void); | |
| 47 | assert(@memberType(Bar, 1) == i32); | |
| 48 | assert(@memberType(Bar, 2) == bool); | |
| 49 | assert(@memberType(Bar, 3) == f64); | |
| 50 | ||
| 51 | assert(mem.eql(u8, @memberName(Bar, 0), "One")); | |
| 52 | assert(mem.eql(u8, @memberName(Bar, 1), "Two")); | |
| 53 | assert(mem.eql(u8, @memberName(Bar, 2), "Three")); | |
| 54 | assert(mem.eql(u8, @memberName(Bar, 3), "Four")); | |
| 55 | } | |
| 56 | ||
| 57 | } | |
| 58 | ||
| 59 | const Foo = struct { | |
| 60 | one: i32, | |
| 61 | two: bool, | |
| 62 | three: void, | |
| 63 | }; | |
| 64 | ||
| 65 | const Bar = enum { | |
| 66 | One, | |
| 67 | Two: i32, | |
| 68 | Three: bool, | |
| 69 | Four: f64, | |
| 70 | }; |
test/compile_errors.zig+60| ... | ... | @@ -2275,4 +2275,64 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 2275 | 2275 | , |
| 2276 | 2276 | ".tmp_source.zig:2:1: error: invalid character: '\\t'"); |
| 2277 | 2277 | |
| 2278 | cases.add("@ArgType given non function parameter", | |
| 2279 | \\comptime { | |
| 2280 | \\ _ = @ArgType(i32, 3); | |
| 2281 | \\} | |
| 2282 | , | |
| 2283 | ".tmp_source.zig:2:18: error: expected function, found 'i32'"); | |
| 2284 | ||
| 2285 | cases.add("@ArgType arg index out of bounds", | |
| 2286 | \\comptime { | |
| 2287 | \\ _ = @ArgType(@typeOf(add), 2); | |
| 2288 | \\} | |
| 2289 | \\fn add(a: i32, b: i32) -> i32 { return a + b; } | |
| 2290 | , | |
| 2291 | ".tmp_source.zig:2:32: error: arg index 2 out of bounds; 'fn(i32, i32) -> i32' has 2 arguments"); | |
| 2292 | ||
| 2293 | cases.add("@memberType on unsupported type", | |
| 2294 | \\comptime { | |
| 2295 | \\ _ = @memberType(i32, 0); | |
| 2296 | \\} | |
| 2297 | , | |
| 2298 | ".tmp_source.zig:2:21: error: type 'i32' does not support @memberType"); | |
| 2299 | ||
| 2300 | cases.add("@memberType struct out of bounds", | |
| 2301 | \\comptime { | |
| 2302 | \\ _ = @memberType(Foo, 0); | |
| 2303 | \\} | |
| 2304 | \\const Foo = struct {}; | |
| 2305 | , | |
| 2306 | ".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members"); | |
| 2307 | ||
| 2308 | cases.add("@memberType enum out of bounds", | |
| 2309 | \\comptime { | |
| 2310 | \\ _ = @memberType(Foo, 0); | |
| 2311 | \\} | |
| 2312 | \\const Foo = enum {}; | |
| 2313 | , | |
| 2314 | ".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members"); | |
| 2315 | ||
| 2316 | cases.add("@memberName on unsupported type", | |
| 2317 | \\comptime { | |
| 2318 | \\ _ = @memberName(i32, 0); | |
| 2319 | \\} | |
| 2320 | , | |
| 2321 | ".tmp_source.zig:2:21: error: type 'i32' does not support @memberName"); | |
| 2322 | ||
| 2323 | cases.add("@memberName struct out of bounds", | |
| 2324 | \\comptime { | |
| 2325 | \\ _ = @memberName(Foo, 0); | |
| 2326 | \\} | |
| 2327 | \\const Foo = struct {}; | |
| 2328 | , | |
| 2329 | ".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members"); | |
| 2330 | ||
| 2331 | cases.add("@memberName enum out of bounds", | |
| 2332 | \\comptime { | |
| 2333 | \\ _ = @memberName(Foo, 0); | |
| 2334 | \\} | |
| 2335 | \\const Foo = enum {}; | |
| 2336 | , | |
| 2337 | ".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members"); | |
| 2278 | 2338 | } |