| author | |
| committer | |
| log | 1fc2082b4ccc2b75fba892bc9e27e9a5a3d821bf |
| tree | 1c63bda773e97c41bcbdfd68d3d880ef46c0bd8d |
| parent | 63d37b7cff0907cdf2361f1d61f19410fd6cc626 |
See #2616 files changed, 370 insertions(+), 86 deletions(-)
src/all_types.hpp+13-2| ... | ... | @@ -873,11 +873,13 @@ struct TypeStructField { |
| 873 | 873 | TypeTableEntry *type_entry; |
| 874 | 874 | size_t src_index; |
| 875 | 875 | size_t gen_index; |
| 876 | // offset from the memory at gen_index | |
| 877 | size_t packed_bits_offset; | |
| 878 | size_t packed_bits_size; | |
| 876 | 879 | }; |
| 877 | 880 | struct TypeTableEntryStruct { |
| 878 | 881 | AstNode *decl_node; |
| 879 | 882 | ContainerLayout layout; |
| 880 | bool is_packed; | |
| 881 | 883 | uint32_t src_field_count; |
| 882 | 884 | uint32_t gen_field_count; |
| 883 | 885 | TypeStructField *fields; |
| ... | ... | @@ -1037,7 +1039,7 @@ struct TypeTableEntry { |
| 1037 | 1039 | |
| 1038 | 1040 | // use these fields to make sure we don't duplicate type table entries for the same type |
| 1039 | 1041 | TypeTableEntry *pointer_parent[2][2]; // [0 - mut, 1 - const][0 - normal, 1 - volatile] |
| 1040 | TypeTableEntry *unknown_size_array_parent[2]; | |
| 1042 | TypeTableEntry *slice_parent[2]; // [0 - mut, 1 - const] | |
| 1041 | 1043 | HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size; |
| 1042 | 1044 | TypeTableEntry *maybe_parent; |
| 1043 | 1045 | TypeTableEntry *error_parent; |
| ... | ... | @@ -1193,6 +1195,14 @@ enum PanicMsgId { |
| 1193 | 1195 | uint32_t fn_eval_hash(Scope*); |
| 1194 | 1196 | bool fn_eval_eql(Scope *a, Scope *b); |
| 1195 | 1197 | |
| 1198 | struct IntTypeId { | |
| 1199 | bool is_signed; | |
| 1200 | uint8_t bit_count; | |
| 1201 | }; | |
| 1202 | ||
| 1203 | uint32_t int_type_id_hash(IntTypeId); | |
| 1204 | bool int_type_id_eql(IntTypeId a, IntTypeId b); | |
| 1205 | ||
| 1196 | 1206 | struct CodeGen { |
| 1197 | 1207 | LLVMModuleRef module; |
| 1198 | 1208 | ZigList<ErrorMsg*> errors; |
| ... | ... | @@ -1208,6 +1218,7 @@ struct CodeGen { |
| 1208 | 1218 | HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table; |
| 1209 | 1219 | HashMap<Buf *, BuiltinFnEntry *, buf_hash, buf_eql_buf> builtin_fn_table; |
| 1210 | 1220 | HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> primitive_type_table; |
| 1221 | HashMap<IntTypeId, TypeTableEntry *, int_type_id_hash, int_type_id_eql> int_type_table; | |
| 1211 | 1222 | HashMap<FnTypeId *, TypeTableEntry *, fn_type_id_hash, fn_type_id_eql> fn_type_table; |
| 1212 | 1223 | HashMap<Buf *, ErrorTableEntry *, buf_hash, buf_eql_buf> error_table; |
| 1213 | 1224 | HashMap<GenericFnTypeId *, FnTableEntry *, generic_fn_type_id_hash, generic_fn_type_id_eql> generic_table; |
src/analyze.cpp+202-19| ... | ... | @@ -261,6 +261,24 @@ uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry) { |
| 261 | 261 | } |
| 262 | 262 | } |
| 263 | 263 | |
| 264 | // This has to do with packed structs | |
| 265 | static uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry) { | |
| 266 | TypeTableEntry *canon_type = get_underlying_type(type_entry); | |
| 267 | ||
| 268 | if (!type_has_bits(type_entry)) | |
| 269 | return 0; | |
| 270 | ||
| 271 | if (canon_type->id == TypeTableEntryIdStruct && canon_type->data.structure.layout == ContainerLayoutPacked) { | |
| 272 | uint64_t result = 0; | |
| 273 | for (size_t i = 0; i < canon_type->data.structure.src_field_count; i += 1) { | |
| 274 | result += type_size_bits(g, canon_type->data.structure.fields[i].type_entry); | |
| 275 | } | |
| 276 | return result; | |
| 277 | } | |
| 278 | ||
| 279 | return LLVMSizeOfTypeInBits(g->target_data_ref, canon_type->type_ref); | |
| 280 | } | |
| 281 | ||
| 264 | 282 | static bool is_slice(TypeTableEntry *type) { |
| 265 | 283 | return type->id == TypeTableEntryIdStruct && type->data.structure.is_slice; |
| 266 | 284 | } |
| ... | ... | @@ -507,7 +525,7 @@ static void slice_type_common_init(CodeGen *g, TypeTableEntry *child_type, |
| 507 | 525 | TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const); |
| 508 | 526 | |
| 509 | 527 | unsigned element_count = 2; |
| 510 | entry->data.structure.is_packed = false; | |
| 528 | entry->data.structure.layout = ContainerLayoutAuto; | |
| 511 | 529 | entry->data.structure.is_slice = true; |
| 512 | 530 | entry->data.structure.src_field_count = element_count; |
| 513 | 531 | entry->data.structure.gen_field_count = element_count; |
| ... | ... | @@ -531,7 +549,7 @@ static void slice_type_common_init(CodeGen *g, TypeTableEntry *child_type, |
| 531 | 549 | |
| 532 | 550 | TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) { |
| 533 | 551 | assert(child_type->id != TypeTableEntryIdInvalid); |
| 534 | TypeTableEntry **parent_pointer = &child_type->unknown_size_array_parent[(is_const ? 1 : 0)]; | |
| 552 | TypeTableEntry **parent_pointer = &child_type->slice_parent[(is_const ? 1 : 0)]; | |
| 535 | 553 | |
| 536 | 554 | if (*parent_pointer) { |
| 537 | 555 | return *parent_pointer; |
| ... | ... | @@ -1269,6 +1287,48 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { |
| 1269 | 1287 | } |
| 1270 | 1288 | } |
| 1271 | 1289 | |
| 1290 | static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) { | |
| 1291 | TypeTableEntry *canon_type = get_underlying_type(type_entry); | |
| 1292 | switch (canon_type->id) { | |
| 1293 | case TypeTableEntryIdInvalid: | |
| 1294 | case TypeTableEntryIdVar: | |
| 1295 | zig_unreachable(); | |
| 1296 | case TypeTableEntryIdMetaType: | |
| 1297 | case TypeTableEntryIdUnreachable: | |
| 1298 | case TypeTableEntryIdNumLitFloat: | |
| 1299 | case TypeTableEntryIdNumLitInt: | |
| 1300 | case TypeTableEntryIdUndefLit: | |
| 1301 | case TypeTableEntryIdNullLit: | |
| 1302 | case TypeTableEntryIdErrorUnion: | |
| 1303 | case TypeTableEntryIdPureError: | |
| 1304 | case TypeTableEntryIdEnum: | |
| 1305 | case TypeTableEntryIdEnumTag: | |
| 1306 | case TypeTableEntryIdTypeDecl: | |
| 1307 | case TypeTableEntryIdNamespace: | |
| 1308 | case TypeTableEntryIdBlock: | |
| 1309 | case TypeTableEntryIdBoundFn: | |
| 1310 | case TypeTableEntryIdArgTuple: | |
| 1311 | return false; | |
| 1312 | case TypeTableEntryIdVoid: | |
| 1313 | case TypeTableEntryIdBool: | |
| 1314 | case TypeTableEntryIdInt: | |
| 1315 | case TypeTableEntryIdFloat: | |
| 1316 | case TypeTableEntryIdPointer: | |
| 1317 | case TypeTableEntryIdArray: | |
| 1318 | case TypeTableEntryIdUnion: | |
| 1319 | case TypeTableEntryIdFn: | |
| 1320 | return true; | |
| 1321 | case TypeTableEntryIdStruct: | |
| 1322 | return canon_type->data.structure.layout == ContainerLayoutPacked; | |
| 1323 | case TypeTableEntryIdMaybe: | |
| 1324 | { | |
| 1325 | TypeTableEntry *canon_child_type = get_underlying_type(canon_type->data.maybe.child_type); | |
| 1326 | return canon_child_type->id == TypeTableEntryIdPointer || canon_child_type->id == TypeTableEntryIdFn; | |
| 1327 | } | |
| 1328 | } | |
| 1329 | zig_unreachable(); | |
| 1330 | } | |
| 1331 | ||
| 1272 | 1332 | static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { |
| 1273 | 1333 | // if you change the logic of this function likely you must make a similar change in |
| 1274 | 1334 | // parseh.cpp |
| ... | ... | @@ -1307,22 +1367,77 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { |
| 1307 | 1367 | |
| 1308 | 1368 | Scope *scope = &struct_type->data.structure.decls_scope->base; |
| 1309 | 1369 | |
| 1370 | size_t gen_field_index = 0; | |
| 1371 | bool packed = (struct_type->data.structure.layout == ContainerLayoutPacked); | |
| 1372 | size_t packed_bits_offset = 0; | |
| 1373 | size_t first_packed_bits_offset_misalign = SIZE_MAX; | |
| 1374 | size_t debug_field_count = 0; | |
| 1375 | ||
| 1310 | 1376 | for (size_t i = 0; i < field_count; i += 1) { |
| 1311 | 1377 | TypeStructField *type_struct_field = &struct_type->data.structure.fields[i]; |
| 1312 | 1378 | TypeTableEntry *field_type = type_struct_field->type_entry; |
| 1313 | 1379 | |
| 1314 | 1380 | ensure_complete_type(g, field_type); |
| 1381 | ||
| 1315 | 1382 | if (type_is_invalid(field_type)) { |
| 1316 | 1383 | struct_type->data.structure.is_invalid = true; |
| 1317 | continue; | |
| 1384 | break; | |
| 1318 | 1385 | } |
| 1319 | 1386 | |
| 1320 | 1387 | if (!type_has_bits(field_type)) |
| 1321 | 1388 | continue; |
| 1322 | 1389 | |
| 1323 | element_types[type_struct_field->gen_index] = field_type->type_ref; | |
| 1324 | assert(element_types[type_struct_field->gen_index]); | |
| 1390 | type_struct_field->gen_index = gen_field_index; | |
| 1391 | ||
| 1392 | if (packed) { | |
| 1393 | if (!type_allowed_in_packed_struct(field_type)) { | |
| 1394 | AstNode *field_source_node = decl_node->data.container_decl.fields.at(i); | |
| 1395 | add_node_error(g, field_source_node, | |
| 1396 | buf_sprintf("packed structs cannot contain fields of type '%s'", | |
| 1397 | buf_ptr(&field_type->name))); | |
| 1398 | struct_type->data.structure.is_invalid = true; | |
| 1399 | break; | |
| 1400 | } | |
| 1401 | ||
| 1402 | type_struct_field->packed_bits_size = type_size_bits(g, field_type); | |
| 1403 | ||
| 1404 | size_t next_packed_bits_offset = packed_bits_offset + type_struct_field->packed_bits_size; | |
| 1405 | ||
| 1406 | if (first_packed_bits_offset_misalign != SIZE_MAX) { | |
| 1407 | // this field is not byte-aligned; it is part of the previous field with a bit offset | |
| 1408 | type_struct_field->packed_bits_offset = packed_bits_offset - first_packed_bits_offset_misalign; | |
| 1409 | ||
| 1410 | if (next_packed_bits_offset % 8 == 0) { | |
| 1411 | // next field recovers byte alignment | |
| 1412 | size_t full_bit_count = next_packed_bits_offset - first_packed_bits_offset_misalign; | |
| 1413 | element_types[gen_field_index] = LLVMIntType(full_bit_count); | |
| 1414 | gen_field_index += 1; | |
| 1415 | ||
| 1416 | first_packed_bits_offset_misalign = SIZE_MAX; | |
| 1417 | } | |
| 1418 | } else if (next_packed_bits_offset % 8 != 0) { | |
| 1419 | first_packed_bits_offset_misalign = packed_bits_offset; | |
| 1420 | type_struct_field->packed_bits_offset = 0; | |
| 1421 | } else { | |
| 1422 | element_types[gen_field_index] = field_type->type_ref; | |
| 1423 | type_struct_field->packed_bits_offset = 0; | |
| 1424 | gen_field_index += 1; | |
| 1425 | } | |
| 1426 | packed_bits_offset = next_packed_bits_offset; | |
| 1427 | } else { | |
| 1428 | element_types[gen_field_index] = field_type->type_ref; | |
| 1429 | assert(element_types[gen_field_index]); | |
| 1430 | ||
| 1431 | gen_field_index += 1; | |
| 1432 | } | |
| 1433 | debug_field_count += 1; | |
| 1325 | 1434 | } |
| 1435 | if (first_packed_bits_offset_misalign != SIZE_MAX) { | |
| 1436 | size_t full_bit_count = packed_bits_offset - first_packed_bits_offset_misalign; | |
| 1437 | element_types[gen_field_index] = LLVMIntType(full_bit_count); | |
| 1438 | gen_field_index += 1; | |
| 1439 | } | |
| 1440 | ||
| 1326 | 1441 | struct_type->data.structure.embedded_in_current = false; |
| 1327 | 1442 | struct_type->data.structure.complete = true; |
| 1328 | 1443 | |
| ... | ... | @@ -1337,13 +1452,18 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { |
| 1337 | 1452 | } |
| 1338 | 1453 | assert(struct_type->di_type); |
| 1339 | 1454 | |
| 1340 | bool packed = (struct_type->data.structure.layout == ContainerLayoutPacked); | |
| 1455 | ||
| 1456 | // the count may have been adjusting from packing bit fields | |
| 1457 | gen_field_count = gen_field_index; | |
| 1458 | struct_type->data.structure.gen_field_count = gen_field_count; | |
| 1459 | ||
| 1341 | 1460 | LLVMStructSetBody(struct_type->type_ref, element_types, gen_field_count, packed); |
| 1342 | 1461 | assert(LLVMStoreSizeOfType(g->target_data_ref, struct_type->type_ref) > 0); |
| 1343 | 1462 | |
| 1344 | ZigLLVMDIType **di_element_types = allocate<ZigLLVMDIType*>(gen_field_count); | |
| 1463 | ZigLLVMDIType **di_element_types = allocate<ZigLLVMDIType*>(debug_field_count); | |
| 1345 | 1464 | |
| 1346 | 1465 | ImportTableEntry *import = get_scope_import(scope); |
| 1466 | size_t debug_field_index = 0; | |
| 1347 | 1467 | for (size_t i = 0; i < field_count; i += 1) { |
| 1348 | 1468 | AstNode *field_node = decl_node->data.container_decl.fields.at(i); |
| 1349 | 1469 | TypeStructField *type_struct_field = &struct_type->data.structure.fields[i]; |
| ... | ... | @@ -1369,19 +1489,28 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { |
| 1369 | 1489 | assert(field_type->type_ref); |
| 1370 | 1490 | assert(struct_type->type_ref); |
| 1371 | 1491 | assert(struct_type->data.structure.complete); |
| 1372 | uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref); | |
| 1373 | uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, field_type->type_ref); | |
| 1374 | uint64_t debug_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, struct_type->type_ref, | |
| 1375 | gen_field_index); | |
| 1376 | di_element_types[gen_field_index] = ZigLLVMCreateDebugMemberType(g->dbuilder, | |
| 1492 | uint64_t debug_size_in_bits; | |
| 1493 | uint64_t debug_align_in_bits; | |
| 1494 | uint64_t debug_offset_in_bits; | |
| 1495 | if (packed) { | |
| 1496 | debug_size_in_bits = type_struct_field->packed_bits_size; | |
| 1497 | debug_align_in_bits = 1; | |
| 1498 | debug_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, struct_type->type_ref, | |
| 1499 | gen_field_index) + type_struct_field->packed_bits_offset; | |
| 1500 | } else { | |
| 1501 | debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref); | |
| 1502 | debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, field_type->type_ref); | |
| 1503 | debug_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, struct_type->type_ref, gen_field_index); | |
| 1504 | } | |
| 1505 | di_element_types[debug_field_index] = ZigLLVMCreateDebugMemberType(g->dbuilder, | |
| 1377 | 1506 | ZigLLVMTypeToScope(struct_type->di_type), buf_ptr(type_struct_field->name), |
| 1378 | 1507 | import->di_file, field_node->line + 1, |
| 1379 | 1508 | debug_size_in_bits, |
| 1380 | 1509 | debug_align_in_bits, |
| 1381 | 1510 | debug_offset_in_bits, |
| 1382 | 1511 | 0, field_di_type); |
| 1383 | ||
| 1384 | assert(di_element_types[gen_field_index]); | |
| 1512 | assert(di_element_types[debug_field_index]); | |
| 1513 | debug_field_index += 1; | |
| 1385 | 1514 | } |
| 1386 | 1515 | |
| 1387 | 1516 | |
| ... | ... | @@ -1393,7 +1522,7 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { |
| 1393 | 1522 | import->di_file, decl_node->line + 1, |
| 1394 | 1523 | debug_size_in_bits, |
| 1395 | 1524 | debug_align_in_bits, |
| 1396 | 0, nullptr, di_element_types, gen_field_count, 0, nullptr, ""); | |
| 1525 | 0, nullptr, di_element_types, debug_field_count, 0, nullptr, ""); | |
| 1397 | 1526 | |
| 1398 | 1527 | ZigLLVMReplaceTemporary(g->dbuilder, struct_type->di_type, replacement_di_type); |
| 1399 | 1528 | struct_type->di_type = replacement_di_type; |
| ... | ... | @@ -2672,7 +2801,7 @@ bool is_node_void_expr(AstNode *node) { |
| 2672 | 2801 | return false; |
| 2673 | 2802 | } |
| 2674 | 2803 | |
| 2675 | TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, size_t size_in_bits) { | |
| 2804 | TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, uint8_t size_in_bits) { | |
| 2676 | 2805 | size_t index; |
| 2677 | 2806 | if (size_in_bits == 8) { |
| 2678 | 2807 | index = 0; |
| ... | ... | @@ -2683,13 +2812,25 @@ TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, size_t size_in_bit |
| 2683 | 2812 | } else if (size_in_bits == 64) { |
| 2684 | 2813 | index = 3; |
| 2685 | 2814 | } else { |
| 2686 | zig_unreachable(); | |
| 2815 | return nullptr; | |
| 2687 | 2816 | } |
| 2688 | 2817 | return &g->builtin_types.entry_int[is_signed ? 0 : 1][index]; |
| 2689 | 2818 | } |
| 2690 | 2819 | |
| 2691 | TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, size_t size_in_bits) { | |
| 2692 | return *get_int_type_ptr(g, is_signed, size_in_bits); | |
| 2820 | TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, uint8_t size_in_bits) { | |
| 2821 | TypeTableEntry **common_entry = get_int_type_ptr(g, is_signed, size_in_bits); | |
| 2822 | if (common_entry) | |
| 2823 | return *common_entry; | |
| 2824 | ||
| 2825 | { | |
| 2826 | auto entry = g->int_type_table.maybe_get({is_signed, size_in_bits}); | |
| 2827 | if (entry) | |
| 2828 | return entry->value; | |
| 2829 | } | |
| 2830 | ||
| 2831 | TypeTableEntry *new_entry = make_int_type(g, is_signed, size_in_bits); | |
| 2832 | g->int_type_table.put({is_signed, size_in_bits}, new_entry); | |
| 2833 | return new_entry; | |
| 2693 | 2834 | } |
| 2694 | 2835 | |
| 2695 | 2836 | TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type) { |
| ... | ... | @@ -3703,3 +3844,45 @@ void render_const_value(Buf *buf, ConstExprValue *const_val) { |
| 3703 | 3844 | } |
| 3704 | 3845 | zig_unreachable(); |
| 3705 | 3846 | } |
| 3847 | ||
| 3848 | TypeTableEntry *make_int_type(CodeGen *g, bool is_signed, size_t size_in_bits) { | |
| 3849 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); | |
| 3850 | entry->type_ref = LLVMIntType(size_in_bits); | |
| 3851 | ||
| 3852 | const char u_or_i = is_signed ? 'i' : 'u'; | |
| 3853 | buf_resize(&entry->name, 0); | |
| 3854 | buf_appendf(&entry->name, "%c%zu", u_or_i, size_in_bits); | |
| 3855 | ||
| 3856 | unsigned dwarf_tag; | |
| 3857 | if (is_signed) { | |
| 3858 | if (size_in_bits == 8) { | |
| 3859 | dwarf_tag = ZigLLVMEncoding_DW_ATE_signed_char(); | |
| 3860 | } else { | |
| 3861 | dwarf_tag = ZigLLVMEncoding_DW_ATE_signed(); | |
| 3862 | } | |
| 3863 | } else { | |
| 3864 | if (size_in_bits == 8) { | |
| 3865 | dwarf_tag = ZigLLVMEncoding_DW_ATE_unsigned_char(); | |
| 3866 | } else { | |
| 3867 | dwarf_tag = ZigLLVMEncoding_DW_ATE_unsigned(); | |
| 3868 | } | |
| 3869 | } | |
| 3870 | ||
| 3871 | uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref); | |
| 3872 | uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref); | |
| 3873 | entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), | |
| 3874 | debug_size_in_bits, debug_align_in_bits, dwarf_tag); | |
| 3875 | entry->data.integral.is_signed = is_signed; | |
| 3876 | entry->data.integral.bit_count = size_in_bits; | |
| 3877 | return entry; | |
| 3878 | } | |
| 3879 | ||
| 3880 | uint32_t int_type_id_hash(IntTypeId x) { | |
| 3881 | uint32_t hash = x.is_signed ? 2652528194 : 163929201; | |
| 3882 | hash += ((uint32_t)x.bit_count) * 2998081557; | |
| 3883 | return hash; | |
| 3884 | } | |
| 3885 | ||
| 3886 | bool int_type_id_eql(IntTypeId a, IntTypeId b) { | |
| 3887 | return (a.is_signed == b.is_signed && a.bit_count == b.bit_count); | |
| 3888 | } |
src/analyze.hpp+4-2| ... | ... | @@ -18,8 +18,8 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool |
| 18 | 18 | TypeTableEntry *get_pointer_to_type_volatile(CodeGen *g, TypeTableEntry *child_type, bool is_const, bool is_volatile); |
| 19 | 19 | bool is_node_void_expr(AstNode *node); |
| 20 | 20 | uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry); |
| 21 | TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, size_t size_in_bits); | |
| 22 | TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, size_t size_in_bits); | |
| 21 | TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, uint8_t size_in_bits); | |
| 22 | TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, uint8_t size_in_bits); | |
| 23 | 23 | TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type); |
| 24 | 24 | TypeTableEntry *get_c_int_type(CodeGen *g, CIntType c_int_type); |
| 25 | 25 | TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry *child_type); |
| ... | ... | @@ -143,4 +143,6 @@ ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_ |
| 143 | 143 | |
| 144 | 144 | void init_const_undefined(CodeGen *g, ConstExprValue *const_val); |
| 145 | 145 | |
| 146 | TypeTableEntry *make_int_type(CodeGen *g, bool is_signed, size_t size_in_bits); | |
| 147 | ||
| 146 | 148 | #endif |
src/bignum.cpp+19-26| ... | ... | @@ -46,42 +46,35 @@ void bignum_init_bignum(BigNum *dest, BigNum *src) { |
| 46 | 46 | safe_memcpy(dest, src, 1); |
| 47 | 47 | } |
| 48 | 48 | |
| 49 | static int u64_log2(uint64_t x) { | |
| 50 | int result = 0; | |
| 51 | for (; x != 0; x >>= 1) { | |
| 52 | result += 1; | |
| 53 | } | |
| 54 | return result; | |
| 55 | } | |
| 56 | ||
| 49 | 57 | bool bignum_fits_in_bits(BigNum *bn, int bit_count, bool is_signed) { |
| 50 | 58 | assert(bn->kind == BigNumKindInt); |
| 51 | 59 | |
| 52 | 60 | if (is_signed) { |
| 53 | if (bn->is_negative) { | |
| 54 | if (bn->data.x_uint <= ((uint64_t)INT8_MAX) + 1) { | |
| 55 | return bit_count >= 8; | |
| 56 | } else if (bn->data.x_uint <= ((uint64_t)INT16_MAX) + 1) { | |
| 57 | return bit_count >= 16; | |
| 58 | } else if (bn->data.x_uint <= ((uint64_t)INT32_MAX) + 1) { | |
| 59 | return bit_count >= 32; | |
| 60 | } else { | |
| 61 | return bit_count >= 64; | |
| 62 | } | |
| 63 | } else if (bn->data.x_uint <= (uint64_t)INT8_MAX) { | |
| 64 | return bit_count >= 8; | |
| 65 | } else if (bn->data.x_uint <= (uint64_t)INT16_MAX) { | |
| 66 | return bit_count >= 16; | |
| 67 | } else if (bn->data.x_uint <= (uint64_t)INT32_MAX) { | |
| 68 | return bit_count >= 32; | |
| 61 | uint64_t max_neg; | |
| 62 | uint64_t max_pos; | |
| 63 | if (bit_count < 64) { | |
| 64 | max_neg = (1ULL << (bit_count - 1)); | |
| 65 | max_pos = max_neg - 1; | |
| 69 | 66 | } else { |
| 70 | return bit_count >= 64; | |
| 67 | max_pos = ((uint64_t)INT64_MAX); | |
| 68 | max_neg = max_pos + 1; | |
| 71 | 69 | } |
| 70 | uint64_t max_val = bn->is_negative ? max_neg : max_pos; | |
| 71 | return bn->data.x_uint <= max_val; | |
| 72 | 72 | } else { |
| 73 | 73 | if (bn->is_negative) { |
| 74 | 74 | return bn->data.x_uint == 0; |
| 75 | 75 | } else { |
| 76 | if (bn->data.x_uint <= UINT8_MAX) { | |
| 77 | return bit_count >= 8; | |
| 78 | } else if (bn->data.x_uint <= UINT16_MAX) { | |
| 79 | return bit_count >= 16; | |
| 80 | } else if (bn->data.x_uint <= UINT32_MAX) { | |
| 81 | return bit_count >= 32; | |
| 82 | } else { | |
| 83 | return bit_count >= 64; | |
| 84 | } | |
| 76 | int required_bit_count = u64_log2(bn->data.x_uint); | |
| 77 | return bit_count >= required_bit_count; | |
| 85 | 78 | } |
| 86 | 79 | } |
| 87 | 80 | } |
src/codegen.cpp+130-37| ... | ... | @@ -58,6 +58,7 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) { |
| 58 | 58 | g->import_table.init(32); |
| 59 | 59 | g->builtin_fn_table.init(32); |
| 60 | 60 | g->primitive_type_table.init(32); |
| 61 | g->int_type_table.init(8); | |
| 61 | 62 | g->fn_type_table.init(32); |
| 62 | 63 | g->error_table.init(16); |
| 63 | 64 | g->generic_table.init(16); |
| ... | ... | @@ -232,6 +233,7 @@ void codegen_set_linker_script(CodeGen *g, const char *linker_script) { |
| 232 | 233 | |
| 233 | 234 | static void render_const_val(CodeGen *g, ConstExprValue *const_val); |
| 234 | 235 | static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const char *name); |
| 236 | static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val); | |
| 235 | 237 | |
| 236 | 238 | static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { |
| 237 | 239 | if (fn_table_entry->llvm_value) |
| ... | ... | @@ -2599,6 +2601,84 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *s |
| 2599 | 2601 | return LLVMConstInBoundsGEP(base_ptr, indices, 2); |
| 2600 | 2602 | } |
| 2601 | 2603 | |
| 2604 | static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, ConstExprValue *const_val) { | |
| 2605 | switch (const_val->special) { | |
| 2606 | case ConstValSpecialRuntime: | |
| 2607 | zig_unreachable(); | |
| 2608 | case ConstValSpecialUndef: | |
| 2609 | return LLVMConstInt(big_int_type_ref, 0, false); | |
| 2610 | case ConstValSpecialStatic: | |
| 2611 | break; | |
| 2612 | } | |
| 2613 | ||
| 2614 | TypeTableEntry *canon_type = get_underlying_type(const_val->type); | |
| 2615 | assert(!canon_type->zero_bits); | |
| 2616 | switch (canon_type->id) { | |
| 2617 | case TypeTableEntryIdInvalid: | |
| 2618 | case TypeTableEntryIdVar: | |
| 2619 | case TypeTableEntryIdMetaType: | |
| 2620 | case TypeTableEntryIdUnreachable: | |
| 2621 | case TypeTableEntryIdNumLitFloat: | |
| 2622 | case TypeTableEntryIdNumLitInt: | |
| 2623 | case TypeTableEntryIdUndefLit: | |
| 2624 | case TypeTableEntryIdNullLit: | |
| 2625 | case TypeTableEntryIdErrorUnion: | |
| 2626 | case TypeTableEntryIdPureError: | |
| 2627 | case TypeTableEntryIdEnum: | |
| 2628 | case TypeTableEntryIdEnumTag: | |
| 2629 | case TypeTableEntryIdTypeDecl: | |
| 2630 | case TypeTableEntryIdNamespace: | |
| 2631 | case TypeTableEntryIdBlock: | |
| 2632 | case TypeTableEntryIdBoundFn: | |
| 2633 | case TypeTableEntryIdArgTuple: | |
| 2634 | case TypeTableEntryIdVoid: | |
| 2635 | zig_unreachable(); | |
| 2636 | case TypeTableEntryIdBool: | |
| 2637 | return LLVMConstInt(big_int_type_ref, const_val->data.x_bool ? 1 : 0, false); | |
| 2638 | case TypeTableEntryIdInt: | |
| 2639 | { | |
| 2640 | LLVMValueRef int_val = gen_const_val(g, const_val); | |
| 2641 | return LLVMConstZExt(int_val, big_int_type_ref); | |
| 2642 | } | |
| 2643 | return LLVMConstInt(big_int_type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false); | |
| 2644 | case TypeTableEntryIdFloat: | |
| 2645 | { | |
| 2646 | LLVMValueRef float_val = gen_const_val(g, const_val); | |
| 2647 | LLVMValueRef int_val = LLVMConstFPToUI(float_val, LLVMIntType(canon_type->data.floating.bit_count)); | |
| 2648 | return LLVMConstZExt(int_val, big_int_type_ref); | |
| 2649 | } | |
| 2650 | case TypeTableEntryIdPointer: | |
| 2651 | case TypeTableEntryIdFn: | |
| 2652 | case TypeTableEntryIdMaybe: | |
| 2653 | { | |
| 2654 | LLVMValueRef ptr_val = gen_const_val(g, const_val); | |
| 2655 | LLVMValueRef ptr_size_int_val = LLVMConstPtrToInt(ptr_val, g->builtin_types.entry_usize->type_ref); | |
| 2656 | return LLVMConstZExt(ptr_size_int_val, big_int_type_ref); | |
| 2657 | } | |
| 2658 | case TypeTableEntryIdArray: | |
| 2659 | zig_panic("TODO bit pack an array"); | |
| 2660 | case TypeTableEntryIdUnion: | |
| 2661 | zig_panic("TODO bit pack a union"); | |
| 2662 | case TypeTableEntryIdStruct: | |
| 2663 | { | |
| 2664 | assert(canon_type->data.structure.layout == ContainerLayoutPacked); | |
| 2665 | ||
| 2666 | LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false); | |
| 2667 | for (size_t i = 0; i < canon_type->data.structure.src_field_count; i += 1) { | |
| 2668 | TypeStructField *field = &canon_type->data.structure.fields[i]; | |
| 2669 | if (field->gen_index == SIZE_MAX) { | |
| 2670 | continue; | |
| 2671 | } | |
| 2672 | LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, &const_val->data.x_struct.fields[i]); | |
| 2673 | LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, field->packed_bits_size, false); | |
| 2674 | val = LLVMConstShl(val, shift_amt); | |
| 2675 | val = LLVMConstOr(val, child_val); | |
| 2676 | } | |
| 2677 | return val; | |
| 2678 | } | |
| 2679 | } | |
| 2680 | zig_unreachable(); | |
| 2681 | } | |
| 2602 | 2682 | |
| 2603 | 2683 | static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 2604 | 2684 | TypeTableEntry *canon_type = get_underlying_type(const_val->type); |
| ... | ... | @@ -2670,15 +2750,57 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 2670 | 2750 | case TypeTableEntryIdStruct: |
| 2671 | 2751 | { |
| 2672 | 2752 | LLVMValueRef *fields = allocate<LLVMValueRef>(canon_type->data.structure.gen_field_count); |
| 2673 | for (uint32_t i = 0; i < canon_type->data.structure.src_field_count; i += 1) { | |
| 2674 | TypeStructField *type_struct_field = &canon_type->data.structure.fields[i]; | |
| 2675 | if (type_struct_field->gen_index == SIZE_MAX) { | |
| 2676 | continue; | |
| 2753 | size_t src_field_count = canon_type->data.structure.src_field_count; | |
| 2754 | if (canon_type->data.structure.layout == ContainerLayoutPacked) { | |
| 2755 | size_t src_field_index = 0; | |
| 2756 | while (src_field_index < src_field_count) { | |
| 2757 | TypeStructField *type_struct_field = &canon_type->data.structure.fields[src_field_index]; | |
| 2758 | if (type_struct_field->gen_index == SIZE_MAX) { | |
| 2759 | src_field_index += 1; | |
| 2760 | continue; | |
| 2761 | } | |
| 2762 | ||
| 2763 | size_t src_field_index_end = src_field_index + 1; | |
| 2764 | for (; src_field_index_end < src_field_count; src_field_index_end += 1) { | |
| 2765 | TypeStructField *it_field = &canon_type->data.structure.fields[src_field_index_end]; | |
| 2766 | if (it_field->gen_index != type_struct_field->gen_index) | |
| 2767 | break; | |
| 2768 | } | |
| 2769 | ||
| 2770 | if (src_field_index + 1 == src_field_index_end) { | |
| 2771 | fields[type_struct_field->gen_index] = | |
| 2772 | gen_const_val(g, &const_val->data.x_struct.fields[src_field_index]); | |
| 2773 | } else { | |
| 2774 | LLVMTypeRef big_int_type_ref = LLVMStructGetTypeAtIndex(canon_type->type_ref, | |
| 2775 | type_struct_field->gen_index); | |
| 2776 | LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false); | |
| 2777 | for (size_t i = src_field_index; i < src_field_index_end; i += 1) { | |
| 2778 | TypeStructField *it_field = &canon_type->data.structure.fields[i]; | |
| 2779 | if (it_field->gen_index == SIZE_MAX) { | |
| 2780 | continue; | |
| 2781 | } | |
| 2782 | LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, | |
| 2783 | &const_val->data.x_struct.fields[i]); | |
| 2784 | LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, | |
| 2785 | it_field->packed_bits_size, false); | |
| 2786 | val = LLVMConstShl(val, shift_amt); | |
| 2787 | val = LLVMConstOr(val, child_val); | |
| 2788 | } | |
| 2789 | fields[type_struct_field->gen_index] = val; | |
| 2790 | } | |
| 2791 | ||
| 2792 | src_field_index = src_field_index_end; | |
| 2793 | } | |
| 2794 | } else { | |
| 2795 | for (uint32_t i = 0; i < src_field_count; i += 1) { | |
| 2796 | TypeStructField *type_struct_field = &canon_type->data.structure.fields[i]; | |
| 2797 | if (type_struct_field->gen_index == SIZE_MAX) { | |
| 2798 | continue; | |
| 2799 | } | |
| 2800 | fields[type_struct_field->gen_index] = gen_const_val(g, &const_val->data.x_struct.fields[i]); | |
| 2677 | 2801 | } |
| 2678 | fields[type_struct_field->gen_index] = gen_const_val(g, &const_val->data.x_struct.fields[i]); | |
| 2679 | 2802 | } |
| 2680 | return LLVMConstNamedStruct(canon_type->type_ref, fields, | |
| 2681 | canon_type->data.structure.gen_field_count); | |
| 2803 | return LLVMConstNamedStruct(canon_type->type_ref, fields, canon_type->data.structure.gen_field_count); | |
| 2682 | 2804 | } |
| 2683 | 2805 | case TypeTableEntryIdUnion: |
| 2684 | 2806 | { |
| ... | ... | @@ -3406,37 +3528,8 @@ static void define_builtin_types(CodeGen *g) { |
| 3406 | 3528 | size_t size_in_bits = int_sizes_in_bits[int_size_i]; |
| 3407 | 3529 | for (size_t is_sign_i = 0; is_sign_i < array_length(is_signed_list); is_sign_i += 1) { |
| 3408 | 3530 | bool is_signed = is_signed_list[is_sign_i]; |
| 3409 | ||
| 3410 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); | |
| 3411 | entry->type_ref = LLVMIntType(size_in_bits); | |
| 3412 | ||
| 3413 | const char u_or_i = is_signed ? 'i' : 'u'; | |
| 3414 | buf_resize(&entry->name, 0); | |
| 3415 | buf_appendf(&entry->name, "%c%zu", u_or_i, size_in_bits); | |
| 3416 | ||
| 3417 | unsigned dwarf_tag; | |
| 3418 | if (is_signed) { | |
| 3419 | if (size_in_bits == 8) { | |
| 3420 | dwarf_tag = ZigLLVMEncoding_DW_ATE_signed_char(); | |
| 3421 | } else { | |
| 3422 | dwarf_tag = ZigLLVMEncoding_DW_ATE_signed(); | |
| 3423 | } | |
| 3424 | } else { | |
| 3425 | if (size_in_bits == 8) { | |
| 3426 | dwarf_tag = ZigLLVMEncoding_DW_ATE_unsigned_char(); | |
| 3427 | } else { | |
| 3428 | dwarf_tag = ZigLLVMEncoding_DW_ATE_unsigned(); | |
| 3429 | } | |
| 3430 | } | |
| 3431 | ||
| 3432 | uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref); | |
| 3433 | uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref); | |
| 3434 | entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), | |
| 3435 | debug_size_in_bits, debug_align_in_bits, dwarf_tag); | |
| 3436 | entry->data.integral.is_signed = is_signed; | |
| 3437 | entry->data.integral.bit_count = size_in_bits; | |
| 3531 | TypeTableEntry *entry = make_int_type(g, is_signed, size_in_bits); | |
| 3438 | 3532 | g->primitive_type_table.put(&entry->name, entry); |
| 3439 | ||
| 3440 | 3533 | get_int_type_ptr(g, is_signed, size_in_bits)[0] = entry; |
| 3441 | 3534 | } |
| 3442 | 3535 | } |
test/run_tests.cpp+2| ... | ... | @@ -2212,6 +2212,7 @@ static void run_all_tests(bool reverse) { |
| 2212 | 2212 | for (size_t i = test_cases.length;;) { |
| 2213 | 2213 | TestCase *test_case = test_cases.at(i); |
| 2214 | 2214 | printf("Test %zu/%zu %s...", i + 1, test_cases.length, test_case->case_name); |
| 2215 | fflush(stdout); | |
| 2215 | 2216 | run_test(test_case); |
| 2216 | 2217 | printf("OK\n"); |
| 2217 | 2218 | if (i == 0) break; |
| ... | ... | @@ -2221,6 +2222,7 @@ static void run_all_tests(bool reverse) { |
| 2221 | 2222 | for (size_t i = 0; i < test_cases.length; i += 1) { |
| 2222 | 2223 | TestCase *test_case = test_cases.at(i); |
| 2223 | 2224 | printf("Test %zu/%zu %s...", i + 1, test_cases.length, test_case->case_name); |
| 2225 | fflush(stdout); | |
| 2224 | 2226 | run_test(test_case); |
| 2225 | 2227 | printf("OK\n"); |
| 2226 | 2228 | } |