| author | |
| committer | |
| log | accd5701c251c2741479fe08e56c8271c444f021 |
| tree | 78871f150609687a9210063e90f8f4eb53997c38 |
| parent | 0345d7866347c9066b0646f9e46be9a068dcfaa3 |
Structs were previously using `SegmentedList` to be given indexes, but
were not actually backed by the InternPool arrays.
After this, the only remaining uses of `SegmentedList` in the compiler
are `Module.Decl` and `Module.Namespace`. Once those last two are
migrated to become backed by InternPool arrays as well, we can introduce
state serialization via writing these arrays to disk all at once.
Unfortunately there are a lot of source code locations that touch the
struct type API, so this commit is still work-in-progress. Once I get it
compiling and passing the test suite, I can provide some interesting
data points such as how it affected the InternPool memory size and
performance comparison against master branch.
I also couldn't resist migrating over a bunch of alignment API over to
use the log2 Alignment type rather than a mismash of u32 and u64 byte
units with 0 meaning something implicitly different and special at every
location. Turns out you can do all the math you need directly on the
log2 representation of alignments.36 files changed, 2856 insertions(+), 2602 deletions(-)
src/InternPool.zig+646-184| ... | @@ -1,7 +1,7 @@ | ... | @@ -1,7 +1,7 @@ |
| 1 | //! All interned objects have both a value and a type. | 1 | //! All interned objects have both a value and a type. |
| 2 | //! This data structure is self-contained, with the following exceptions: | 2 | //! This data structure is self-contained, with the following exceptions: |
| 3 | //! * type_struct via Module.Struct.Index | 3 | //! * Module.Namespace has a pointer to Module.File |
| 4 | //! * type_opaque via Module.Namespace.Index and Module.Decl.Index | 4 | //! * Module.Decl has a pointer to Module.CaptureScope |
| 5 | 5 | ||
| 6 | /// Maps `Key` to `Index`. `Key` objects are not stored anywhere; they are | 6 | /// Maps `Key` to `Index`. `Key` objects are not stored anywhere; they are |
| 7 | /// constructed lazily. | 7 | /// constructed lazily. |
| ... | @@ -39,17 +39,11 @@ allocated_namespaces: std.SegmentedList(Module.Namespace, 0) = .{}, | ... | @@ -39,17 +39,11 @@ allocated_namespaces: std.SegmentedList(Module.Namespace, 0) = .{}, |
| 39 | /// Same pattern as with `decls_free_list`. | 39 | /// Same pattern as with `decls_free_list`. |
| 40 | namespaces_free_list: std.ArrayListUnmanaged(Module.Namespace.Index) = .{}, | 40 | namespaces_free_list: std.ArrayListUnmanaged(Module.Namespace.Index) = .{}, |
| 41 | 41 | ||
| 42 | /// Struct objects are stored in this data structure because: | ||
| 43 | /// * They contain pointers such as the field maps. | ||
| 44 | /// * They need to be mutated after creation. | ||
| 45 | allocated_structs: std.SegmentedList(Module.Struct, 0) = .{}, | ||
| 46 | /// When a Struct object is freed from `allocated_structs`, it is pushed into this stack. | ||
| 47 | structs_free_list: std.ArrayListUnmanaged(Module.Struct.Index) = .{}, | ||
| 48 | |||
| 49 | /// Some types such as enums, structs, and unions need to store mappings from field names | 42 | /// Some types such as enums, structs, and unions need to store mappings from field names |
| 50 | /// to field index, or value to field index. In such cases, they will store the underlying | 43 | /// to field index, or value to field index. In such cases, they will store the underlying |
| 51 | /// field names and values directly, relying on one of these maps, stored separately, | 44 | /// field names and values directly, relying on one of these maps, stored separately, |
| 52 | /// to provide lookup. | 45 | /// to provide lookup. |
| 46 | /// These are not serialized; it is computed upon deserialization. | ||
| 53 | maps: std.ArrayListUnmanaged(FieldMap) = .{}, | 47 | maps: std.ArrayListUnmanaged(FieldMap) = .{}, |
| 54 | 48 | ||
| 55 | /// Used for finding the index inside `string_bytes`. | 49 | /// Used for finding the index inside `string_bytes`. |
| ... | @@ -365,11 +359,264 @@ pub const Key = union(enum) { | ... | @@ -365,11 +359,264 @@ pub const Key = union(enum) { |
| 365 | namespace: Module.Namespace.Index, | 359 | namespace: Module.Namespace.Index, |
| 366 | }; | 360 | }; |
| 367 | 361 | ||
| 368 | pub const StructType = extern struct { | 362 | /// Although packed structs and non-packed structs are encoded differently, |
| 369 | /// The `none` tag is used to represent a struct with no fields. | 363 | /// this struct is used for both categories since they share some common |
| 370 | index: Module.Struct.OptionalIndex, | 364 | /// functionality. |
| 371 | /// May be `none` if the struct has no declarations. | 365 | pub const StructType = struct { |
| 366 | extra_index: u32, | ||
| 367 | /// `none` when the struct is `@TypeOf(.{})`. | ||
| 368 | decl: Module.Decl.OptionalIndex, | ||
| 369 | /// `none` when the struct has no declarations. | ||
| 372 | namespace: Module.Namespace.OptionalIndex, | 370 | namespace: Module.Namespace.OptionalIndex, |
| 371 | /// Index of the struct_decl ZIR instruction. | ||
| 372 | zir_index: Zir.Inst.Index, | ||
| 373 | layout: std.builtin.Type.ContainerLayout, | ||
| 374 | field_names: NullTerminatedString.Slice, | ||
| 375 | field_types: Index.Slice, | ||
| 376 | field_inits: Index.Slice, | ||
| 377 | field_aligns: Alignment.Slice, | ||
| 378 | runtime_order: RuntimeOrder.Slice, | ||
| 379 | comptime_bits: ComptimeBits, | ||
| 380 | offsets: Offsets, | ||
| 381 | names_map: MapIndex, | ||
| 382 | |||
| 383 | pub const ComptimeBits = struct { | ||
| 384 | start: u32, | ||
| 385 | len: u32, | ||
| 386 | |||
| 387 | pub fn get(this: @This(), ip: *const InternPool) []u32 { | ||
| 388 | return ip.extra.items[this.start..][0..this.len]; | ||
| 389 | } | ||
| 390 | |||
| 391 | pub fn getBit(this: @This(), ip: *const InternPool, i: usize) bool { | ||
| 392 | if (this.len == 0) return false; | ||
| 393 | return @as(u1, @truncate(this.get(ip)[i / 32] >> @intCast(i % 32))) != 0; | ||
| 394 | } | ||
| 395 | |||
| 396 | pub fn setBit(this: @This(), ip: *const InternPool, i: usize) void { | ||
| 397 | this.get(ip)[i / 32] |= @as(u32, 1) << @intCast(i % 32); | ||
| 398 | } | ||
| 399 | |||
| 400 | pub fn clearBit(this: @This(), ip: *const InternPool, i: usize) void { | ||
| 401 | this.get(ip)[i / 32] &= ~(@as(u32, 1) << @intCast(i % 32)); | ||
| 402 | } | ||
| 403 | }; | ||
| 404 | |||
| 405 | pub const Offsets = struct { | ||
| 406 | start: u32, | ||
| 407 | len: u32, | ||
| 408 | |||
| 409 | pub fn get(this: @This(), ip: *const InternPool) []u32 { | ||
| 410 | return @ptrCast(ip.extra.items[this.start..][0..this.len]); | ||
| 411 | } | ||
| 412 | }; | ||
| 413 | |||
| 414 | pub const RuntimeOrder = enum(u32) { | ||
| 415 | /// Placeholder until layout is resolved. | ||
| 416 | unresolved = std.math.maxInt(u32) - 0, | ||
| 417 | /// Field not present at runtime | ||
| 418 | omitted = std.math.maxInt(u32) - 1, | ||
| 419 | _, | ||
| 420 | |||
| 421 | pub const Slice = struct { | ||
| 422 | start: u32, | ||
| 423 | len: u32, | ||
| 424 | |||
| 425 | pub fn get(slice: Slice, ip: *const InternPool) []RuntimeOrder { | ||
| 426 | return @ptrCast(ip.extra.items[slice.start..][0..slice.len]); | ||
| 427 | } | ||
| 428 | }; | ||
| 429 | |||
| 430 | pub fn toInt(i: @This()) ?u32 { | ||
| 431 | return switch (i) { | ||
| 432 | .omitted => null, | ||
| 433 | .unresolved => unreachable, | ||
| 434 | else => @intFromEnum(i), | ||
| 435 | }; | ||
| 436 | } | ||
| 437 | }; | ||
| 438 | |||
| 439 | /// Look up field index based on field name. | ||
| 440 | pub fn nameIndex(self: StructType, ip: *const InternPool, name: NullTerminatedString) ?u32 { | ||
| 441 | if (self.decl == .none) return null; // empty_struct_type | ||
| 442 | const map = &ip.maps.items[@intFromEnum(self.names_map)]; | ||
| 443 | const adapter: NullTerminatedString.Adapter = .{ .strings = self.field_names.get(ip) }; | ||
| 444 | const field_index = map.getIndexAdapted(name, adapter) orelse return null; | ||
| 445 | return @intCast(field_index); | ||
| 446 | } | ||
| 447 | |||
| 448 | /// Returns the already-existing field with the same name, if any. | ||
| 449 | pub fn addFieldName( | ||
| 450 | self: @This(), | ||
| 451 | ip: *InternPool, | ||
| 452 | name: NullTerminatedString, | ||
| 453 | ) ?u32 { | ||
| 454 | return ip.addFieldName(self.names_map, self.field_names.start, name); | ||
| 455 | } | ||
| 456 | |||
| 457 | pub fn fieldAlign(s: @This(), ip: *const InternPool, i: usize) Alignment { | ||
| 458 | if (s.field_aligns.len == 0) return .none; | ||
| 459 | return s.field_aligns.get(ip)[i]; | ||
| 460 | } | ||
| 461 | |||
| 462 | pub fn fieldInit(s: @This(), ip: *const InternPool, i: usize) Index { | ||
| 463 | if (s.field_inits.len == 0) return .none; | ||
| 464 | return s.field_inits.get(ip)[i]; | ||
| 465 | } | ||
| 466 | |||
| 467 | /// Returns `none` in the case the struct is a tuple. | ||
| 468 | pub fn fieldName(s: @This(), ip: *const InternPool, i: usize) OptionalNullTerminatedString { | ||
| 469 | if (s.field_names.len == 0) return .none; | ||
| 470 | return s.field_names.get(ip)[i].toOptional(); | ||
| 471 | } | ||
| 472 | |||
| 473 | pub fn fieldIsComptime(s: @This(), ip: *const InternPool, i: usize) bool { | ||
| 474 | return s.comptime_bits.getBit(ip, i); | ||
| 475 | } | ||
| 476 | |||
| 477 | pub fn setFieldComptime(s: @This(), ip: *InternPool, i: usize) void { | ||
| 478 | s.comptime_bits.setBit(ip, i); | ||
| 479 | } | ||
| 480 | |||
| 481 | /// Reads the non-opv flag calculated during AstGen. Used to short-circuit more | ||
| 482 | /// complicated logic. | ||
| 483 | pub fn knownNonOpv(s: @This(), ip: *InternPool) bool { | ||
| 484 | return switch (s.layout) { | ||
| 485 | .Packed => false, | ||
| 486 | .Auto, .Extern => s.flagsPtr(ip).known_non_opv, | ||
| 487 | }; | ||
| 488 | } | ||
| 489 | |||
| 490 | /// The returned pointer expires with any addition to the `InternPool`. | ||
| 491 | /// Asserts the struct is not packed. | ||
| 492 | pub fn flagsPtr(self: @This(), ip: *InternPool) *Tag.TypeStruct.Flags { | ||
| 493 | assert(self.layout != .Packed); | ||
| 494 | const flags_field_index = std.meta.fieldIndex(Tag.TypeStruct, "flags").?; | ||
| 495 | return @ptrCast(&ip.extra.items[self.extra_index + flags_field_index]); | ||
| 496 | } | ||
| 497 | |||
| 498 | pub fn assumeRuntimeBitsIfFieldTypesWip(s: @This(), ip: *InternPool) bool { | ||
| 499 | if (s.layout == .Packed) return false; | ||
| 500 | const flags_ptr = s.flagsPtr(ip); | ||
| 501 | if (flags_ptr.field_types_wip) { | ||
| 502 | flags_ptr.assumed_runtime_bits = true; | ||
| 503 | return true; | ||
| 504 | } | ||
| 505 | return false; | ||
| 506 | } | ||
| 507 | |||
| 508 | pub fn setLayoutWip(s: @This(), ip: *InternPool) bool { | ||
| 509 | if (s.layout == .Packed) return false; | ||
| 510 | const flags_ptr = s.flagsPtr(ip); | ||
| 511 | if (flags_ptr.field_types_wip or flags_ptr.layout_wip) { | ||
| 512 | return true; | ||
| 513 | } | ||
| 514 | flags_ptr.layout_wip = true; | ||
| 515 | return false; | ||
| 516 | } | ||
| 517 | |||
| 518 | pub fn setFullyResolved(s: @This(), ip: *InternPool) bool { | ||
| 519 | if (s.layout == .Packed) return true; | ||
| 520 | const flags_ptr = s.flagsPtr(ip); | ||
| 521 | if (flags_ptr.fully_resolved) return true; | ||
| 522 | flags_ptr.fully_resolved = true; | ||
| 523 | return false; | ||
| 524 | } | ||
| 525 | |||
| 526 | pub fn clearFullyResolved(s: @This(), ip: *InternPool) void { | ||
| 527 | s.flagsPtr(ip).fully_resolved = false; | ||
| 528 | } | ||
| 529 | |||
| 530 | pub fn setRequiresComptime(s: @This(), ip: *InternPool) void { | ||
| 531 | assert(s.layout != .Packed); | ||
| 532 | const flags_ptr = s.flagsPtr(ip); | ||
| 533 | // Layout is resolved (and non-existent) in the case of a comptime-known struct. | ||
| 534 | flags_ptr.layout_resolved = true; | ||
| 535 | flags_ptr.requires_comptime = .yes; | ||
| 536 | } | ||
| 537 | |||
| 538 | /// The returned pointer expires with any addition to the `InternPool`. | ||
| 539 | /// Asserts the struct is not packed. | ||
| 540 | pub fn size(self: @This(), ip: *InternPool) *u32 { | ||
| 541 | assert(self.layout != .Packed); | ||
| 542 | const size_field_index = std.meta.fieldIndex(Tag.TypeStruct, "size").?; | ||
| 543 | return @ptrCast(&ip.extra.items[self.extra_index + size_field_index]); | ||
| 544 | } | ||
| 545 | |||
| 546 | /// The backing integer type of the packed struct. Whether zig chooses | ||
| 547 | /// this type or the user specifies it, it is stored here. This will be | ||
| 548 | /// set to `none` until the layout is resolved. | ||
| 549 | /// Asserts the struct is packed. | ||
| 550 | pub fn backingIntType(s: @This(), ip: *const InternPool) *Index { | ||
| 551 | assert(s.layout == .Packed); | ||
| 552 | const field_index = std.meta.fieldIndex(Tag.TypeStructPacked, "backing_int_ty").?; | ||
| 553 | return @ptrCast(&ip.extra.items[s.extra_index + field_index]); | ||
| 554 | } | ||
| 555 | |||
| 556 | /// Asserts the struct is not packed. | ||
| 557 | pub fn setZirIndex(s: @This(), ip: *InternPool, new_zir_index: Zir.Inst.Index) void { | ||
| 558 | assert(s.layout != .Packed); | ||
| 559 | const field_index = std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?; | ||
| 560 | ip.extra.items[s.extra_index + field_index] = new_zir_index; | ||
| 561 | } | ||
| 562 | |||
| 563 | pub fn haveFieldTypes(s: @This(), ip: *const InternPool) bool { | ||
| 564 | const types = s.field_types.get(ip); | ||
| 565 | return types.len == 0 or types[0] != .none; | ||
| 566 | } | ||
| 567 | |||
| 568 | pub fn haveLayout(s: @This(), ip: *InternPool) bool { | ||
| 569 | return switch (s.layout) { | ||
| 570 | .Packed => s.haveFieldTypes(ip), | ||
| 571 | .Auto, .Extern => s.flagsPtr(ip).layout_resolved, | ||
| 572 | }; | ||
| 573 | } | ||
| 574 | |||
| 575 | pub fn isTuple(s: @This(), ip: *InternPool) bool { | ||
| 576 | return s.layout != .Packed and s.flagsPtr(ip).is_tuple; | ||
| 577 | } | ||
| 578 | |||
| 579 | pub fn hasReorderedFields(s: @This(), ip: *InternPool) bool { | ||
| 580 | return s.layout == .Auto and s.flagsPtr(ip).has_reordered_fields; | ||
| 581 | } | ||
| 582 | |||
| 583 | pub const RuntimeOrderIterator = struct { | ||
| 584 | ip: *InternPool, | ||
| 585 | field_index: u32, | ||
| 586 | struct_type: InternPool.Key.StructType, | ||
| 587 | |||
| 588 | pub fn next(it: *@This()) ?u32 { | ||
| 589 | var i = it.field_index; | ||
| 590 | |||
| 591 | if (i >= it.struct_type.field_types.len) | ||
| 592 | return null; | ||
| 593 | |||
| 594 | if (it.struct_type.hasReorderedFields(it.ip)) { | ||
| 595 | it.field_index += 1; | ||
| 596 | return it.struct_type.runtime_order.get(it.ip)[i].toInt(); | ||
| 597 | } | ||
| 598 | |||
| 599 | while (it.struct_type.fieldIsComptime(it.ip, i)) { | ||
| 600 | i += 1; | ||
| 601 | if (i >= it.struct_type.field_types.len) | ||
| 602 | return null; | ||
| 603 | } | ||
| 604 | |||
| 605 | it.field_index = i + 1; | ||
| 606 | return i; | ||
| 607 | } | ||
| 608 | }; | ||
| 609 | |||
| 610 | /// Iterates over non-comptime fields in the order they are laid out in memory at runtime. | ||
| 611 | /// Asserts the struct is not packed. | ||
| 612 | pub fn iterateRuntimeOrder(s: @This(), ip: *InternPool) RuntimeOrderIterator { | ||
| 613 | assert(s.layout != .Packed); | ||
| 614 | return .{ | ||
| 615 | .ip = ip, | ||
| 616 | .field_index = 0, | ||
| 617 | .struct_type = s, | ||
| 618 | }; | ||
| 619 | } | ||
| 373 | }; | 620 | }; |
| 374 | 621 | ||
| 375 | pub const AnonStructType = struct { | 622 | pub const AnonStructType = struct { |
| ... | @@ -870,7 +1117,6 @@ pub const Key = union(enum) { | ... | @@ -870,7 +1117,6 @@ pub const Key = union(enum) { |
| 870 | .simple_type, | 1117 | .simple_type, |
| 871 | .simple_value, | 1118 | .simple_value, |
| 872 | .opt, | 1119 | .opt, |
| 873 | .struct_type, | ||
| 874 | .undef, | 1120 | .undef, |
| 875 | .err, | 1121 | .err, |
| 876 | .enum_literal, | 1122 | .enum_literal, |
| ... | @@ -893,6 +1139,7 @@ pub const Key = union(enum) { | ... | @@ -893,6 +1139,7 @@ pub const Key = union(enum) { |
| 893 | .enum_type, | 1139 | .enum_type, |
| 894 | .variable, | 1140 | .variable, |
| 895 | .union_type, | 1141 | .union_type, |
| 1142 | .struct_type, | ||
| 896 | => |x| Hash.hash(seed, asBytes(&x.decl)), | 1143 | => |x| Hash.hash(seed, asBytes(&x.decl)), |
| 897 | 1144 | ||
| 898 | .int => |int| { | 1145 | .int => |int| { |
| ... | @@ -969,11 +1216,11 @@ pub const Key = union(enum) { | ... | @@ -969,11 +1216,11 @@ pub const Key = union(enum) { |
| 969 | 1216 | ||
| 970 | if (child == .u8_type) { | 1217 | if (child == .u8_type) { |
| 971 | switch (aggregate.storage) { | 1218 | switch (aggregate.storage) { |
| 972 | .bytes => |bytes| for (bytes[0..@as(usize, @intCast(len))]) |byte| { | 1219 | .bytes => |bytes| for (bytes[0..@intCast(len)]) |byte| { |
| 973 | std.hash.autoHash(&hasher, KeyTag.int); | 1220 | std.hash.autoHash(&hasher, KeyTag.int); |
| 974 | std.hash.autoHash(&hasher, byte); | 1221 | std.hash.autoHash(&hasher, byte); |
| 975 | }, | 1222 | }, |
| 976 | .elems => |elems| for (elems[0..@as(usize, @intCast(len))]) |elem| { | 1223 | .elems => |elems| for (elems[0..@intCast(len)]) |elem| { |
| 977 | const elem_key = ip.indexToKey(elem); | 1224 | const elem_key = ip.indexToKey(elem); |
| 978 | std.hash.autoHash(&hasher, @as(KeyTag, elem_key)); | 1225 | std.hash.autoHash(&hasher, @as(KeyTag, elem_key)); |
| 979 | switch (elem_key) { | 1226 | switch (elem_key) { |
| ... | @@ -1123,10 +1370,6 @@ pub const Key = union(enum) { | ... | @@ -1123,10 +1370,6 @@ pub const Key = union(enum) { |
| 1123 | const b_info = b.opt; | 1370 | const b_info = b.opt; |
| 1124 | return std.meta.eql(a_info, b_info); | 1371 | return std.meta.eql(a_info, b_info); |
| 1125 | }, | 1372 | }, |
| 1126 | .struct_type => |a_info| { | ||
| 1127 | const b_info = b.struct_type; | ||
| 1128 | return std.meta.eql(a_info, b_info); | ||
| 1129 | }, | ||
| 1130 | .un => |a_info| { | 1373 | .un => |a_info| { |
| 1131 | const b_info = b.un; | 1374 | const b_info = b.un; |
| 1132 | return std.meta.eql(a_info, b_info); | 1375 | return std.meta.eql(a_info, b_info); |
| ... | @@ -1298,6 +1541,10 @@ pub const Key = union(enum) { | ... | @@ -1298,6 +1541,10 @@ pub const Key = union(enum) { |
| 1298 | const b_info = b.union_type; | 1541 | const b_info = b.union_type; |
| 1299 | return a_info.decl == b_info.decl; | 1542 | return a_info.decl == b_info.decl; |
| 1300 | }, | 1543 | }, |
| 1544 | .struct_type => |a_info| { | ||
| 1545 | const b_info = b.struct_type; | ||
| 1546 | return a_info.decl == b_info.decl; | ||
| 1547 | }, | ||
| 1301 | .aggregate => |a_info| { | 1548 | .aggregate => |a_info| { |
| 1302 | const b_info = b.aggregate; | 1549 | const b_info = b.aggregate; |
| 1303 | if (a_info.ty != b_info.ty) return false; | 1550 | if (a_info.ty != b_info.ty) return false; |
| ... | @@ -1433,6 +1680,8 @@ pub const Key = union(enum) { | ... | @@ -1433,6 +1680,8 @@ pub const Key = union(enum) { |
| 1433 | } | 1680 | } |
| 1434 | }; | 1681 | }; |
| 1435 | 1682 | ||
| 1683 | pub const RequiresComptime = enum(u2) { no, yes, unknown, wip }; | ||
| 1684 | |||
| 1436 | // Unlike `Tag.TypeUnion` which is an encoding, and `Key.UnionType` which is a | 1685 | // Unlike `Tag.TypeUnion` which is an encoding, and `Key.UnionType` which is a |
| 1437 | // minimal hashmap key, this type is a convenience type that contains info | 1686 | // minimal hashmap key, this type is a convenience type that contains info |
| 1438 | // needed by semantic analysis. | 1687 | // needed by semantic analysis. |
| ... | @@ -1474,8 +1723,6 @@ pub const UnionType = struct { | ... | @@ -1474,8 +1723,6 @@ pub const UnionType = struct { |
| 1474 | } | 1723 | } |
| 1475 | }; | 1724 | }; |
| 1476 | 1725 | ||
| 1477 | pub const RequiresComptime = enum(u2) { no, yes, unknown, wip }; | ||
| 1478 | |||
| 1479 | pub const Status = enum(u3) { | 1726 | pub const Status = enum(u3) { |
| 1480 | none, | 1727 | none, |
| 1481 | field_types_wip, | 1728 | field_types_wip, |
| ... | @@ -1814,9 +2061,11 @@ pub const Index = enum(u32) { | ... | @@ -1814,9 +2061,11 @@ pub const Index = enum(u32) { |
| 1814 | type_enum_nonexhaustive: DataIsExtraIndexOfEnumExplicit, | 2061 | type_enum_nonexhaustive: DataIsExtraIndexOfEnumExplicit, |
| 1815 | simple_type: struct { data: SimpleType }, | 2062 | simple_type: struct { data: SimpleType }, |
| 1816 | type_opaque: struct { data: *Key.OpaqueType }, | 2063 | type_opaque: struct { data: *Key.OpaqueType }, |
| 1817 | type_struct: struct { data: Module.Struct.OptionalIndex }, | 2064 | type_struct: struct { data: *Tag.TypeStruct }, |
| 1818 | type_struct_ns: struct { data: Module.Namespace.Index }, | 2065 | type_struct_ns: struct { data: Module.Namespace.Index }, |
| 1819 | type_struct_anon: DataIsExtraIndexOfTypeStructAnon, | 2066 | type_struct_anon: DataIsExtraIndexOfTypeStructAnon, |
| 2067 | type_struct_packed: struct { data: *Tag.TypeStructPacked }, | ||
| 2068 | type_struct_packed_inits: struct { data: *Tag.TypeStructPacked }, | ||
| 1820 | type_tuple_anon: DataIsExtraIndexOfTypeStructAnon, | 2069 | type_tuple_anon: DataIsExtraIndexOfTypeStructAnon, |
| 1821 | type_union: struct { data: *Tag.TypeUnion }, | 2070 | type_union: struct { data: *Tag.TypeUnion }, |
| 1822 | type_function: struct { | 2071 | type_function: struct { |
| ... | @@ -2241,17 +2490,22 @@ pub const Tag = enum(u8) { | ... | @@ -2241,17 +2490,22 @@ pub const Tag = enum(u8) { |
| 2241 | /// An opaque type. | 2490 | /// An opaque type. |
| 2242 | /// data is index of Key.OpaqueType in extra. | 2491 | /// data is index of Key.OpaqueType in extra. |
| 2243 | type_opaque, | 2492 | type_opaque, |
| 2244 | /// A struct type. | 2493 | /// A non-packed struct type. |
| 2245 | /// data is Module.Struct.OptionalIndex | 2494 | /// data is 0 or extra index of `TypeStruct`. |
| 2246 | /// The `none` tag is used to represent `@TypeOf(.{})`. | 2495 | /// data == 0 represents `@TypeOf(.{})`. |
| 2247 | type_struct, | 2496 | type_struct, |
| 2248 | /// A struct type that has only a namespace; no fields, and there is no | 2497 | /// A non-packed struct type that has only a namespace; no fields. |
| 2249 | /// Module.Struct object allocated for it. | ||
| 2250 | /// data is Module.Namespace.Index. | 2498 | /// data is Module.Namespace.Index. |
| 2251 | type_struct_ns, | 2499 | type_struct_ns, |
| 2252 | /// An AnonStructType which stores types, names, and values for fields. | 2500 | /// An AnonStructType which stores types, names, and values for fields. |
| 2253 | /// data is extra index of `TypeStructAnon`. | 2501 | /// data is extra index of `TypeStructAnon`. |
| 2254 | type_struct_anon, | 2502 | type_struct_anon, |
| 2503 | /// A packed struct, no fields have any init values. | ||
| 2504 | /// data is extra index of `TypeStructPacked`. | ||
| 2505 | type_struct_packed, | ||
| 2506 | /// A packed struct, one or more fields have init values. | ||
| 2507 | /// data is extra index of `TypeStructPacked`. | ||
| 2508 | type_struct_packed_inits, | ||
| 2255 | /// An AnonStructType which has only types and values for fields. | 2509 | /// An AnonStructType which has only types and values for fields. |
| 2256 | /// data is extra index of `TypeStructAnon`. | 2510 | /// data is extra index of `TypeStructAnon`. |
| 2257 | type_tuple_anon, | 2511 | type_tuple_anon, |
| ... | @@ -2461,9 +2715,10 @@ pub const Tag = enum(u8) { | ... | @@ -2461,9 +2715,10 @@ pub const Tag = enum(u8) { |
| 2461 | .type_enum_nonexhaustive => EnumExplicit, | 2715 | .type_enum_nonexhaustive => EnumExplicit, |
| 2462 | .simple_type => unreachable, | 2716 | .simple_type => unreachable, |
| 2463 | .type_opaque => OpaqueType, | 2717 | .type_opaque => OpaqueType, |
| 2464 | .type_struct => unreachable, | 2718 | .type_struct => TypeStruct, |
| 2465 | .type_struct_ns => unreachable, | 2719 | .type_struct_ns => unreachable, |
| 2466 | .type_struct_anon => TypeStructAnon, | 2720 | .type_struct_anon => TypeStructAnon, |
| 2721 | .type_struct_packed, .type_struct_packed_inits => TypeStructPacked, | ||
| 2467 | .type_tuple_anon => TypeStructAnon, | 2722 | .type_tuple_anon => TypeStructAnon, |
| 2468 | .type_union => TypeUnion, | 2723 | .type_union => TypeUnion, |
| 2469 | .type_function => TypeFunction, | 2724 | .type_function => TypeFunction, |
| ... | @@ -2634,11 +2889,90 @@ pub const Tag = enum(u8) { | ... | @@ -2634,11 +2889,90 @@ pub const Tag = enum(u8) { |
| 2634 | any_aligned_fields: bool, | 2889 | any_aligned_fields: bool, |
| 2635 | layout: std.builtin.Type.ContainerLayout, | 2890 | layout: std.builtin.Type.ContainerLayout, |
| 2636 | status: UnionType.Status, | 2891 | status: UnionType.Status, |
| 2637 | requires_comptime: UnionType.RequiresComptime, | 2892 | requires_comptime: RequiresComptime, |
| 2638 | assumed_runtime_bits: bool, | 2893 | assumed_runtime_bits: bool, |
| 2639 | _: u21 = 0, | 2894 | _: u21 = 0, |
| 2640 | }; | 2895 | }; |
| 2641 | }; | 2896 | }; |
| 2897 | |||
| 2898 | /// Trailing: | ||
| 2899 | /// 0. type: Index for each fields_len | ||
| 2900 | /// 1. name: NullTerminatedString for each fields_len | ||
| 2901 | /// 2. init: Index for each fields_len // if tag is type_struct_packed_inits | ||
| 2902 | pub const TypeStructPacked = struct { | ||
| 2903 | decl: Module.Decl.Index, | ||
| 2904 | zir_index: Zir.Inst.Index, | ||
| 2905 | fields_len: u32, | ||
| 2906 | namespace: Module.Namespace.OptionalIndex, | ||
| 2907 | backing_int_ty: Index, | ||
| 2908 | names_map: MapIndex, | ||
| 2909 | }; | ||
| 2910 | |||
| 2911 | /// At first I thought of storing the denormalized data externally, such as... | ||
| 2912 | /// | ||
| 2913 | /// * runtime field order | ||
| 2914 | /// * calculated field offsets | ||
| 2915 | /// * size and alignment of the struct | ||
| 2916 | /// | ||
| 2917 | /// ...since these can be computed based on the other data here. However, | ||
| 2918 | /// this data does need to be memoized, and therefore stored in memory | ||
| 2919 | /// while the compiler is running, in order to avoid O(N^2) logic in many | ||
| 2920 | /// places. Since the data can be stored compactly in the InternPool | ||
| 2921 | /// representation, it is better for memory usage to store denormalized data | ||
| 2922 | /// here, and potentially also better for performance as well. It's also simpler | ||
| 2923 | /// than coming up with some other scheme for the data. | ||
| 2924 | /// | ||
| 2925 | /// Trailing: | ||
| 2926 | /// 0. type: Index for each field in declared order | ||
| 2927 | /// 1. if not is_tuple: | ||
| 2928 | /// names_map: MapIndex, | ||
| 2929 | /// name: NullTerminatedString // for each field in declared order | ||
| 2930 | /// 2. if any_default_inits: | ||
| 2931 | /// init: Index // for each field in declared order | ||
| 2932 | /// 3. if has_namespace: | ||
| 2933 | /// namespace: Module.Namespace.Index | ||
| 2934 | /// 4. if any_aligned_fields: | ||
| 2935 | /// align: Alignment // for each field in declared order | ||
| 2936 | /// 5. if any_comptime_fields: | ||
| 2937 | /// field_is_comptime_bits: u32 // minimal number of u32s needed, LSB is field 0 | ||
| 2938 | /// 6. if has_reordered_fields: | ||
| 2939 | /// field_index: RuntimeOrder // for each field in runtime order | ||
| 2940 | /// 7. field_offset: u32 // for each field in declared order, undef until layout_resolved | ||
| 2941 | pub const TypeStruct = struct { | ||
| 2942 | decl: Module.Decl.Index, | ||
| 2943 | zir_index: Zir.Inst.Index, | ||
| 2944 | fields_len: u32, | ||
| 2945 | flags: Flags, | ||
| 2946 | size: u32, | ||
| 2947 | |||
| 2948 | pub const Flags = packed struct(u32) { | ||
| 2949 | has_runtime_order: bool, | ||
| 2950 | is_extern: bool, | ||
| 2951 | known_non_opv: bool, | ||
| 2952 | requires_comptime: RequiresComptime, | ||
| 2953 | is_tuple: bool, | ||
| 2954 | assumed_runtime_bits: bool, | ||
| 2955 | has_namespace: bool, | ||
| 2956 | has_reordered_fields: bool, | ||
| 2957 | any_comptime_fields: bool, | ||
| 2958 | any_default_inits: bool, | ||
| 2959 | any_aligned_fields: bool, | ||
| 2960 | /// `undefined` until the layout_resolved | ||
| 2961 | alignment: Alignment, | ||
| 2962 | /// Dependency loop detection when resolving field types. | ||
| 2963 | field_types_wip: bool, | ||
| 2964 | /// Dependency loop detection when resolving struct layout. | ||
| 2965 | layout_wip: bool, | ||
| 2966 | /// Determines whether `size`, `alignment`, runtime field order, and | ||
| 2967 | /// field offets are populated. | ||
| 2968 | layout_resolved: bool, | ||
| 2969 | // The types and all its fields have had their layout resolved. Even through pointer, | ||
| 2970 | // which `layout_resolved` does not ensure. | ||
| 2971 | fully_resolved: bool, | ||
| 2972 | |||
| 2973 | _: u10 = 0, | ||
| 2974 | }; | ||
| 2975 | }; | ||
| 2642 | }; | 2976 | }; |
| 2643 | 2977 | ||
| 2644 | /// State that is mutable during semantic analysis. This data is not used for | 2978 | /// State that is mutable during semantic analysis. This data is not used for |
| ... | @@ -2764,20 +3098,26 @@ pub const SimpleValue = enum(u32) { | ... | @@ -2764,20 +3098,26 @@ pub const SimpleValue = enum(u32) { |
| 2764 | 3098 | ||
| 2765 | /// Stored as a power-of-two, with one special value to indicate none. | 3099 | /// Stored as a power-of-two, with one special value to indicate none. |
| 2766 | pub const Alignment = enum(u6) { | 3100 | pub const Alignment = enum(u6) { |
| 3101 | @"1" = 0, | ||
| 3102 | @"2" = 1, | ||
| 3103 | @"4" = 2, | ||
| 3104 | @"8" = 3, | ||
| 3105 | @"16" = 4, | ||
| 3106 | @"32" = 5, | ||
| 2767 | none = std.math.maxInt(u6), | 3107 | none = std.math.maxInt(u6), |
| 2768 | _, | 3108 | _, |
| 2769 | 3109 | ||
| 2770 | pub fn toByteUnitsOptional(a: Alignment) ?u64 { | 3110 | pub fn toByteUnitsOptional(a: Alignment) ?u64 { |
| 2771 | return switch (a) { | 3111 | return switch (a) { |
| 2772 | .none => null, | 3112 | .none => null, |
| 2773 | _ => @as(u64, 1) << @intFromEnum(a), | 3113 | else => @as(u64, 1) << @intFromEnum(a), |
| 2774 | }; | 3114 | }; |
| 2775 | } | 3115 | } |
| 2776 | 3116 | ||
| 2777 | pub fn toByteUnits(a: Alignment, default: u64) u64 { | 3117 | pub fn toByteUnits(a: Alignment, default: u64) u64 { |
| 2778 | return switch (a) { | 3118 | return switch (a) { |
| 2779 | .none => default, | 3119 | .none => default, |
| 2780 | _ => @as(u64, 1) << @intFromEnum(a), | 3120 | else => @as(u64, 1) << @intFromEnum(a), |
| 2781 | }; | 3121 | }; |
| 2782 | } | 3122 | } |
| 2783 | 3123 | ||
| ... | @@ -2792,11 +3132,65 @@ pub const Alignment = enum(u6) { | ... | @@ -2792,11 +3132,65 @@ pub const Alignment = enum(u6) { |
| 2792 | return fromByteUnits(n); | 3132 | return fromByteUnits(n); |
| 2793 | } | 3133 | } |
| 2794 | 3134 | ||
| 3135 | pub fn toLog2Units(a: Alignment) u6 { | ||
| 3136 | assert(a != .none); | ||
| 3137 | return @intFromEnum(a); | ||
| 3138 | } | ||
| 3139 | |||
| 3140 | /// This is just a glorified `@enumFromInt` but using it can help | ||
| 3141 | /// document the intended conversion. | ||
| 3142 | /// The parameter uses a u32 for convenience at the callsite. | ||
| 3143 | pub fn fromLog2Units(a: u32) Alignment { | ||
| 3144 | assert(a != @intFromEnum(Alignment.none)); | ||
| 3145 | return @enumFromInt(a); | ||
| 3146 | } | ||
| 3147 | |||
| 2795 | pub fn order(lhs: Alignment, rhs: Alignment) std.math.Order { | 3148 | pub fn order(lhs: Alignment, rhs: Alignment) std.math.Order { |
| 2796 | assert(lhs != .none and rhs != .none); | 3149 | assert(lhs != .none); |
| 3150 | assert(rhs != .none); | ||
| 2797 | return std.math.order(@intFromEnum(lhs), @intFromEnum(rhs)); | 3151 | return std.math.order(@intFromEnum(lhs), @intFromEnum(rhs)); |
| 2798 | } | 3152 | } |
| 2799 | 3153 | ||
| 3154 | pub fn compare(lhs: Alignment, op: std.math.CompareOperator, rhs: Alignment) bool { | ||
| 3155 | assert(lhs != .none); | ||
| 3156 | assert(rhs != .none); | ||
| 3157 | return std.math.compare(@intFromEnum(lhs), op, @intFromEnum(rhs)); | ||
| 3158 | } | ||
| 3159 | |||
| 3160 | /// Treats `none` as zero. | ||
| 3161 | pub fn max(lhs: Alignment, rhs: Alignment) Alignment { | ||
| 3162 | if (lhs == .none) return rhs; | ||
| 3163 | if (rhs == .none) return lhs; | ||
| 3164 | return @enumFromInt(@max(@intFromEnum(lhs), @intFromEnum(rhs))); | ||
| 3165 | } | ||
| 3166 | |||
| 3167 | /// Treats `none` as maximum value. | ||
| 3168 | pub fn min(lhs: Alignment, rhs: Alignment) Alignment { | ||
| 3169 | if (lhs == .none) return rhs; | ||
| 3170 | if (rhs == .none) return lhs; | ||
| 3171 | return @enumFromInt(@min(@intFromEnum(lhs), @intFromEnum(rhs))); | ||
| 3172 | } | ||
| 3173 | |||
| 3174 | /// Align an address forwards to this alignment. | ||
| 3175 | pub fn forward(a: Alignment, addr: u64) u64 { | ||
| 3176 | assert(a != .none); | ||
| 3177 | const x = (@as(u64, 1) << @intFromEnum(a)) - 1; | ||
| 3178 | return (addr + x) & ~x; | ||
| 3179 | } | ||
| 3180 | |||
| 3181 | /// Align an address backwards to this alignment. | ||
| 3182 | pub fn backward(a: Alignment, addr: u64) u64 { | ||
| 3183 | assert(a != .none); | ||
| 3184 | const x = (@as(u64, 1) << @intFromEnum(a)) - 1; | ||
| 3185 | return addr & ~x; | ||
| 3186 | } | ||
| 3187 | |||
| 3188 | /// Check if an address is aligned to this amount. | ||
| 3189 | pub fn check(a: Alignment, addr: u64) bool { | ||
| 3190 | assert(a != .none); | ||
| 3191 | return @ctz(addr) >= @intFromEnum(a); | ||
| 3192 | } | ||
| 3193 | |||
| 2800 | /// An array of `Alignment` objects existing within the `extra` array. | 3194 | /// An array of `Alignment` objects existing within the `extra` array. |
| 2801 | /// This type exists to provide a struct with lifetime that is | 3195 | /// This type exists to provide a struct with lifetime that is |
| 2802 | /// not invalidated when items are added to the `InternPool`. | 3196 | /// not invalidated when items are added to the `InternPool`. |
| ... | @@ -2811,6 +3205,16 @@ pub const Alignment = enum(u6) { | ... | @@ -2811,6 +3205,16 @@ pub const Alignment = enum(u6) { |
| 2811 | return @ptrCast(bytes[0..slice.len]); | 3205 | return @ptrCast(bytes[0..slice.len]); |
| 2812 | } | 3206 | } |
| 2813 | }; | 3207 | }; |
| 3208 | |||
| 3209 | const LlvmBuilderAlignment = @import("codegen/llvm/Builder.zig").Alignment; | ||
| 3210 | |||
| 3211 | pub fn toLlvm(this: @This()) LlvmBuilderAlignment { | ||
| 3212 | return @enumFromInt(@intFromEnum(this)); | ||
| 3213 | } | ||
| 3214 | |||
| 3215 | pub fn fromLlvm(other: LlvmBuilderAlignment) @This() { | ||
| 3216 | return @enumFromInt(@intFromEnum(other)); | ||
| 3217 | } | ||
| 2814 | }; | 3218 | }; |
| 2815 | 3219 | ||
| 2816 | /// Used for non-sentineled arrays that have length fitting in u32, as well as | 3220 | /// Used for non-sentineled arrays that have length fitting in u32, as well as |
| ... | @@ -3065,9 +3469,6 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void { | ... | @@ -3065,9 +3469,6 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void { |
| 3065 | ip.limbs.deinit(gpa); | 3469 | ip.limbs.deinit(gpa); |
| 3066 | ip.string_bytes.deinit(gpa); | 3470 | ip.string_bytes.deinit(gpa); |
| 3067 | 3471 | ||
| 3068 | ip.structs_free_list.deinit(gpa); | ||
| 3069 | ip.allocated_structs.deinit(gpa); | ||
| 3070 | |||
| 3071 | ip.decls_free_list.deinit(gpa); | 3472 | ip.decls_free_list.deinit(gpa); |
| 3072 | ip.allocated_decls.deinit(gpa); | 3473 | ip.allocated_decls.deinit(gpa); |
| 3073 | 3474 | ||
| ... | @@ -3149,24 +3550,43 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { | ... | @@ -3149,24 +3550,43 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 3149 | }, | 3550 | }, |
| 3150 | 3551 | ||
| 3151 | .type_opaque => .{ .opaque_type = ip.extraData(Key.OpaqueType, data) }, | 3552 | .type_opaque => .{ .opaque_type = ip.extraData(Key.OpaqueType, data) }, |
| 3152 | .type_struct => { | 3553 | |
| 3153 | const struct_index: Module.Struct.OptionalIndex = @enumFromInt(data); | 3554 | .type_struct => .{ .struct_type = if (data == 0) .{ |
| 3154 | const namespace = if (struct_index.unwrap()) |i| | 3555 | .extra_index = 0, |
| 3155 | ip.structPtrConst(i).namespace.toOptional() | 3556 | .namespace = .none, |
| 3156 | else | 3557 | .decl = .none, |
| 3157 | .none; | 3558 | .zir_index = @as(u32, undefined), |
| 3158 | return .{ .struct_type = .{ | 3559 | .layout = .Auto, |
| 3159 | .index = struct_index, | 3560 | .field_names = .{ .start = 0, .len = 0 }, |
| 3160 | .namespace = namespace, | 3561 | .field_types = .{ .start = 0, .len = 0 }, |
| 3161 | } }; | 3562 | .field_inits = .{ .start = 0, .len = 0 }, |
| 3162 | }, | 3563 | .field_aligns = .{ .start = 0, .len = 0 }, |
| 3564 | .runtime_order = .{ .start = 0, .len = 0 }, | ||
| 3565 | .comptime_bits = .{ .start = 0, .len = 0 }, | ||
| 3566 | .offsets = .{ .start = 0, .len = 0 }, | ||
| 3567 | .names_map = undefined, | ||
| 3568 | } else extraStructType(ip, data) }, | ||
| 3569 | |||
| 3163 | .type_struct_ns => .{ .struct_type = .{ | 3570 | .type_struct_ns => .{ .struct_type = .{ |
| 3164 | .index = .none, | 3571 | .extra_index = 0, |
| 3165 | .namespace = @as(Module.Namespace.Index, @enumFromInt(data)).toOptional(), | 3572 | .namespace = @as(Module.Namespace.Index, @enumFromInt(data)).toOptional(), |
| 3573 | .decl = .none, | ||
| 3574 | .zir_index = @as(u32, undefined), | ||
| 3575 | .layout = .Auto, | ||
| 3576 | .field_names = .{ .start = 0, .len = 0 }, | ||
| 3577 | .field_types = .{ .start = 0, .len = 0 }, | ||
| 3578 | .field_inits = .{ .start = 0, .len = 0 }, | ||
| 3579 | .field_aligns = .{ .start = 0, .len = 0 }, | ||
| 3580 | .runtime_order = .{ .start = 0, .len = 0 }, | ||
| 3581 | .comptime_bits = .{ .start = 0, .len = 0 }, | ||
| 3582 | .offsets = .{ .start = 0, .len = 0 }, | ||
| 3583 | .names_map = undefined, | ||
| 3166 | } }, | 3584 | } }, |
| 3167 | 3585 | ||
| 3168 | .type_struct_anon => .{ .anon_struct_type = extraTypeStructAnon(ip, data) }, | 3586 | .type_struct_anon => .{ .anon_struct_type = extraTypeStructAnon(ip, data) }, |
| 3169 | .type_tuple_anon => .{ .anon_struct_type = extraTypeTupleAnon(ip, data) }, | 3587 | .type_tuple_anon => .{ .anon_struct_type = extraTypeTupleAnon(ip, data) }, |
| 3588 | .type_struct_packed => .{ .struct_type = extraPackedStructType(ip, data, false) }, | ||
| 3589 | .type_struct_packed_inits => .{ .struct_type = extraPackedStructType(ip, data, true) }, | ||
| 3170 | .type_union => .{ .union_type = extraUnionType(ip, data) }, | 3590 | .type_union => .{ .union_type = extraUnionType(ip, data) }, |
| 3171 | 3591 | ||
| 3172 | .type_enum_auto => { | 3592 | .type_enum_auto => { |
| ... | @@ -3476,10 +3896,15 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { | ... | @@ -3476,10 +3896,15 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 3476 | const values = ip.extra.items[type_struct_anon.end + fields_len ..][0..fields_len]; | 3896 | const values = ip.extra.items[type_struct_anon.end + fields_len ..][0..fields_len]; |
| 3477 | return .{ .aggregate = .{ | 3897 | return .{ .aggregate = .{ |
| 3478 | .ty = ty, | 3898 | .ty = ty, |
| 3479 | .storage = .{ .elems = @as([]const Index, @ptrCast(values)) }, | 3899 | .storage = .{ .elems = @ptrCast(values) }, |
| 3480 | } }; | 3900 | } }; |
| 3481 | }, | 3901 | }, |
| 3482 | 3902 | ||
| 3903 | .type_struct_packed, .type_struct_packed_inits => { | ||
| 3904 | // a packed struct has a 0-bit backing type | ||
| 3905 | @panic("TODO"); | ||
| 3906 | }, | ||
| 3907 | |||
| 3483 | .type_enum_auto, | 3908 | .type_enum_auto, |
| 3484 | .type_enum_explicit, | 3909 | .type_enum_explicit, |
| 3485 | .type_union, | 3910 | .type_union, |
| ... | @@ -3490,7 +3915,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { | ... | @@ -3490,7 +3915,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 3490 | }, | 3915 | }, |
| 3491 | .bytes => { | 3916 | .bytes => { |
| 3492 | const extra = ip.extraData(Bytes, data); | 3917 | const extra = ip.extraData(Bytes, data); |
| 3493 | const len = @as(u32, @intCast(ip.aggregateTypeLenIncludingSentinel(extra.ty))); | 3918 | const len: u32 = @intCast(ip.aggregateTypeLenIncludingSentinel(extra.ty)); |
| 3494 | return .{ .aggregate = .{ | 3919 | return .{ .aggregate = .{ |
| 3495 | .ty = extra.ty, | 3920 | .ty = extra.ty, |
| 3496 | .storage = .{ .bytes = ip.string_bytes.items[@intFromEnum(extra.bytes)..][0..len] }, | 3921 | .storage = .{ .bytes = ip.string_bytes.items[@intFromEnum(extra.bytes)..][0..len] }, |
| ... | @@ -3498,8 +3923,8 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { | ... | @@ -3498,8 +3923,8 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 3498 | }, | 3923 | }, |
| 3499 | .aggregate => { | 3924 | .aggregate => { |
| 3500 | const extra = ip.extraDataTrail(Tag.Aggregate, data); | 3925 | const extra = ip.extraDataTrail(Tag.Aggregate, data); |
| 3501 | const len = @as(u32, @intCast(ip.aggregateTypeLenIncludingSentinel(extra.data.ty))); | 3926 | const len: u32 = @intCast(ip.aggregateTypeLenIncludingSentinel(extra.data.ty)); |
| 3502 | const fields = @as([]const Index, @ptrCast(ip.extra.items[extra.end..][0..len])); | 3927 | const fields: []const Index = @ptrCast(ip.extra.items[extra.end..][0..len]); |
| 3503 | return .{ .aggregate = .{ | 3928 | return .{ .aggregate = .{ |
| 3504 | .ty = extra.data.ty, | 3929 | .ty = extra.data.ty, |
| 3505 | .storage = .{ .elems = fields }, | 3930 | .storage = .{ .elems = fields }, |
| ... | @@ -3603,6 +4028,44 @@ fn extraTypeTupleAnon(ip: *const InternPool, extra_index: u32) Key.AnonStructTyp | ... | @@ -3603,6 +4028,44 @@ fn extraTypeTupleAnon(ip: *const InternPool, extra_index: u32) Key.AnonStructTyp |
| 3603 | }; | 4028 | }; |
| 3604 | } | 4029 | } |
| 3605 | 4030 | ||
| 4031 | fn extraStructType(ip: *const InternPool, extra_index: u32) Key.StructType { | ||
| 4032 | _ = ip; | ||
| 4033 | _ = extra_index; | ||
| 4034 | @panic("TODO"); | ||
| 4035 | } | ||
| 4036 | |||
| 4037 | fn extraPackedStructType(ip: *const InternPool, extra_index: u32, inits: bool) Key.StructType { | ||
| 4038 | const type_struct_packed = ip.extraDataTrail(Tag.TypeStructPacked, extra_index); | ||
| 4039 | const fields_len = type_struct_packed.data.fields_len; | ||
| 4040 | return .{ | ||
| 4041 | .extra_index = extra_index, | ||
| 4042 | .decl = type_struct_packed.data.decl.toOptional(), | ||
| 4043 | .namespace = type_struct_packed.data.namespace, | ||
| 4044 | .zir_index = type_struct_packed.data.zir_index, | ||
| 4045 | .layout = .Packed, | ||
| 4046 | .field_types = .{ | ||
| 4047 | .start = type_struct_packed.end, | ||
| 4048 | .len = fields_len, | ||
| 4049 | }, | ||
| 4050 | .field_names = .{ | ||
| 4051 | .start = type_struct_packed.end + fields_len, | ||
| 4052 | .len = fields_len, | ||
| 4053 | }, | ||
| 4054 | .field_inits = if (inits) .{ | ||
| 4055 | .start = type_struct_packed.end + fields_len + fields_len, | ||
| 4056 | .len = fields_len, | ||
| 4057 | } else .{ | ||
| 4058 | .start = 0, | ||
| 4059 | .len = 0, | ||
| 4060 | }, | ||
| 4061 | .field_aligns = .{ .start = 0, .len = 0 }, | ||
| 4062 | .runtime_order = .{ .start = 0, .len = 0 }, | ||
| 4063 | .comptime_bits = .{ .start = 0, .len = 0 }, | ||
| 4064 | .offsets = .{ .start = 0, .len = 0 }, | ||
| 4065 | .names_map = type_struct_packed.data.names_map, | ||
| 4066 | }; | ||
| 4067 | } | ||
| 4068 | |||
| 3606 | fn extraFuncType(ip: *const InternPool, extra_index: u32) Key.FuncType { | 4069 | fn extraFuncType(ip: *const InternPool, extra_index: u32) Key.FuncType { |
| 3607 | const type_function = ip.extraDataTrail(Tag.TypeFunction, extra_index); | 4070 | const type_function = ip.extraDataTrail(Tag.TypeFunction, extra_index); |
| 3608 | var index: usize = type_function.end; | 4071 | var index: usize = type_function.end; |
| ... | @@ -3831,8 +4294,9 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { | ... | @@ -3831,8 +4294,9 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 3831 | .error_set_type => |error_set_type| { | 4294 | .error_set_type => |error_set_type| { |
| 3832 | assert(error_set_type.names_map == .none); | 4295 | assert(error_set_type.names_map == .none); |
| 3833 | assert(std.sort.isSorted(NullTerminatedString, error_set_type.names.get(ip), {}, NullTerminatedString.indexLessThan)); | 4296 | assert(std.sort.isSorted(NullTerminatedString, error_set_type.names.get(ip), {}, NullTerminatedString.indexLessThan)); |
| 3834 | const names_map = try ip.addMap(gpa); | 4297 | const names = error_set_type.names.get(ip); |
| 3835 | try addStringsToMap(ip, gpa, names_map, error_set_type.names.get(ip)); | 4298 | const names_map = try ip.addMap(gpa, names.len); |
| 4299 | addStringsToMap(ip, names_map, names); | ||
| 3836 | const names_len = error_set_type.names.len; | 4300 | const names_len = error_set_type.names.len; |
| 3837 | try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.ErrorSet).Struct.fields.len + names_len); | 4301 | try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.ErrorSet).Struct.fields.len + names_len); |
| 3838 | ip.items.appendAssumeCapacity(.{ | 4302 | ip.items.appendAssumeCapacity(.{ |
| ... | @@ -3877,21 +4341,8 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { | ... | @@ -3877,21 +4341,8 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 3877 | }); | 4341 | }); |
| 3878 | }, | 4342 | }, |
| 3879 | 4343 | ||
| 3880 | .struct_type => |struct_type| { | 4344 | .struct_type => unreachable, // use getStructType() instead |
| 3881 | ip.items.appendAssumeCapacity(if (struct_type.index.unwrap()) |i| .{ | ||
| 3882 | .tag = .type_struct, | ||
| 3883 | .data = @intFromEnum(i), | ||
| 3884 | } else if (struct_type.namespace.unwrap()) |i| .{ | ||
| 3885 | .tag = .type_struct_ns, | ||
| 3886 | .data = @intFromEnum(i), | ||
| 3887 | } else .{ | ||
| 3888 | .tag = .type_struct, | ||
| 3889 | .data = @intFromEnum(Module.Struct.OptionalIndex.none), | ||
| 3890 | }); | ||
| 3891 | }, | ||
| 3892 | |||
| 3893 | .anon_struct_type => unreachable, // use getAnonStructType() instead | 4345 | .anon_struct_type => unreachable, // use getAnonStructType() instead |
| 3894 | |||
| 3895 | .union_type => unreachable, // use getUnionType() instead | 4346 | .union_type => unreachable, // use getUnionType() instead |
| 3896 | 4347 | ||
| 3897 | .opaque_type => |opaque_type| { | 4348 | .opaque_type => |opaque_type| { |
| ... | @@ -3994,7 +4445,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { | ... | @@ -3994,7 +4445,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 3994 | }, | 4445 | }, |
| 3995 | .struct_type => |struct_type| { | 4446 | .struct_type => |struct_type| { |
| 3996 | assert(ptr.addr == .field); | 4447 | assert(ptr.addr == .field); |
| 3997 | assert(base_index.index < ip.structPtrUnwrapConst(struct_type.index).?.fields.count()); | 4448 | assert(base_index.index < struct_type.field_types.len); |
| 3998 | }, | 4449 | }, |
| 3999 | .union_type => |union_key| { | 4450 | .union_type => |union_key| { |
| 4000 | const union_type = ip.loadUnionType(union_key); | 4451 | const union_type = ip.loadUnionType(union_key); |
| ... | @@ -4388,12 +4839,9 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { | ... | @@ -4388,12 +4839,9 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 4388 | assert(ip.typeOf(elem) == child); | 4839 | assert(ip.typeOf(elem) == child); |
| 4389 | } | 4840 | } |
| 4390 | }, | 4841 | }, |
| 4391 | .struct_type => |struct_type| { | 4842 | .struct_type => |t| { |
| 4392 | for ( | 4843 | for (aggregate.storage.values(), t.field_types.get(ip)) |elem, field_ty| { |
| 4393 | aggregate.storage.values(), | 4844 | assert(ip.typeOf(elem) == field_ty); |
| 4394 | ip.structPtrUnwrapConst(struct_type.index).?.fields.values(), | ||
| 4395 | ) |elem, field| { | ||
| 4396 | assert(ip.typeOf(elem) == field.ty.toIntern()); | ||
| 4397 | } | 4845 | } |
| 4398 | }, | 4846 | }, |
| 4399 | .anon_struct_type => |anon_struct_type| { | 4847 | .anon_struct_type => |anon_struct_type| { |
| ... | @@ -4635,6 +5083,28 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, ini: UnionTypeInit) Allocat | ... | @@ -4635,6 +5083,28 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, ini: UnionTypeInit) Allocat |
| 4635 | return @enumFromInt(ip.items.len - 1); | 5083 | return @enumFromInt(ip.items.len - 1); |
| 4636 | } | 5084 | } |
| 4637 | 5085 | ||
| 5086 | pub const StructTypeInit = struct { | ||
| 5087 | decl: Module.Decl.Index, | ||
| 5088 | namespace: Module.Namespace.OptionalIndex, | ||
| 5089 | layout: std.builtin.Type.ContainerLayout, | ||
| 5090 | zir_index: Zir.Inst.Index, | ||
| 5091 | fields_len: u32, | ||
| 5092 | known_non_opv: bool, | ||
| 5093 | requires_comptime: RequiresComptime, | ||
| 5094 | is_tuple: bool, | ||
| 5095 | }; | ||
| 5096 | |||
| 5097 | pub fn getStructType( | ||
| 5098 | ip: *InternPool, | ||
| 5099 | gpa: Allocator, | ||
| 5100 | ini: StructTypeInit, | ||
| 5101 | ) Allocator.Error!Index { | ||
| 5102 | _ = ip; | ||
| 5103 | _ = gpa; | ||
| 5104 | _ = ini; | ||
| 5105 | @panic("TODO"); | ||
| 5106 | } | ||
| 5107 | |||
| 4638 | pub const AnonStructTypeInit = struct { | 5108 | pub const AnonStructTypeInit = struct { |
| 4639 | types: []const Index, | 5109 | types: []const Index, |
| 4640 | /// This may be empty, indicating this is a tuple. | 5110 | /// This may be empty, indicating this is a tuple. |
| ... | @@ -4997,10 +5467,10 @@ pub fn getErrorSetType( | ... | @@ -4997,10 +5467,10 @@ pub fn getErrorSetType( |
| 4997 | }); | 5467 | }); |
| 4998 | errdefer ip.items.len -= 1; | 5468 | errdefer ip.items.len -= 1; |
| 4999 | 5469 | ||
| 5000 | const names_map = try ip.addMap(gpa); | 5470 | const names_map = try ip.addMap(gpa, names.len); |
| 5001 | errdefer _ = ip.maps.pop(); | 5471 | errdefer _ = ip.maps.pop(); |
| 5002 | 5472 | ||
| 5003 | try addStringsToMap(ip, gpa, names_map, names); | 5473 | addStringsToMap(ip, names_map, names); |
| 5004 | 5474 | ||
| 5005 | return @enumFromInt(ip.items.len - 1); | 5475 | return @enumFromInt(ip.items.len - 1); |
| 5006 | } | 5476 | } |
| ... | @@ -5299,19 +5769,9 @@ pub const IncompleteEnumType = struct { | ... | @@ -5299,19 +5769,9 @@ pub const IncompleteEnumType = struct { |
| 5299 | pub fn addFieldName( | 5769 | pub fn addFieldName( |
| 5300 | self: @This(), | 5770 | self: @This(), |
| 5301 | ip: *InternPool, | 5771 | ip: *InternPool, |
| 5302 | gpa: Allocator, | ||
| 5303 | name: NullTerminatedString, | 5772 | name: NullTerminatedString, |
| 5304 | ) Allocator.Error!?u32 { | 5773 | ) ?u32 { |
| 5305 | const map = &ip.maps.items[@intFromEnum(self.names_map)]; | 5774 | return ip.addFieldName(self.names_map, self.names_start, name); |
| 5306 | const field_index = map.count(); | ||
| 5307 | const strings = ip.extra.items[self.names_start..][0..field_index]; | ||
| 5308 | const adapter: NullTerminatedString.Adapter = .{ | ||
| 5309 | .strings = @as([]const NullTerminatedString, @ptrCast(strings)), | ||
| 5310 | }; | ||
| 5311 | const gop = try map.getOrPutAdapted(gpa, name, adapter); | ||
| 5312 | if (gop.found_existing) return @intCast(gop.index); | ||
| 5313 | ip.extra.items[self.names_start + field_index] = @intFromEnum(name); | ||
| 5314 | return null; | ||
| 5315 | } | 5775 | } |
| 5316 | 5776 | ||
| 5317 | /// Returns the already-existing field with the same value, if any. | 5777 | /// Returns the already-existing field with the same value, if any. |
| ... | @@ -5319,17 +5779,14 @@ pub const IncompleteEnumType = struct { | ... | @@ -5319,17 +5779,14 @@ pub const IncompleteEnumType = struct { |
| 5319 | pub fn addFieldValue( | 5779 | pub fn addFieldValue( |
| 5320 | self: @This(), | 5780 | self: @This(), |
| 5321 | ip: *InternPool, | 5781 | ip: *InternPool, |
| 5322 | gpa: Allocator, | ||
| 5323 | value: Index, | 5782 | value: Index, |
| 5324 | ) Allocator.Error!?u32 { | 5783 | ) ?u32 { |
| 5325 | assert(ip.typeOf(value) == @as(Index, @enumFromInt(ip.extra.items[self.tag_ty_index]))); | 5784 | assert(ip.typeOf(value) == @as(Index, @enumFromInt(ip.extra.items[self.tag_ty_index]))); |
| 5326 | const map = &ip.maps.items[@intFromEnum(self.values_map.unwrap().?)]; | 5785 | const map = &ip.maps.items[@intFromEnum(self.values_map.unwrap().?)]; |
| 5327 | const field_index = map.count(); | 5786 | const field_index = map.count(); |
| 5328 | const indexes = ip.extra.items[self.values_start..][0..field_index]; | 5787 | const indexes = ip.extra.items[self.values_start..][0..field_index]; |
| 5329 | const adapter: Index.Adapter = .{ | 5788 | const adapter: Index.Adapter = .{ .indexes = @ptrCast(indexes) }; |
| 5330 | .indexes = @as([]const Index, @ptrCast(indexes)), | 5789 | const gop = map.getOrPutAssumeCapacityAdapted(value, adapter); |
| 5331 | }; | ||
| 5332 | const gop = try map.getOrPutAdapted(gpa, value, adapter); | ||
| 5333 | if (gop.found_existing) return @intCast(gop.index); | 5790 | if (gop.found_existing) return @intCast(gop.index); |
| 5334 | ip.extra.items[self.values_start + field_index] = @intFromEnum(value); | 5791 | ip.extra.items[self.values_start + field_index] = @intFromEnum(value); |
| 5335 | return null; | 5792 | return null; |
| ... | @@ -5370,7 +5827,7 @@ fn getIncompleteEnumAuto( | ... | @@ -5370,7 +5827,7 @@ fn getIncompleteEnumAuto( |
| 5370 | const gop = try ip.map.getOrPutAdapted(gpa, enum_type.toKey(), adapter); | 5827 | const gop = try ip.map.getOrPutAdapted(gpa, enum_type.toKey(), adapter); |
| 5371 | assert(!gop.found_existing); | 5828 | assert(!gop.found_existing); |
| 5372 | 5829 | ||
| 5373 | const names_map = try ip.addMap(gpa); | 5830 | const names_map = try ip.addMap(gpa, enum_type.fields_len); |
| 5374 | 5831 | ||
| 5375 | const extra_fields_len: u32 = @typeInfo(EnumAuto).Struct.fields.len; | 5832 | const extra_fields_len: u32 = @typeInfo(EnumAuto).Struct.fields.len; |
| 5376 | try ip.extra.ensureUnusedCapacity(gpa, extra_fields_len + enum_type.fields_len); | 5833 | try ip.extra.ensureUnusedCapacity(gpa, extra_fields_len + enum_type.fields_len); |
| ... | @@ -5390,7 +5847,7 @@ fn getIncompleteEnumAuto( | ... | @@ -5390,7 +5847,7 @@ fn getIncompleteEnumAuto( |
| 5390 | }); | 5847 | }); |
| 5391 | ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), enum_type.fields_len); | 5848 | ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), enum_type.fields_len); |
| 5392 | return .{ | 5849 | return .{ |
| 5393 | .index = @as(Index, @enumFromInt(ip.items.len - 1)), | 5850 | .index = @enumFromInt(ip.items.len - 1), |
| 5394 | .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?, | 5851 | .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?, |
| 5395 | .names_map = names_map, | 5852 | .names_map = names_map, |
| 5396 | .names_start = extra_index + extra_fields_len, | 5853 | .names_start = extra_index + extra_fields_len, |
| ... | @@ -5412,9 +5869,9 @@ fn getIncompleteEnumExplicit( | ... | @@ -5412,9 +5869,9 @@ fn getIncompleteEnumExplicit( |
| 5412 | const gop = try ip.map.getOrPutAdapted(gpa, enum_type.toKey(), adapter); | 5869 | const gop = try ip.map.getOrPutAdapted(gpa, enum_type.toKey(), adapter); |
| 5413 | assert(!gop.found_existing); | 5870 | assert(!gop.found_existing); |
| 5414 | 5871 | ||
| 5415 | const names_map = try ip.addMap(gpa); | 5872 | const names_map = try ip.addMap(gpa, enum_type.fields_len); |
| 5416 | const values_map: OptionalMapIndex = if (!enum_type.has_values) .none else m: { | 5873 | const values_map: OptionalMapIndex = if (!enum_type.has_values) .none else m: { |
| 5417 | const values_map = try ip.addMap(gpa); | 5874 | const values_map = try ip.addMap(gpa, enum_type.fields_len); |
| 5418 | break :m values_map.toOptional(); | 5875 | break :m values_map.toOptional(); |
| 5419 | }; | 5876 | }; |
| 5420 | 5877 | ||
| ... | @@ -5441,7 +5898,7 @@ fn getIncompleteEnumExplicit( | ... | @@ -5441,7 +5898,7 @@ fn getIncompleteEnumExplicit( |
| 5441 | // This is both fields and values (if present). | 5898 | // This is both fields and values (if present). |
| 5442 | ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), reserved_len); | 5899 | ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), reserved_len); |
| 5443 | return .{ | 5900 | return .{ |
| 5444 | .index = @as(Index, @enumFromInt(ip.items.len - 1)), | 5901 | .index = @enumFromInt(ip.items.len - 1), |
| 5445 | .tag_ty_index = extra_index + std.meta.fieldIndex(EnumExplicit, "int_tag_type").?, | 5902 | .tag_ty_index = extra_index + std.meta.fieldIndex(EnumExplicit, "int_tag_type").?, |
| 5446 | .names_map = names_map, | 5903 | .names_map = names_map, |
| 5447 | .names_start = extra_index + extra_fields_len, | 5904 | .names_start = extra_index + extra_fields_len, |
| ... | @@ -5484,8 +5941,8 @@ pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Erro | ... | @@ -5484,8 +5941,8 @@ pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Erro |
| 5484 | 5941 | ||
| 5485 | switch (ini.tag_mode) { | 5942 | switch (ini.tag_mode) { |
| 5486 | .auto => { | 5943 | .auto => { |
| 5487 | const names_map = try ip.addMap(gpa); | 5944 | const names_map = try ip.addMap(gpa, ini.names.len); |
| 5488 | try addStringsToMap(ip, gpa, names_map, ini.names); | 5945 | addStringsToMap(ip, names_map, ini.names); |
| 5489 | 5946 | ||
| 5490 | const fields_len: u32 = @intCast(ini.names.len); | 5947 | const fields_len: u32 = @intCast(ini.names.len); |
| 5491 | try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumAuto).Struct.fields.len + | 5948 | try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumAuto).Struct.fields.len + |
| ... | @@ -5514,12 +5971,12 @@ pub fn finishGetEnum( | ... | @@ -5514,12 +5971,12 @@ pub fn finishGetEnum( |
| 5514 | ini: GetEnumInit, | 5971 | ini: GetEnumInit, |
| 5515 | tag: Tag, | 5972 | tag: Tag, |
| 5516 | ) Allocator.Error!Index { | 5973 | ) Allocator.Error!Index { |
| 5517 | const names_map = try ip.addMap(gpa); | 5974 | const names_map = try ip.addMap(gpa, ini.names.len); |
| 5518 | try addStringsToMap(ip, gpa, names_map, ini.names); | 5975 | addStringsToMap(ip, names_map, ini.names); |
| 5519 | 5976 | ||
| 5520 | const values_map: OptionalMapIndex = if (ini.values.len == 0) .none else m: { | 5977 | const values_map: OptionalMapIndex = if (ini.values.len == 0) .none else m: { |
| 5521 | const values_map = try ip.addMap(gpa); | 5978 | const values_map = try ip.addMap(gpa, ini.values.len); |
| 5522 | try addIndexesToMap(ip, gpa, values_map, ini.values); | 5979 | addIndexesToMap(ip, values_map, ini.values); |
| 5523 | break :m values_map.toOptional(); | 5980 | break :m values_map.toOptional(); |
| 5524 | }; | 5981 | }; |
| 5525 | const fields_len: u32 = @intCast(ini.names.len); | 5982 | const fields_len: u32 = @intCast(ini.names.len); |
| ... | @@ -5553,35 +6010,35 @@ pub fn getAssumeExists(ip: *const InternPool, key: Key) Index { | ... | @@ -5553,35 +6010,35 @@ pub fn getAssumeExists(ip: *const InternPool, key: Key) Index { |
| 5553 | 6010 | ||
| 5554 | fn addStringsToMap( | 6011 | fn addStringsToMap( |
| 5555 | ip: *InternPool, | 6012 | ip: *InternPool, |
| 5556 | gpa: Allocator, | ||
| 5557 | map_index: MapIndex, | 6013 | map_index: MapIndex, |
| 5558 | strings: []const NullTerminatedString, | 6014 | strings: []const NullTerminatedString, |
| 5559 | ) Allocator.Error!void { | 6015 | ) void { |
| 5560 | const map = &ip.maps.items[@intFromEnum(map_index)]; | 6016 | const map = &ip.maps.items[@intFromEnum(map_index)]; |
| 5561 | const adapter: NullTerminatedString.Adapter = .{ .strings = strings }; | 6017 | const adapter: NullTerminatedString.Adapter = .{ .strings = strings }; |
| 5562 | for (strings) |string| { | 6018 | for (strings) |string| { |
| 5563 | const gop = try map.getOrPutAdapted(gpa, string, adapter); | 6019 | const gop = map.getOrPutAssumeCapacityAdapted(string, adapter); |
| 5564 | assert(!gop.found_existing); | 6020 | assert(!gop.found_existing); |
| 5565 | } | 6021 | } |
| 5566 | } | 6022 | } |
| 5567 | 6023 | ||
| 5568 | fn addIndexesToMap( | 6024 | fn addIndexesToMap( |
| 5569 | ip: *InternPool, | 6025 | ip: *InternPool, |
| 5570 | gpa: Allocator, | ||
| 5571 | map_index: MapIndex, | 6026 | map_index: MapIndex, |
| 5572 | indexes: []const Index, | 6027 | indexes: []const Index, |
| 5573 | ) Allocator.Error!void { | 6028 | ) void { |
| 5574 | const map = &ip.maps.items[@intFromEnum(map_index)]; | 6029 | const map = &ip.maps.items[@intFromEnum(map_index)]; |
| 5575 | const adapter: Index.Adapter = .{ .indexes = indexes }; | 6030 | const adapter: Index.Adapter = .{ .indexes = indexes }; |
| 5576 | for (indexes) |index| { | 6031 | for (indexes) |index| { |
| 5577 | const gop = try map.getOrPutAdapted(gpa, index, adapter); | 6032 | const gop = map.getOrPutAssumeCapacityAdapted(index, adapter); |
| 5578 | assert(!gop.found_existing); | 6033 | assert(!gop.found_existing); |
| 5579 | } | 6034 | } |
| 5580 | } | 6035 | } |
| 5581 | 6036 | ||
| 5582 | fn addMap(ip: *InternPool, gpa: Allocator) Allocator.Error!MapIndex { | 6037 | fn addMap(ip: *InternPool, gpa: Allocator, cap: usize) Allocator.Error!MapIndex { |
| 5583 | const ptr = try ip.maps.addOne(gpa); | 6038 | const ptr = try ip.maps.addOne(gpa); |
| 6039 | errdefer _ = ip.maps.pop(); | ||
| 5584 | ptr.* = .{}; | 6040 | ptr.* = .{}; |
| 6041 | try ptr.ensureTotalCapacity(gpa, cap); | ||
| 5585 | return @enumFromInt(ip.maps.items.len - 1); | 6042 | return @enumFromInt(ip.maps.items.len - 1); |
| 5586 | } | 6043 | } |
| 5587 | 6044 | ||
| ... | @@ -5632,8 +6089,9 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 { | ... | @@ -5632,8 +6089,9 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 { |
| 5632 | Tag.TypePointer.Flags, | 6089 | Tag.TypePointer.Flags, |
| 5633 | Tag.TypeFunction.Flags, | 6090 | Tag.TypeFunction.Flags, |
| 5634 | Tag.TypePointer.PackedOffset, | 6091 | Tag.TypePointer.PackedOffset, |
| 5635 | Tag.Variable.Flags, | ||
| 5636 | Tag.TypeUnion.Flags, | 6092 | Tag.TypeUnion.Flags, |
| 6093 | Tag.TypeStruct.Flags, | ||
| 6094 | Tag.Variable.Flags, | ||
| 5637 | => @bitCast(@field(extra, field.name)), | 6095 | => @bitCast(@field(extra, field.name)), |
| 5638 | 6096 | ||
| 5639 | else => @compileError("bad field type: " ++ @typeName(field.type)), | 6097 | else => @compileError("bad field type: " ++ @typeName(field.type)), |
| ... | @@ -5705,6 +6163,7 @@ fn extraDataTrail(ip: *const InternPool, comptime T: type, index: usize) struct | ... | @@ -5705,6 +6163,7 @@ fn extraDataTrail(ip: *const InternPool, comptime T: type, index: usize) struct |
| 5705 | Tag.TypeFunction.Flags, | 6163 | Tag.TypeFunction.Flags, |
| 5706 | Tag.TypePointer.PackedOffset, | 6164 | Tag.TypePointer.PackedOffset, |
| 5707 | Tag.TypeUnion.Flags, | 6165 | Tag.TypeUnion.Flags, |
| 6166 | Tag.TypeStruct.Flags, | ||
| 5708 | Tag.Variable.Flags, | 6167 | Tag.Variable.Flags, |
| 5709 | FuncAnalysis, | 6168 | FuncAnalysis, |
| 5710 | => @bitCast(int32), | 6169 | => @bitCast(int32), |
| ... | @@ -6093,8 +6552,7 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al | ... | @@ -6093,8 +6552,7 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al |
| 6093 | const new_elem_ty = switch (ip.indexToKey(new_ty)) { | 6552 | const new_elem_ty = switch (ip.indexToKey(new_ty)) { |
| 6094 | inline .array_type, .vector_type => |seq_type| seq_type.child, | 6553 | inline .array_type, .vector_type => |seq_type| seq_type.child, |
| 6095 | .anon_struct_type => |anon_struct_type| anon_struct_type.types.get(ip)[i], | 6554 | .anon_struct_type => |anon_struct_type| anon_struct_type.types.get(ip)[i], |
| 6096 | .struct_type => |struct_type| ip.structPtr(struct_type.index.unwrap().?) | 6555 | .struct_type => |struct_type| struct_type.field_types.get(ip)[i], |
| 6097 | .fields.values()[i].ty.toIntern(), | ||
| 6098 | else => unreachable, | 6556 | else => unreachable, |
| 6099 | }; | 6557 | }; |
| 6100 | elem.* = try ip.getCoerced(gpa, elem.*, new_elem_ty); | 6558 | elem.* = try ip.getCoerced(gpa, elem.*, new_elem_ty); |
| ... | @@ -6206,25 +6664,6 @@ pub fn getCoercedInts(ip: *InternPool, gpa: Allocator, int: Key.Int, new_ty: Ind | ... | @@ -6206,25 +6664,6 @@ pub fn getCoercedInts(ip: *InternPool, gpa: Allocator, int: Key.Int, new_ty: Ind |
| 6206 | } }); | 6664 | } }); |
| 6207 | } | 6665 | } |
| 6208 | 6666 | ||
| 6209 | pub fn indexToStructType(ip: *const InternPool, val: Index) Module.Struct.OptionalIndex { | ||
| 6210 | assert(val != .none); | ||
| 6211 | const tags = ip.items.items(.tag); | ||
| 6212 | if (tags[@intFromEnum(val)] != .type_struct) return .none; | ||
| 6213 | const datas = ip.items.items(.data); | ||
| 6214 | return @as(Module.Struct.Index, @enumFromInt(datas[@intFromEnum(val)])).toOptional(); | ||
| 6215 | } | ||
| 6216 | |||
| 6217 | pub fn indexToUnionType(ip: *const InternPool, val: Index) Module.Union.OptionalIndex { | ||
| 6218 | assert(val != .none); | ||
| 6219 | const tags = ip.items.items(.tag); | ||
| 6220 | switch (tags[@intFromEnum(val)]) { | ||
| 6221 | .type_union => {}, | ||
| 6222 | else => return .none, | ||
| 6223 | } | ||
| 6224 | const datas = ip.items.items(.data); | ||
| 6225 | return @as(Module.Union.Index, @enumFromInt(datas[@intFromEnum(val)])).toOptional(); | ||
| 6226 | } | ||
| 6227 | |||
| 6228 | pub fn indexToFuncType(ip: *const InternPool, val: Index) ?Key.FuncType { | 6667 | pub fn indexToFuncType(ip: *const InternPool, val: Index) ?Key.FuncType { |
| 6229 | assert(val != .none); | 6668 | assert(val != .none); |
| 6230 | const tags = ip.items.items(.tag); | 6669 | const tags = ip.items.items(.tag); |
| ... | @@ -6337,20 +6776,16 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void { | ... | @@ -6337,20 +6776,16 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void { |
| 6337 | const items_size = (1 + 4) * ip.items.len; | 6776 | const items_size = (1 + 4) * ip.items.len; |
| 6338 | const extra_size = 4 * ip.extra.items.len; | 6777 | const extra_size = 4 * ip.extra.items.len; |
| 6339 | const limbs_size = 8 * ip.limbs.items.len; | 6778 | const limbs_size = 8 * ip.limbs.items.len; |
| 6340 | // TODO: fields size is not taken into account | ||
| 6341 | const structs_size = ip.allocated_structs.len * | ||
| 6342 | (@sizeOf(Module.Struct) + @sizeOf(Module.Namespace)); | ||
| 6343 | const decls_size = ip.allocated_decls.len * @sizeOf(Module.Decl); | 6779 | const decls_size = ip.allocated_decls.len * @sizeOf(Module.Decl); |
| 6344 | 6780 | ||
| 6345 | // TODO: map overhead size is not taken into account | 6781 | // TODO: map overhead size is not taken into account |
| 6346 | const total_size = @sizeOf(InternPool) + items_size + extra_size + limbs_size + structs_size + decls_size; | 6782 | const total_size = @sizeOf(InternPool) + items_size + extra_size + limbs_size + decls_size; |
| 6347 | 6783 | ||
| 6348 | std.debug.print( | 6784 | std.debug.print( |
| 6349 | \\InternPool size: {d} bytes | 6785 | \\InternPool size: {d} bytes |
| 6350 | \\ {d} items: {d} bytes | 6786 | \\ {d} items: {d} bytes |
| 6351 | \\ {d} extra: {d} bytes | 6787 | \\ {d} extra: {d} bytes |
| 6352 | \\ {d} limbs: {d} bytes | 6788 | \\ {d} limbs: {d} bytes |
| 6353 | \\ {d} structs: {d} bytes | ||
| 6354 | \\ {d} decls: {d} bytes | 6789 | \\ {d} decls: {d} bytes |
| 6355 | \\ | 6790 | \\ |
| 6356 | , .{ | 6791 | , .{ |
| ... | @@ -6361,8 +6796,6 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void { | ... | @@ -6361,8 +6796,6 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void { |
| 6361 | extra_size, | 6796 | extra_size, |
| 6362 | ip.limbs.items.len, | 6797 | ip.limbs.items.len, |
| 6363 | limbs_size, | 6798 | limbs_size, |
| 6364 | ip.allocated_structs.len, | ||
| 6365 | structs_size, | ||
| 6366 | ip.allocated_decls.len, | 6799 | ip.allocated_decls.len, |
| 6367 | decls_size, | 6800 | decls_size, |
| 6368 | }); | 6801 | }); |
| ... | @@ -6399,17 +6832,40 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void { | ... | @@ -6399,17 +6832,40 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void { |
| 6399 | .type_enum_auto => @sizeOf(EnumAuto), | 6832 | .type_enum_auto => @sizeOf(EnumAuto), |
| 6400 | .type_opaque => @sizeOf(Key.OpaqueType), | 6833 | .type_opaque => @sizeOf(Key.OpaqueType), |
| 6401 | .type_struct => b: { | 6834 | .type_struct => b: { |
| 6402 | const struct_index = @as(Module.Struct.Index, @enumFromInt(data)); | 6835 | const info = ip.extraData(Tag.TypeStruct, data); |
| 6403 | const struct_obj = ip.structPtrConst(struct_index); | 6836 | var ints: usize = @typeInfo(Tag.TypeStruct).Struct.fields.len; |
| 6404 | break :b @sizeOf(Module.Struct) + | 6837 | ints += info.fields_len; // types |
| 6405 | @sizeOf(Module.Namespace) + | 6838 | if (!info.flags.is_tuple) { |
| 6406 | (struct_obj.fields.count() * @sizeOf(Module.Struct.Field)); | 6839 | ints += 1; // names_map |
| 6840 | ints += info.fields_len; // names | ||
| 6841 | } | ||
| 6842 | if (info.flags.any_default_inits) | ||
| 6843 | ints += info.fields_len; // inits | ||
| 6844 | ints += @intFromBool(info.flags.has_namespace); // namespace | ||
| 6845 | if (info.flags.any_aligned_fields) | ||
| 6846 | ints += (info.fields_len + 3) / 4; // aligns | ||
| 6847 | if (info.flags.any_comptime_fields) | ||
| 6848 | ints += (info.fields_len + 31) / 32; // comptime bits | ||
| 6849 | if (info.flags.has_reordered_fields) | ||
| 6850 | ints += info.fields_len; // runtime order | ||
| 6851 | ints += info.fields_len; // offsets | ||
| 6852 | break :b @sizeOf(u32) * ints; | ||
| 6407 | }, | 6853 | }, |
| 6408 | .type_struct_ns => @sizeOf(Module.Namespace), | 6854 | .type_struct_ns => @sizeOf(Module.Namespace), |
| 6409 | .type_struct_anon => b: { | 6855 | .type_struct_anon => b: { |
| 6410 | const info = ip.extraData(TypeStructAnon, data); | 6856 | const info = ip.extraData(TypeStructAnon, data); |
| 6411 | break :b @sizeOf(TypeStructAnon) + (@sizeOf(u32) * 3 * info.fields_len); | 6857 | break :b @sizeOf(TypeStructAnon) + (@sizeOf(u32) * 3 * info.fields_len); |
| 6412 | }, | 6858 | }, |
| 6859 | .type_struct_packed => b: { | ||
| 6860 | const info = ip.extraData(Tag.TypeStructPacked, data); | ||
| 6861 | break :b @sizeOf(u32) * (@typeInfo(Tag.TypeStructPacked).Struct.fields.len + | ||
| 6862 | info.fields_len + info.fields_len); | ||
| 6863 | }, | ||
| 6864 | .type_struct_packed_inits => b: { | ||
| 6865 | const info = ip.extraData(Tag.TypeStructPacked, data); | ||
| 6866 | break :b @sizeOf(u32) * (@typeInfo(Tag.TypeStructPacked).Struct.fields.len + | ||
| 6867 | info.fields_len + info.fields_len + info.fields_len); | ||
| 6868 | }, | ||
| 6413 | .type_tuple_anon => b: { | 6869 | .type_tuple_anon => b: { |
| 6414 | const info = ip.extraData(TypeStructAnon, data); | 6870 | const info = ip.extraData(TypeStructAnon, data); |
| 6415 | break :b @sizeOf(TypeStructAnon) + (@sizeOf(u32) * 2 * info.fields_len); | 6871 | break :b @sizeOf(TypeStructAnon) + (@sizeOf(u32) * 2 * info.fields_len); |
| ... | @@ -6562,6 +7018,8 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void { | ... | @@ -6562,6 +7018,8 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void { |
| 6562 | .type_struct, | 7018 | .type_struct, |
| 6563 | .type_struct_ns, | 7019 | .type_struct_ns, |
| 6564 | .type_struct_anon, | 7020 | .type_struct_anon, |
| 7021 | .type_struct_packed, | ||
| 7022 | .type_struct_packed_inits, | ||
| 6565 | .type_tuple_anon, | 7023 | .type_tuple_anon, |
| 6566 | .type_union, | 7024 | .type_union, |
| 6567 | .type_function, | 7025 | .type_function, |
| ... | @@ -6677,18 +7135,6 @@ pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator) | ... | @@ -6677,18 +7135,6 @@ pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator) |
| 6677 | try bw.flush(); | 7135 | try bw.flush(); |
| 6678 | } | 7136 | } |
| 6679 | 7137 | ||
| 6680 | pub fn structPtr(ip: *InternPool, index: Module.Struct.Index) *Module.Struct { | ||
| 6681 | return ip.allocated_structs.at(@intFromEnum(index)); | ||
| 6682 | } | ||
| 6683 | |||
| 6684 | pub fn structPtrConst(ip: *const InternPool, index: Module.Struct.Index) *const Module.Struct { | ||
| 6685 | return ip.allocated_structs.at(@intFromEnum(index)); | ||
| 6686 | } | ||
| 6687 | |||
| 6688 | pub fn structPtrUnwrapConst(ip: *const InternPool, index: Module.Struct.OptionalIndex) ?*const Module.Struct { | ||
| 6689 | return structPtrConst(ip, index.unwrap() orelse return null); | ||
| 6690 | } | ||
| 6691 | |||
| 6692 | pub fn declPtr(ip: *InternPool, index: Module.Decl.Index) *Module.Decl { | 7138 | pub fn declPtr(ip: *InternPool, index: Module.Decl.Index) *Module.Decl { |
| 6693 | return ip.allocated_decls.at(@intFromEnum(index)); | 7139 | return ip.allocated_decls.at(@intFromEnum(index)); |
| 6694 | } | 7140 | } |
| ... | @@ -6701,28 +7147,6 @@ pub fn namespacePtr(ip: *InternPool, index: Module.Namespace.Index) *Module.Name | ... | @@ -6701,28 +7147,6 @@ pub fn namespacePtr(ip: *InternPool, index: Module.Namespace.Index) *Module.Name |
| 6701 | return ip.allocated_namespaces.at(@intFromEnum(index)); | 7147 | return ip.allocated_namespaces.at(@intFromEnum(index)); |
| 6702 | } | 7148 | } |
| 6703 | 7149 | ||
| 6704 | pub fn createStruct( | ||
| 6705 | ip: *InternPool, | ||
| 6706 | gpa: Allocator, | ||
| 6707 | initialization: Module.Struct, | ||
| 6708 | ) Allocator.Error!Module.Struct.Index { | ||
| 6709 | if (ip.structs_free_list.popOrNull()) |index| { | ||
| 6710 | ip.allocated_structs.at(@intFromEnum(index)).* = initialization; | ||
| 6711 | return index; | ||
| 6712 | } | ||
| 6713 | const ptr = try ip.allocated_structs.addOne(gpa); | ||
| 6714 | ptr.* = initialization; | ||
| 6715 | return @enumFromInt(ip.allocated_structs.len - 1); | ||
| 6716 | } | ||
| 6717 | |||
| 6718 | pub fn destroyStruct(ip: *InternPool, gpa: Allocator, index: Module.Struct.Index) void { | ||
| 6719 | ip.structPtr(index).* = undefined; | ||
| 6720 | ip.structs_free_list.append(gpa, index) catch { | ||
| 6721 | // In order to keep `destroyStruct` a non-fallible function, we ignore memory | ||
| 6722 | // allocation failures here, instead leaking the Struct until garbage collection. | ||
| 6723 | }; | ||
| 6724 | } | ||
| 6725 | |||
| 6726 | pub fn createDecl( | 7150 | pub fn createDecl( |
| 6727 | ip: *InternPool, | 7151 | ip: *InternPool, |
| 6728 | gpa: Allocator, | 7152 | gpa: Allocator, |
| ... | @@ -6967,6 +7391,8 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index { | ... | @@ -6967,6 +7391,8 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index { |
| 6967 | .type_struct, | 7391 | .type_struct, |
| 6968 | .type_struct_ns, | 7392 | .type_struct_ns, |
| 6969 | .type_struct_anon, | 7393 | .type_struct_anon, |
| 7394 | .type_struct_packed, | ||
| 7395 | .type_struct_packed_inits, | ||
| 6970 | .type_tuple_anon, | 7396 | .type_tuple_anon, |
| 6971 | .type_union, | 7397 | .type_union, |
| 6972 | .type_function, | 7398 | .type_function, |
| ... | @@ -7056,7 +7482,7 @@ pub fn toEnum(ip: *const InternPool, comptime E: type, i: Index) E { | ... | @@ -7056,7 +7482,7 @@ pub fn toEnum(ip: *const InternPool, comptime E: type, i: Index) E { |
| 7056 | 7482 | ||
| 7057 | pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 { | 7483 | pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 { |
| 7058 | return switch (ip.indexToKey(ty)) { | 7484 | return switch (ip.indexToKey(ty)) { |
| 7059 | .struct_type => |struct_type| ip.structPtrConst(struct_type.index.unwrap() orelse return 0).fields.count(), | 7485 | .struct_type => |struct_type| struct_type.field_types.len, |
| 7060 | .anon_struct_type => |anon_struct_type| anon_struct_type.types.len, | 7486 | .anon_struct_type => |anon_struct_type| anon_struct_type.types.len, |
| 7061 | .array_type => |array_type| array_type.len, | 7487 | .array_type => |array_type| array_type.len, |
| 7062 | .vector_type => |vector_type| vector_type.len, | 7488 | .vector_type => |vector_type| vector_type.len, |
| ... | @@ -7066,7 +7492,7 @@ pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 { | ... | @@ -7066,7 +7492,7 @@ pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 { |
| 7066 | 7492 | ||
| 7067 | pub fn aggregateTypeLenIncludingSentinel(ip: *const InternPool, ty: Index) u64 { | 7493 | pub fn aggregateTypeLenIncludingSentinel(ip: *const InternPool, ty: Index) u64 { |
| 7068 | return switch (ip.indexToKey(ty)) { | 7494 | return switch (ip.indexToKey(ty)) { |
| 7069 | .struct_type => |struct_type| ip.structPtrConst(struct_type.index.unwrap() orelse return 0).fields.count(), | 7495 | .struct_type => |struct_type| struct_type.field_types.len, |
| 7070 | .anon_struct_type => |anon_struct_type| anon_struct_type.types.len, | 7496 | .anon_struct_type => |anon_struct_type| anon_struct_type.types.len, |
| 7071 | .array_type => |array_type| array_type.len + @intFromBool(array_type.sentinel != .none), | 7497 | .array_type => |array_type| array_type.len + @intFromBool(array_type.sentinel != .none), |
| 7072 | .vector_type => |vector_type| vector_type.len, | 7498 | .vector_type => |vector_type| vector_type.len, |
| ... | @@ -7301,6 +7727,8 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois | ... | @@ -7301,6 +7727,8 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois |
| 7301 | .type_struct, | 7727 | .type_struct, |
| 7302 | .type_struct_ns, | 7728 | .type_struct_ns, |
| 7303 | .type_struct_anon, | 7729 | .type_struct_anon, |
| 7730 | .type_struct_packed, | ||
| 7731 | .type_struct_packed_inits, | ||
| 7304 | .type_tuple_anon, | 7732 | .type_tuple_anon, |
| 7305 | => .Struct, | 7733 | => .Struct, |
| 7306 | 7734 | ||
| ... | @@ -7526,6 +7954,40 @@ pub fn resolveBuiltinType(ip: *InternPool, want_index: Index, resolved_index: In | ... | @@ -7526,6 +7954,40 @@ pub fn resolveBuiltinType(ip: *InternPool, want_index: Index, resolved_index: In |
| 7526 | .data = @intFromEnum(SimpleValue.@"unreachable"), | 7954 | .data = @intFromEnum(SimpleValue.@"unreachable"), |
| 7527 | }); | 7955 | }); |
| 7528 | } else { | 7956 | } else { |
| 7529 | // TODO: add the index to a free-list for reuse | 7957 | // Here we could add the index to a free-list for reuse, but since |
| 7958 | // there is so little garbage created this way it's not worth it. | ||
| 7530 | } | 7959 | } |
| 7531 | } | 7960 | } |
| 7961 | |||
| 7962 | pub fn anonStructFieldTypes(ip: *const InternPool, i: Index) []const Index { | ||
| 7963 | return ip.indexToKey(i).anon_struct_type.types; | ||
| 7964 | } | ||
| 7965 | |||
| 7966 | pub fn anonStructFieldsLen(ip: *const InternPool, i: Index) u32 { | ||
| 7967 | return @intCast(ip.indexToKey(i).anon_struct_type.types.len); | ||
| 7968 | } | ||
| 7969 | |||
| 7970 | /// Asserts the type is a struct. | ||
| 7971 | pub fn structDecl(ip: *const InternPool, i: Index) Module.Decl.OptionalIndex { | ||
| 7972 | return switch (ip.indexToKey(i)) { | ||
| 7973 | .struct_type => |t| t.decl, | ||
| 7974 | else => unreachable, | ||
| 7975 | }; | ||
| 7976 | } | ||
| 7977 | |||
| 7978 | /// Returns the already-existing field with the same name, if any. | ||
| 7979 | pub fn addFieldName( | ||
| 7980 | ip: *InternPool, | ||
| 7981 | names_map: MapIndex, | ||
| 7982 | names_start: u32, | ||
| 7983 | name: NullTerminatedString, | ||
| 7984 | ) ?u32 { | ||
| 7985 | const map = &ip.maps.items[@intFromEnum(names_map)]; | ||
| 7986 | const field_index = map.count(); | ||
| 7987 | const strings = ip.extra.items[names_start..][0..field_index]; | ||
| 7988 | const adapter: NullTerminatedString.Adapter = .{ .strings = @ptrCast(strings) }; | ||
| 7989 | const gop = map.getOrPutAssumeCapacityAdapted(name, adapter); | ||
| 7990 | if (gop.found_existing) return @intCast(gop.index); | ||
| 7991 | ip.extra.items[names_start + field_index] = @intFromEnum(name); | ||
| 7992 | return null; | ||
| 7993 | } |
src/Module.zig+192-374| ... | @@ -105,8 +105,6 @@ comptime_capture_scopes: std.AutoArrayHashMapUnmanaged(CaptureScope.Key, InternP | ... | @@ -105,8 +105,6 @@ comptime_capture_scopes: std.AutoArrayHashMapUnmanaged(CaptureScope.Key, InternP |
| 105 | 105 | ||
| 106 | /// To be eliminated in a future commit by moving more data into InternPool. | 106 | /// To be eliminated in a future commit by moving more data into InternPool. |
| 107 | /// Current uses that must be eliminated: | 107 | /// Current uses that must be eliminated: |
| 108 | /// * Struct comptime_args | ||
| 109 | /// * Struct optimized_order | ||
| 110 | /// * comptime pointer mutation | 108 | /// * comptime pointer mutation |
| 111 | /// This memory lives until the Module is destroyed. | 109 | /// This memory lives until the Module is destroyed. |
| 112 | tmp_hack_arena: std.heap.ArenaAllocator, | 110 | tmp_hack_arena: std.heap.ArenaAllocator, |
| ... | @@ -678,14 +676,10 @@ pub const Decl = struct { | ... | @@ -678,14 +676,10 @@ pub const Decl = struct { |
| 678 | 676 | ||
| 679 | /// If the Decl owns its value and it is a struct, return it, | 677 | /// If the Decl owns its value and it is a struct, return it, |
| 680 | /// otherwise null. | 678 | /// otherwise null. |
| 681 | pub fn getOwnedStruct(decl: Decl, mod: *Module) ?*Struct { | 679 | pub fn getOwnedStruct(decl: Decl, mod: *Module) ?InternPool.Key.StructType { |
| 682 | return mod.structPtrUnwrap(decl.getOwnedStructIndex(mod)); | 680 | if (!decl.owns_tv) return null; |
| 683 | } | 681 | if (decl.val.ip_index == .none) return null; |
| 684 | 682 | return mod.typeToStruct(decl.val.toType()); | |
| 685 | pub fn getOwnedStructIndex(decl: Decl, mod: *Module) Struct.OptionalIndex { | ||
| 686 | if (!decl.owns_tv) return .none; | ||
| 687 | if (decl.val.ip_index == .none) return .none; | ||
| 688 | return mod.intern_pool.indexToStructType(decl.val.toIntern()); | ||
| 689 | } | 683 | } |
| 690 | 684 | ||
| 691 | /// If the Decl owns its value and it is a union, return it, | 685 | /// If the Decl owns its value and it is a union, return it, |
| ... | @@ -795,9 +789,10 @@ pub const Decl = struct { | ... | @@ -795,9 +789,10 @@ pub const Decl = struct { |
| 795 | return decl.getExternDecl(mod) != .none; | 789 | return decl.getExternDecl(mod) != .none; |
| 796 | } | 790 | } |
| 797 | 791 | ||
| 798 | pub fn getAlignment(decl: Decl, mod: *Module) u32 { | 792 | pub fn getAlignment(decl: Decl, mod: *Module) Alignment { |
| 799 | assert(decl.has_tv); | 793 | assert(decl.has_tv); |
| 800 | return @as(u32, @intCast(decl.alignment.toByteUnitsOptional() orelse decl.ty.abiAlignment(mod))); | 794 | if (decl.alignment != .none) return decl.alignment; |
| 795 | return decl.ty.abiAlignment(mod); | ||
| 801 | } | 796 | } |
| 802 | }; | 797 | }; |
| 803 | 798 | ||
| ... | @@ -806,218 +801,6 @@ pub const EmitH = struct { | ... | @@ -806,218 +801,6 @@ pub const EmitH = struct { |
| 806 | fwd_decl: ArrayListUnmanaged(u8) = .{}, | 801 | fwd_decl: ArrayListUnmanaged(u8) = .{}, |
| 807 | }; | 802 | }; |
| 808 | 803 | ||
| 809 | pub const PropertyBoolean = enum { no, yes, unknown, wip }; | ||
| 810 | |||
| 811 | /// Represents the data that a struct declaration provides. | ||
| 812 | pub const Struct = struct { | ||
| 813 | /// Set of field names in declaration order. | ||
| 814 | fields: Fields, | ||
| 815 | /// Represents the declarations inside this struct. | ||
| 816 | namespace: Namespace.Index, | ||
| 817 | /// The Decl that corresponds to the struct itself. | ||
| 818 | owner_decl: Decl.Index, | ||
| 819 | /// Index of the struct_decl ZIR instruction. | ||
| 820 | zir_index: Zir.Inst.Index, | ||
| 821 | /// Indexes into `fields` sorted to be most memory efficient. | ||
| 822 | optimized_order: ?[*]u32 = null, | ||
| 823 | layout: std.builtin.Type.ContainerLayout, | ||
| 824 | /// If the layout is not packed, this is the noreturn type. | ||
| 825 | /// If the layout is packed, this is the backing integer type of the packed struct. | ||
| 826 | /// Whether zig chooses this type or the user specifies it, it is stored here. | ||
| 827 | /// This will be set to the noreturn type until status is `have_layout`. | ||
| 828 | backing_int_ty: Type = Type.noreturn, | ||
| 829 | status: enum { | ||
| 830 | none, | ||
| 831 | field_types_wip, | ||
| 832 | have_field_types, | ||
| 833 | layout_wip, | ||
| 834 | have_layout, | ||
| 835 | fully_resolved_wip, | ||
| 836 | // The types and all its fields have had their layout resolved. Even through pointer, | ||
| 837 | // which `have_layout` does not ensure. | ||
| 838 | fully_resolved, | ||
| 839 | }, | ||
| 840 | /// If true, has more than one possible value. However it may still be non-runtime type | ||
| 841 | /// if it is a comptime-only type. | ||
| 842 | /// If false, resolving the fields is necessary to determine whether the type has only | ||
| 843 | /// one possible value. | ||
| 844 | known_non_opv: bool, | ||
| 845 | requires_comptime: PropertyBoolean = .unknown, | ||
| 846 | have_field_inits: bool = false, | ||
| 847 | is_tuple: bool, | ||
| 848 | assumed_runtime_bits: bool = false, | ||
| 849 | |||
| 850 | pub const Index = enum(u32) { | ||
| 851 | _, | ||
| 852 | |||
| 853 | pub fn toOptional(i: Index) OptionalIndex { | ||
| 854 | return @as(OptionalIndex, @enumFromInt(@intFromEnum(i))); | ||
| 855 | } | ||
| 856 | }; | ||
| 857 | |||
| 858 | pub const OptionalIndex = enum(u32) { | ||
| 859 | none = std.math.maxInt(u32), | ||
| 860 | _, | ||
| 861 | |||
| 862 | pub fn init(oi: ?Index) OptionalIndex { | ||
| 863 | return @as(OptionalIndex, @enumFromInt(@intFromEnum(oi orelse return .none))); | ||
| 864 | } | ||
| 865 | |||
| 866 | pub fn unwrap(oi: OptionalIndex) ?Index { | ||
| 867 | if (oi == .none) return null; | ||
| 868 | return @as(Index, @enumFromInt(@intFromEnum(oi))); | ||
| 869 | } | ||
| 870 | }; | ||
| 871 | |||
| 872 | pub const Fields = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, Field); | ||
| 873 | |||
| 874 | /// The `Type` and `Value` memory is owned by the arena of the Struct's owner_decl. | ||
| 875 | pub const Field = struct { | ||
| 876 | /// Uses `noreturn` to indicate `anytype`. | ||
| 877 | /// undefined until `status` is >= `have_field_types`. | ||
| 878 | ty: Type, | ||
| 879 | /// Uses `none` to indicate no default. | ||
| 880 | default_val: InternPool.Index, | ||
| 881 | /// Zero means to use the ABI alignment of the type. | ||
| 882 | abi_align: Alignment, | ||
| 883 | /// undefined until `status` is `have_layout`. | ||
| 884 | offset: u32, | ||
| 885 | /// If true then `default_val` is the comptime field value. | ||
| 886 | is_comptime: bool, | ||
| 887 | |||
| 888 | /// Returns the field alignment. If the struct is packed, returns 0. | ||
| 889 | /// Keep implementation in sync with `Sema.structFieldAlignment`. | ||
| 890 | pub fn alignment( | ||
| 891 | field: Field, | ||
| 892 | mod: *Module, | ||
| 893 | layout: std.builtin.Type.ContainerLayout, | ||
| 894 | ) u32 { | ||
| 895 | if (field.abi_align.toByteUnitsOptional()) |abi_align| { | ||
| 896 | assert(layout != .Packed); | ||
| 897 | return @as(u32, @intCast(abi_align)); | ||
| 898 | } | ||
| 899 | |||
| 900 | const target = mod.getTarget(); | ||
| 901 | |||
| 902 | switch (layout) { | ||
| 903 | .Packed => return 0, | ||
| 904 | .Auto => { | ||
| 905 | if (target.ofmt == .c) { | ||
| 906 | return alignmentExtern(field, mod); | ||
| 907 | } else { | ||
| 908 | return field.ty.abiAlignment(mod); | ||
| 909 | } | ||
| 910 | }, | ||
| 911 | .Extern => return alignmentExtern(field, mod), | ||
| 912 | } | ||
| 913 | } | ||
| 914 | |||
| 915 | pub fn alignmentExtern(field: Field, mod: *Module) u32 { | ||
| 916 | // This logic is duplicated in Type.abiAlignmentAdvanced. | ||
| 917 | const ty_abi_align = field.ty.abiAlignment(mod); | ||
| 918 | |||
| 919 | if (field.ty.isAbiInt(mod) and field.ty.intInfo(mod).bits >= 128) { | ||
| 920 | // The C ABI requires 128 bit integer fields of structs | ||
| 921 | // to be 16-bytes aligned. | ||
| 922 | return @max(ty_abi_align, 16); | ||
| 923 | } | ||
| 924 | |||
| 925 | return ty_abi_align; | ||
| 926 | } | ||
| 927 | }; | ||
| 928 | |||
| 929 | /// Used in `optimized_order` to indicate field that is not present in the | ||
| 930 | /// runtime version of the struct. | ||
| 931 | pub const omitted_field = std.math.maxInt(u32); | ||
| 932 | |||
| 933 | pub fn getFullyQualifiedName(s: *Struct, mod: *Module) !InternPool.NullTerminatedString { | ||
| 934 | return mod.declPtr(s.owner_decl).getFullyQualifiedName(mod); | ||
| 935 | } | ||
| 936 | |||
| 937 | pub fn srcLoc(s: Struct, mod: *Module) SrcLoc { | ||
| 938 | return mod.declPtr(s.owner_decl).srcLoc(mod); | ||
| 939 | } | ||
| 940 | |||
| 941 | pub fn haveFieldTypes(s: Struct) bool { | ||
| 942 | return switch (s.status) { | ||
| 943 | .none, | ||
| 944 | .field_types_wip, | ||
| 945 | => false, | ||
| 946 | .have_field_types, | ||
| 947 | .layout_wip, | ||
| 948 | .have_layout, | ||
| 949 | .fully_resolved_wip, | ||
| 950 | .fully_resolved, | ||
| 951 | => true, | ||
| 952 | }; | ||
| 953 | } | ||
| 954 | |||
| 955 | pub fn haveLayout(s: Struct) bool { | ||
| 956 | return switch (s.status) { | ||
| 957 | .none, | ||
| 958 | .field_types_wip, | ||
| 959 | .have_field_types, | ||
| 960 | .layout_wip, | ||
| 961 | => false, | ||
| 962 | .have_layout, | ||
| 963 | .fully_resolved_wip, | ||
| 964 | .fully_resolved, | ||
| 965 | => true, | ||
| 966 | }; | ||
| 967 | } | ||
| 968 | |||
| 969 | pub fn packedFieldBitOffset(s: Struct, mod: *Module, index: usize) u16 { | ||
| 970 | assert(s.layout == .Packed); | ||
| 971 | assert(s.haveLayout()); | ||
| 972 | var bit_sum: u64 = 0; | ||
| 973 | for (s.fields.values(), 0..) |field, i| { | ||
| 974 | if (i == index) { | ||
| 975 | return @as(u16, @intCast(bit_sum)); | ||
| 976 | } | ||
| 977 | bit_sum += field.ty.bitSize(mod); | ||
| 978 | } | ||
| 979 | unreachable; // index out of bounds | ||
| 980 | } | ||
| 981 | |||
| 982 | pub const RuntimeFieldIterator = struct { | ||
| 983 | module: *Module, | ||
| 984 | struct_obj: *const Struct, | ||
| 985 | index: u32 = 0, | ||
| 986 | |||
| 987 | pub const FieldAndIndex = struct { | ||
| 988 | field: Field, | ||
| 989 | index: u32, | ||
| 990 | }; | ||
| 991 | |||
| 992 | pub fn next(it: *RuntimeFieldIterator) ?FieldAndIndex { | ||
| 993 | const mod = it.module; | ||
| 994 | while (true) { | ||
| 995 | var i = it.index; | ||
| 996 | it.index += 1; | ||
| 997 | if (it.struct_obj.fields.count() <= i) | ||
| 998 | return null; | ||
| 999 | |||
| 1000 | if (it.struct_obj.optimized_order) |some| { | ||
| 1001 | i = some[i]; | ||
| 1002 | if (i == Module.Struct.omitted_field) return null; | ||
| 1003 | } | ||
| 1004 | const field = it.struct_obj.fields.values()[i]; | ||
| 1005 | |||
| 1006 | if (!field.is_comptime and field.ty.hasRuntimeBits(mod)) { | ||
| 1007 | return FieldAndIndex{ .index = i, .field = field }; | ||
| 1008 | } | ||
| 1009 | } | ||
| 1010 | } | ||
| 1011 | }; | ||
| 1012 | |||
| 1013 | pub fn runtimeFieldIterator(s: *const Struct, module: *Module) RuntimeFieldIterator { | ||
| 1014 | return .{ | ||
| 1015 | .struct_obj = s, | ||
| 1016 | .module = module, | ||
| 1017 | }; | ||
| 1018 | } | ||
| 1019 | }; | ||
| 1020 | |||
| 1021 | pub const DeclAdapter = struct { | 804 | pub const DeclAdapter = struct { |
| 1022 | mod: *Module, | 805 | mod: *Module, |
| 1023 | 806 | ||
| ... | @@ -2893,20 +2676,10 @@ pub fn namespacePtr(mod: *Module, index: Namespace.Index) *Namespace { | ... | @@ -2893,20 +2676,10 @@ pub fn namespacePtr(mod: *Module, index: Namespace.Index) *Namespace { |
| 2893 | return mod.intern_pool.namespacePtr(index); | 2676 | return mod.intern_pool.namespacePtr(index); |
| 2894 | } | 2677 | } |
| 2895 | 2678 | ||
| 2896 | pub fn structPtr(mod: *Module, index: Struct.Index) *Struct { | ||
| 2897 | return mod.intern_pool.structPtr(index); | ||
| 2898 | } | ||
| 2899 | |||
| 2900 | pub fn namespacePtrUnwrap(mod: *Module, index: Namespace.OptionalIndex) ?*Namespace { | 2679 | pub fn namespacePtrUnwrap(mod: *Module, index: Namespace.OptionalIndex) ?*Namespace { |
| 2901 | return mod.namespacePtr(index.unwrap() orelse return null); | 2680 | return mod.namespacePtr(index.unwrap() orelse return null); |
| 2902 | } | 2681 | } |
| 2903 | 2682 | ||
| 2904 | /// This one accepts an index from the InternPool and asserts that it is not | ||
| 2905 | /// the anonymous empty struct type. | ||
| 2906 | pub fn structPtrUnwrap(mod: *Module, index: Struct.OptionalIndex) ?*Struct { | ||
| 2907 | return mod.structPtr(index.unwrap() orelse return null); | ||
| 2908 | } | ||
| 2909 | |||
| 2910 | /// Returns true if and only if the Decl is the top level struct associated with a File. | 2683 | /// Returns true if and only if the Decl is the top level struct associated with a File. |
| 2911 | pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool { | 2684 | pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool { |
| 2912 | const decl = mod.declPtr(decl_index); | 2685 | const decl = mod.declPtr(decl_index); |
| ... | @@ -3351,11 +3124,11 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void { | ... | @@ -3351,11 +3124,11 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void { |
| 3351 | 3124 | ||
| 3352 | if (!decl.owns_tv) continue; | 3125 | if (!decl.owns_tv) continue; |
| 3353 | 3126 | ||
| 3354 | if (decl.getOwnedStruct(mod)) |struct_obj| { | 3127 | if (decl.getOwnedStruct(mod)) |struct_type| { |
| 3355 | struct_obj.zir_index = inst_map.get(struct_obj.zir_index) orelse { | 3128 | struct_type.setZirIndex(ip, inst_map.get(struct_type.zir_index) orelse { |
| 3356 | try file.deleted_decls.append(gpa, decl_index); | 3129 | try file.deleted_decls.append(gpa, decl_index); |
| 3357 | continue; | 3130 | continue; |
| 3358 | }; | 3131 | }); |
| 3359 | } | 3132 | } |
| 3360 | 3133 | ||
| 3361 | if (decl.getOwnedUnion(mod)) |union_type| { | 3134 | if (decl.getOwnedUnion(mod)) |union_type| { |
| ... | @@ -3870,36 +3643,16 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { | ... | @@ -3870,36 +3643,16 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { |
| 3870 | const new_decl = mod.declPtr(new_decl_index); | 3643 | const new_decl = mod.declPtr(new_decl_index); |
| 3871 | errdefer @panic("TODO error handling"); | 3644 | errdefer @panic("TODO error handling"); |
| 3872 | 3645 | ||
| 3873 | const struct_index = try mod.createStruct(.{ | ||
| 3874 | .owner_decl = new_decl_index, | ||
| 3875 | .fields = .{}, | ||
| 3876 | .zir_index = undefined, // set below | ||
| 3877 | .layout = .Auto, | ||
| 3878 | .status = .none, | ||
| 3879 | .known_non_opv = undefined, | ||
| 3880 | .is_tuple = undefined, // set below | ||
| 3881 | .namespace = new_namespace_index, | ||
| 3882 | }); | ||
| 3883 | errdefer mod.destroyStruct(struct_index); | ||
| 3884 | |||
| 3885 | const struct_ty = try mod.intern_pool.get(gpa, .{ .struct_type = .{ | ||
| 3886 | .index = struct_index.toOptional(), | ||
| 3887 | .namespace = new_namespace_index.toOptional(), | ||
| 3888 | } }); | ||
| 3889 | // TODO: figure out InternPool removals for incremental compilation | ||
| 3890 | //errdefer mod.intern_pool.remove(struct_ty); | ||
| 3891 | |||
| 3892 | new_namespace.ty = struct_ty.toType(); | ||
| 3893 | file.root_decl = new_decl_index.toOptional(); | 3646 | file.root_decl = new_decl_index.toOptional(); |
| 3894 | 3647 | ||
| 3895 | new_decl.name = try file.fullyQualifiedName(mod); | 3648 | new_decl.name = try file.fullyQualifiedName(mod); |
| 3649 | new_decl.name_fully_qualified = true; | ||
| 3896 | new_decl.src_line = 0; | 3650 | new_decl.src_line = 0; |
| 3897 | new_decl.is_pub = true; | 3651 | new_decl.is_pub = true; |
| 3898 | new_decl.is_exported = false; | 3652 | new_decl.is_exported = false; |
| 3899 | new_decl.has_align = false; | 3653 | new_decl.has_align = false; |
| 3900 | new_decl.has_linksection_or_addrspace = false; | 3654 | new_decl.has_linksection_or_addrspace = false; |
| 3901 | new_decl.ty = Type.type; | 3655 | new_decl.ty = Type.type; |
| 3902 | new_decl.val = struct_ty.toValue(); | ||
| 3903 | new_decl.alignment = .none; | 3656 | new_decl.alignment = .none; |
| 3904 | new_decl.@"linksection" = .none; | 3657 | new_decl.@"linksection" = .none; |
| 3905 | new_decl.has_tv = true; | 3658 | new_decl.has_tv = true; |
| ... | @@ -3907,75 +3660,76 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { | ... | @@ -3907,75 +3660,76 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { |
| 3907 | new_decl.alive = true; // This Decl corresponds to a File and is therefore always alive. | 3660 | new_decl.alive = true; // This Decl corresponds to a File and is therefore always alive. |
| 3908 | new_decl.analysis = .in_progress; | 3661 | new_decl.analysis = .in_progress; |
| 3909 | new_decl.generation = mod.generation; | 3662 | new_decl.generation = mod.generation; |
| 3910 | new_decl.name_fully_qualified = true; | ||
| 3911 | 3663 | ||
| 3912 | if (file.status == .success_zir) { | 3664 | if (file.status != .success_zir) { |
| 3913 | assert(file.zir_loaded); | 3665 | new_decl.analysis = .file_failure; |
| 3914 | const main_struct_inst = Zir.main_struct_inst; | 3666 | return; |
| 3915 | const struct_obj = mod.structPtr(struct_index); | 3667 | } |
| 3916 | struct_obj.zir_index = main_struct_inst; | 3668 | assert(file.zir_loaded); |
| 3917 | const extended = file.zir.instructions.items(.data)[main_struct_inst].extended; | ||
| 3918 | const small = @as(Zir.Inst.StructDecl.Small, @bitCast(extended.small)); | ||
| 3919 | struct_obj.is_tuple = small.is_tuple; | ||
| 3920 | |||
| 3921 | var sema_arena = std.heap.ArenaAllocator.init(gpa); | ||
| 3922 | defer sema_arena.deinit(); | ||
| 3923 | const sema_arena_allocator = sema_arena.allocator(); | ||
| 3924 | |||
| 3925 | var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa); | ||
| 3926 | defer comptime_mutable_decls.deinit(); | ||
| 3927 | |||
| 3928 | var sema: Sema = .{ | ||
| 3929 | .mod = mod, | ||
| 3930 | .gpa = gpa, | ||
| 3931 | .arena = sema_arena_allocator, | ||
| 3932 | .code = file.zir, | ||
| 3933 | .owner_decl = new_decl, | ||
| 3934 | .owner_decl_index = new_decl_index, | ||
| 3935 | .func_index = .none, | ||
| 3936 | .func_is_naked = false, | ||
| 3937 | .fn_ret_ty = Type.void, | ||
| 3938 | .fn_ret_ty_ies = null, | ||
| 3939 | .owner_func_index = .none, | ||
| 3940 | .comptime_mutable_decls = &comptime_mutable_decls, | ||
| 3941 | }; | ||
| 3942 | defer sema.deinit(); | ||
| 3943 | 3669 | ||
| 3944 | if (sema.analyzeStructDecl(new_decl, main_struct_inst, struct_index)) |_| { | 3670 | var sema_arena = std.heap.ArenaAllocator.init(gpa); |
| 3945 | for (comptime_mutable_decls.items) |decl_index| { | 3671 | defer sema_arena.deinit(); |
| 3946 | const decl = mod.declPtr(decl_index); | 3672 | const sema_arena_allocator = sema_arena.allocator(); |
| 3947 | _ = try decl.internValue(mod); | ||
| 3948 | } | ||
| 3949 | new_decl.analysis = .complete; | ||
| 3950 | } else |err| switch (err) { | ||
| 3951 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3952 | error.AnalysisFail => {}, | ||
| 3953 | } | ||
| 3954 | 3673 | ||
| 3955 | if (mod.comp.whole_cache_manifest) |whole_cache_manifest| { | 3674 | var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa); |
| 3956 | const source = file.getSource(gpa) catch |err| { | 3675 | defer comptime_mutable_decls.deinit(); |
| 3957 | try reportRetryableFileError(mod, file, "unable to load source: {s}", .{@errorName(err)}); | ||
| 3958 | return error.AnalysisFail; | ||
| 3959 | }; | ||
| 3960 | 3676 | ||
| 3961 | const resolved_path = std.fs.path.resolve( | 3677 | var sema: Sema = .{ |
| 3962 | gpa, | 3678 | .mod = mod, |
| 3963 | if (file.pkg.root_src_directory.path) |pkg_path| | 3679 | .gpa = gpa, |
| 3964 | &[_][]const u8{ pkg_path, file.sub_file_path } | 3680 | .arena = sema_arena_allocator, |
| 3965 | else | 3681 | .code = file.zir, |
| 3966 | &[_][]const u8{file.sub_file_path}, | 3682 | .owner_decl = new_decl, |
| 3967 | ) catch |err| { | 3683 | .owner_decl_index = new_decl_index, |
| 3968 | try reportRetryableFileError(mod, file, "unable to resolve path: {s}", .{@errorName(err)}); | 3684 | .func_index = .none, |
| 3969 | return error.AnalysisFail; | 3685 | .func_is_naked = false, |
| 3970 | }; | 3686 | .fn_ret_ty = Type.void, |
| 3971 | errdefer gpa.free(resolved_path); | 3687 | .fn_ret_ty_ies = null, |
| 3688 | .owner_func_index = .none, | ||
| 3689 | .comptime_mutable_decls = &comptime_mutable_decls, | ||
| 3690 | }; | ||
| 3691 | defer sema.deinit(); | ||
| 3972 | 3692 | ||
| 3973 | mod.comp.whole_cache_manifest_mutex.lock(); | 3693 | const main_struct_inst = Zir.main_struct_inst; |
| 3974 | defer mod.comp.whole_cache_manifest_mutex.unlock(); | 3694 | const struct_ty = sema.getStructType( |
| 3975 | try whole_cache_manifest.addFilePostContents(resolved_path, source.bytes, source.stat); | 3695 | new_decl_index, |
| 3976 | } | 3696 | new_namespace_index, |
| 3977 | } else { | 3697 | main_struct_inst, |
| 3978 | new_decl.analysis = .file_failure; | 3698 | ) catch |err| switch (err) { |
| 3699 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3700 | }; | ||
| 3701 | // TODO: figure out InternPool removals for incremental compilation | ||
| 3702 | //errdefer ip.remove(struct_ty); | ||
| 3703 | for (comptime_mutable_decls.items) |decl_index| { | ||
| 3704 | const decl = mod.declPtr(decl_index); | ||
| 3705 | _ = try decl.internValue(mod); | ||
| 3706 | } | ||
| 3707 | |||
| 3708 | new_namespace.ty = struct_ty.toType(); | ||
| 3709 | new_decl.val = struct_ty.toValue(); | ||
| 3710 | new_decl.analysis = .complete; | ||
| 3711 | |||
| 3712 | if (mod.comp.whole_cache_manifest) |whole_cache_manifest| { | ||
| 3713 | const source = file.getSource(gpa) catch |err| { | ||
| 3714 | try reportRetryableFileError(mod, file, "unable to load source: {s}", .{@errorName(err)}); | ||
| 3715 | return error.AnalysisFail; | ||
| 3716 | }; | ||
| 3717 | |||
| 3718 | const resolved_path = std.fs.path.resolve( | ||
| 3719 | gpa, | ||
| 3720 | if (file.pkg.root_src_directory.path) |pkg_path| | ||
| 3721 | &[_][]const u8{ pkg_path, file.sub_file_path } | ||
| 3722 | else | ||
| 3723 | &[_][]const u8{file.sub_file_path}, | ||
| 3724 | ) catch |err| { | ||
| 3725 | try reportRetryableFileError(mod, file, "unable to resolve path: {s}", .{@errorName(err)}); | ||
| 3726 | return error.AnalysisFail; | ||
| 3727 | }; | ||
| 3728 | errdefer gpa.free(resolved_path); | ||
| 3729 | |||
| 3730 | mod.comp.whole_cache_manifest_mutex.lock(); | ||
| 3731 | defer mod.comp.whole_cache_manifest_mutex.unlock(); | ||
| 3732 | try whole_cache_manifest.addFilePostContents(resolved_path, source.bytes, source.stat); | ||
| 3979 | } | 3733 | } |
| 3980 | } | 3734 | } |
| 3981 | 3735 | ||
| ... | @@ -4057,12 +3811,12 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { | ... | @@ -4057,12 +3811,12 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4057 | 3811 | ||
| 4058 | if (mod.declIsRoot(decl_index)) { | 3812 | if (mod.declIsRoot(decl_index)) { |
| 4059 | const main_struct_inst = Zir.main_struct_inst; | 3813 | const main_struct_inst = Zir.main_struct_inst; |
| 4060 | const struct_index = decl.getOwnedStructIndex(mod).unwrap().?; | 3814 | const struct_type = decl.getOwnedStruct(mod).?; |
| 4061 | const struct_obj = mod.structPtr(struct_index); | 3815 | assert(struct_type.zir_index == main_struct_inst); |
| 4062 | // This might not have gotten set in `semaFile` if the first time had | 3816 | if (true) @panic("TODO"); |
| 4063 | // a ZIR failure, so we set it here in case. | 3817 | // why did the code used to have this? I don't see how struct_type could have |
| 4064 | struct_obj.zir_index = main_struct_inst; | 3818 | // been created already without the analyzeStructDecl logic already called on it. |
| 4065 | try sema.analyzeStructDecl(decl, main_struct_inst, struct_index); | 3819 | //try sema.analyzeStructDecl(decl, main_struct_inst, struct_type); |
| 4066 | decl.analysis = .complete; | 3820 | decl.analysis = .complete; |
| 4067 | decl.generation = mod.generation; | 3821 | decl.generation = mod.generation; |
| 4068 | return false; | 3822 | return false; |
| ... | @@ -5241,14 +4995,6 @@ pub fn destroyNamespace(mod: *Module, index: Namespace.Index) void { | ... | @@ -5241,14 +4995,6 @@ pub fn destroyNamespace(mod: *Module, index: Namespace.Index) void { |
| 5241 | return mod.intern_pool.destroyNamespace(mod.gpa, index); | 4995 | return mod.intern_pool.destroyNamespace(mod.gpa, index); |
| 5242 | } | 4996 | } |
| 5243 | 4997 | ||
| 5244 | pub fn createStruct(mod: *Module, initialization: Struct) Allocator.Error!Struct.Index { | ||
| 5245 | return mod.intern_pool.createStruct(mod.gpa, initialization); | ||
| 5246 | } | ||
| 5247 | |||
| 5248 | pub fn destroyStruct(mod: *Module, index: Struct.Index) void { | ||
| 5249 | return mod.intern_pool.destroyStruct(mod.gpa, index); | ||
| 5250 | } | ||
| 5251 | |||
| 5252 | pub fn allocateNewDecl( | 4998 | pub fn allocateNewDecl( |
| 5253 | mod: *Module, | 4999 | mod: *Module, |
| 5254 | namespace: Namespace.Index, | 5000 | namespace: Namespace.Index, |
| ... | @@ -6210,10 +5956,10 @@ pub fn ptrType(mod: *Module, info: InternPool.Key.PtrType) Allocator.Error!Type | ... | @@ -6210,10 +5956,10 @@ pub fn ptrType(mod: *Module, info: InternPool.Key.PtrType) Allocator.Error!Type |
| 6210 | // type, we change it to 0 here. If this causes an assertion trip because the | 5956 | // type, we change it to 0 here. If this causes an assertion trip because the |
| 6211 | // pointee type needs to be resolved more, that needs to be done before calling | 5957 | // pointee type needs to be resolved more, that needs to be done before calling |
| 6212 | // this ptr() function. | 5958 | // this ptr() function. |
| 6213 | if (info.flags.alignment.toByteUnitsOptional()) |info_align| { | 5959 | if (info.flags.alignment != .none and have_elem_layout and |
| 6214 | if (have_elem_layout and info_align == info.child.toType().abiAlignment(mod)) { | 5960 | info.flags.alignment == info.child.toType().abiAlignment(mod)) |
| 6215 | canon_info.flags.alignment = .none; | 5961 | { |
| 6216 | } | 5962 | canon_info.flags.alignment = .none; |
| 6217 | } | 5963 | } |
| 6218 | 5964 | ||
| 6219 | switch (info.flags.vector_index) { | 5965 | switch (info.flags.vector_index) { |
| ... | @@ -6483,7 +6229,7 @@ pub fn intBitsForValue(mod: *Module, val: Value, sign: bool) u16 { | ... | @@ -6483,7 +6229,7 @@ pub fn intBitsForValue(mod: *Module, val: Value, sign: bool) u16 { |
| 6483 | return @as(u16, @intCast(big.bitCountTwosComp())); | 6229 | return @as(u16, @intCast(big.bitCountTwosComp())); |
| 6484 | }, | 6230 | }, |
| 6485 | .lazy_align => |lazy_ty| { | 6231 | .lazy_align => |lazy_ty| { |
| 6486 | return Type.smallestUnsignedBits(lazy_ty.toType().abiAlignment(mod)) + @intFromBool(sign); | 6232 | return Type.smallestUnsignedBits(lazy_ty.toType().abiAlignment(mod).toByteUnits(0)) + @intFromBool(sign); |
| 6487 | }, | 6233 | }, |
| 6488 | .lazy_size => |lazy_ty| { | 6234 | .lazy_size => |lazy_ty| { |
| 6489 | return Type.smallestUnsignedBits(lazy_ty.toType().abiSize(mod)) + @intFromBool(sign); | 6235 | return Type.smallestUnsignedBits(lazy_ty.toType().abiSize(mod)) + @intFromBool(sign); |
| ... | @@ -6639,20 +6385,30 @@ pub fn namespaceDeclIndex(mod: *Module, namespace_index: Namespace.Index) Decl.I | ... | @@ -6639,20 +6385,30 @@ pub fn namespaceDeclIndex(mod: *Module, namespace_index: Namespace.Index) Decl.I |
| 6639 | /// * `@TypeOf(.{})` | 6385 | /// * `@TypeOf(.{})` |
| 6640 | /// * A struct which has no fields (`struct {}`). | 6386 | /// * A struct which has no fields (`struct {}`). |
| 6641 | /// * Not a struct. | 6387 | /// * Not a struct. |
| 6642 | pub fn typeToStruct(mod: *Module, ty: Type) ?*Struct { | 6388 | pub fn typeToStruct(mod: *Module, ty: Type) ?InternPool.Key.StructType { |
| 6643 | if (ty.ip_index == .none) return null; | 6389 | if (ty.ip_index == .none) return null; |
| 6644 | const struct_index = mod.intern_pool.indexToStructType(ty.toIntern()).unwrap() orelse return null; | 6390 | return switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 6645 | return mod.structPtr(struct_index); | 6391 | .struct_type => |t| t, |
| 6392 | else => null, | ||
| 6393 | }; | ||
| 6394 | } | ||
| 6395 | |||
| 6396 | pub fn typeToPackedStruct(mod: *Module, ty: Type) ?InternPool.Key.StructType { | ||
| 6397 | if (ty.ip_index == .none) return null; | ||
| 6398 | return switch (mod.intern_pool.indexToKey(ty.ip_index)) { | ||
| 6399 | .struct_type => |t| if (t.layout == .Packed) t else null, | ||
| 6400 | else => null, | ||
| 6401 | }; | ||
| 6646 | } | 6402 | } |
| 6647 | 6403 | ||
| 6648 | /// This asserts that the union's enum tag type has been resolved. | 6404 | /// This asserts that the union's enum tag type has been resolved. |
| 6649 | pub fn typeToUnion(mod: *Module, ty: Type) ?InternPool.UnionType { | 6405 | pub fn typeToUnion(mod: *Module, ty: Type) ?InternPool.UnionType { |
| 6650 | if (ty.ip_index == .none) return null; | 6406 | if (ty.ip_index == .none) return null; |
| 6651 | const ip = &mod.intern_pool; | 6407 | const ip = &mod.intern_pool; |
| 6652 | switch (ip.indexToKey(ty.ip_index)) { | 6408 | return switch (ip.indexToKey(ty.ip_index)) { |
| 6653 | .union_type => |k| return ip.loadUnionType(k), | 6409 | .union_type => |k| ip.loadUnionType(k), |
| 6654 | else => return null, | 6410 | else => null, |
| 6655 | } | 6411 | }; |
| 6656 | } | 6412 | } |
| 6657 | 6413 | ||
| 6658 | pub fn typeToFunc(mod: *Module, ty: Type) ?InternPool.Key.FuncType { | 6414 | pub fn typeToFunc(mod: *Module, ty: Type) ?InternPool.Key.FuncType { |
| ... | @@ -6741,13 +6497,13 @@ pub fn getParamName(mod: *Module, func_index: InternPool.Index, index: u32) [:0] | ... | @@ -6741,13 +6497,13 @@ pub fn getParamName(mod: *Module, func_index: InternPool.Index, index: u32) [:0] |
| 6741 | 6497 | ||
| 6742 | pub const UnionLayout = struct { | 6498 | pub const UnionLayout = struct { |
| 6743 | abi_size: u64, | 6499 | abi_size: u64, |
| 6744 | abi_align: u32, | 6500 | abi_align: Alignment, |
| 6745 | most_aligned_field: u32, | 6501 | most_aligned_field: u32, |
| 6746 | most_aligned_field_size: u64, | 6502 | most_aligned_field_size: u64, |
| 6747 | biggest_field: u32, | 6503 | biggest_field: u32, |
| 6748 | payload_size: u64, | 6504 | payload_size: u64, |
| 6749 | payload_align: u32, | 6505 | payload_align: Alignment, |
| 6750 | tag_align: u32, | 6506 | tag_align: Alignment, |
| 6751 | tag_size: u64, | 6507 | tag_size: u64, |
| 6752 | padding: u32, | 6508 | padding: u32, |
| 6753 | }; | 6509 | }; |
| ... | @@ -6759,35 +6515,37 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout { | ... | @@ -6759,35 +6515,37 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout { |
| 6759 | var most_aligned_field_size: u64 = undefined; | 6515 | var most_aligned_field_size: u64 = undefined; |
| 6760 | var biggest_field: u32 = undefined; | 6516 | var biggest_field: u32 = undefined; |
| 6761 | var payload_size: u64 = 0; | 6517 | var payload_size: u64 = 0; |
| 6762 | var payload_align: u32 = 0; | 6518 | var payload_align: Alignment = .@"1"; |
| 6763 | for (u.field_types.get(ip), 0..) |field_ty, i| { | 6519 | for (u.field_types.get(ip), 0..) |field_ty, i| { |
| 6764 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; | 6520 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 6765 | 6521 | ||
| 6766 | const field_align = u.fieldAlign(ip, @intCast(i)).toByteUnitsOptional() orelse | 6522 | const explicit_align = u.fieldAlign(ip, @intCast(i)); |
| 6523 | const field_align = if (explicit_align != .none) | ||
| 6524 | explicit_align | ||
| 6525 | else | ||
| 6767 | field_ty.toType().abiAlignment(mod); | 6526 | field_ty.toType().abiAlignment(mod); |
| 6768 | const field_size = field_ty.toType().abiSize(mod); | 6527 | const field_size = field_ty.toType().abiSize(mod); |
| 6769 | if (field_size > payload_size) { | 6528 | if (field_size > payload_size) { |
| 6770 | payload_size = field_size; | 6529 | payload_size = field_size; |
| 6771 | biggest_field = @intCast(i); | 6530 | biggest_field = @intCast(i); |
| 6772 | } | 6531 | } |
| 6773 | if (field_align > payload_align) { | 6532 | if (field_align.compare(.gte, payload_align)) { |
| 6774 | payload_align = @intCast(field_align); | 6533 | payload_align = field_align; |
| 6775 | most_aligned_field = @intCast(i); | 6534 | most_aligned_field = @intCast(i); |
| 6776 | most_aligned_field_size = field_size; | 6535 | most_aligned_field_size = field_size; |
| 6777 | } | 6536 | } |
| 6778 | } | 6537 | } |
| 6779 | payload_align = @max(payload_align, 1); | ||
| 6780 | const have_tag = u.flagsPtr(ip).runtime_tag.hasTag(); | 6538 | const have_tag = u.flagsPtr(ip).runtime_tag.hasTag(); |
| 6781 | if (!have_tag or !u.enum_tag_ty.toType().hasRuntimeBits(mod)) { | 6539 | if (!have_tag or !u.enum_tag_ty.toType().hasRuntimeBits(mod)) { |
| 6782 | return .{ | 6540 | return .{ |
| 6783 | .abi_size = std.mem.alignForward(u64, payload_size, payload_align), | 6541 | .abi_size = payload_align.forward(payload_size), |
| 6784 | .abi_align = payload_align, | 6542 | .abi_align = payload_align, |
| 6785 | .most_aligned_field = most_aligned_field, | 6543 | .most_aligned_field = most_aligned_field, |
| 6786 | .most_aligned_field_size = most_aligned_field_size, | 6544 | .most_aligned_field_size = most_aligned_field_size, |
| 6787 | .biggest_field = biggest_field, | 6545 | .biggest_field = biggest_field, |
| 6788 | .payload_size = payload_size, | 6546 | .payload_size = payload_size, |
| 6789 | .payload_align = payload_align, | 6547 | .payload_align = payload_align, |
| 6790 | .tag_align = 0, | 6548 | .tag_align = .none, |
| 6791 | .tag_size = 0, | 6549 | .tag_size = 0, |
| 6792 | .padding = 0, | 6550 | .padding = 0, |
| 6793 | }; | 6551 | }; |
| ... | @@ -6795,29 +6553,29 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout { | ... | @@ -6795,29 +6553,29 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout { |
| 6795 | // Put the tag before or after the payload depending on which one's | 6553 | // Put the tag before or after the payload depending on which one's |
| 6796 | // alignment is greater. | 6554 | // alignment is greater. |
| 6797 | const tag_size = u.enum_tag_ty.toType().abiSize(mod); | 6555 | const tag_size = u.enum_tag_ty.toType().abiSize(mod); |
| 6798 | const tag_align = @max(1, u.enum_tag_ty.toType().abiAlignment(mod)); | 6556 | const tag_align = u.enum_tag_ty.toType().abiAlignment(mod).max(.@"1"); |
| 6799 | var size: u64 = 0; | 6557 | var size: u64 = 0; |
| 6800 | var padding: u32 = undefined; | 6558 | var padding: u32 = undefined; |
| 6801 | if (tag_align >= payload_align) { | 6559 | if (tag_align.compare(.gte, payload_align)) { |
| 6802 | // {Tag, Payload} | 6560 | // {Tag, Payload} |
| 6803 | size += tag_size; | 6561 | size += tag_size; |
| 6804 | size = std.mem.alignForward(u64, size, payload_align); | 6562 | size = payload_align.forward(size); |
| 6805 | size += payload_size; | 6563 | size += payload_size; |
| 6806 | const prev_size = size; | 6564 | const prev_size = size; |
| 6807 | size = std.mem.alignForward(u64, size, tag_align); | 6565 | size = tag_align.forward(size); |
| 6808 | padding = @as(u32, @intCast(size - prev_size)); | 6566 | padding = @intCast(size - prev_size); |
| 6809 | } else { | 6567 | } else { |
| 6810 | // {Payload, Tag} | 6568 | // {Payload, Tag} |
| 6811 | size += payload_size; | 6569 | size += payload_size; |
| 6812 | size = std.mem.alignForward(u64, size, tag_align); | 6570 | size = tag_align.forward(size); |
| 6813 | size += tag_size; | 6571 | size += tag_size; |
| 6814 | const prev_size = size; | 6572 | const prev_size = size; |
| 6815 | size = std.mem.alignForward(u64, size, payload_align); | 6573 | size = payload_align.forward(size); |
| 6816 | padding = @as(u32, @intCast(size - prev_size)); | 6574 | padding = @intCast(size - prev_size); |
| 6817 | } | 6575 | } |
| 6818 | return .{ | 6576 | return .{ |
| 6819 | .abi_size = size, | 6577 | .abi_size = size, |
| 6820 | .abi_align = @max(tag_align, payload_align), | 6578 | .abi_align = tag_align.max(payload_align), |
| 6821 | .most_aligned_field = most_aligned_field, | 6579 | .most_aligned_field = most_aligned_field, |
| 6822 | .most_aligned_field_size = most_aligned_field_size, | 6580 | .most_aligned_field_size = most_aligned_field_size, |
| 6823 | .biggest_field = biggest_field, | 6581 | .biggest_field = biggest_field, |
| ... | @@ -6834,17 +6592,16 @@ pub fn unionAbiSize(mod: *Module, u: InternPool.UnionType) u64 { | ... | @@ -6834,17 +6592,16 @@ pub fn unionAbiSize(mod: *Module, u: InternPool.UnionType) u64 { |
| 6834 | } | 6592 | } |
| 6835 | 6593 | ||
| 6836 | /// Returns 0 if the union is represented with 0 bits at runtime. | 6594 | /// Returns 0 if the union is represented with 0 bits at runtime. |
| 6837 | /// TODO: this returns alignment in byte units should should be a u64 | 6595 | pub fn unionAbiAlignment(mod: *Module, u: InternPool.UnionType) Alignment { |
| 6838 | pub fn unionAbiAlignment(mod: *Module, u: InternPool.UnionType) u32 { | ||
| 6839 | const ip = &mod.intern_pool; | 6596 | const ip = &mod.intern_pool; |
| 6840 | const have_tag = u.flagsPtr(ip).runtime_tag.hasTag(); | 6597 | const have_tag = u.flagsPtr(ip).runtime_tag.hasTag(); |
| 6841 | var max_align: u32 = 0; | 6598 | var max_align: Alignment = .none; |
| 6842 | if (have_tag) max_align = u.enum_tag_ty.toType().abiAlignment(mod); | 6599 | if (have_tag) max_align = u.enum_tag_ty.toType().abiAlignment(mod); |
| 6843 | for (u.field_types.get(ip), 0..) |field_ty, field_index| { | 6600 | for (u.field_types.get(ip), 0..) |field_ty, field_index| { |
| 6844 | if (!field_ty.toType().hasRuntimeBits(mod)) continue; | 6601 | if (!field_ty.toType().hasRuntimeBits(mod)) continue; |
| 6845 | 6602 | ||
| 6846 | const field_align = mod.unionFieldNormalAlignment(u, @intCast(field_index)); | 6603 | const field_align = mod.unionFieldNormalAlignment(u, @intCast(field_index)); |
| 6847 | max_align = @max(max_align, field_align); | 6604 | max_align = max_align.max(field_align); |
| 6848 | } | 6605 | } |
| 6849 | return max_align; | 6606 | return max_align; |
| 6850 | } | 6607 | } |
| ... | @@ -6852,10 +6609,10 @@ pub fn unionAbiAlignment(mod: *Module, u: InternPool.UnionType) u32 { | ... | @@ -6852,10 +6609,10 @@ pub fn unionAbiAlignment(mod: *Module, u: InternPool.UnionType) u32 { |
| 6852 | /// Returns the field alignment, assuming the union is not packed. | 6609 | /// Returns the field alignment, assuming the union is not packed. |
| 6853 | /// Keep implementation in sync with `Sema.unionFieldAlignment`. | 6610 | /// Keep implementation in sync with `Sema.unionFieldAlignment`. |
| 6854 | /// Prefer to call that function instead of this one during Sema. | 6611 | /// Prefer to call that function instead of this one during Sema. |
| 6855 | /// TODO: this returns alignment in byte units should should be a u64 | 6612 | pub fn unionFieldNormalAlignment(mod: *Module, u: InternPool.UnionType, field_index: u32) Alignment { |
| 6856 | pub fn unionFieldNormalAlignment(mod: *Module, u: InternPool.UnionType, field_index: u32) u32 { | ||
| 6857 | const ip = &mod.intern_pool; | 6613 | const ip = &mod.intern_pool; |
| 6858 | if (u.fieldAlign(ip, field_index).toByteUnitsOptional()) |a| return @intCast(a); | 6614 | const field_align = u.fieldAlign(ip, field_index); |
| 6615 | if (field_align != .none) return field_align; | ||
| 6859 | const field_ty = u.field_types.get(ip)[field_index].toType(); | 6616 | const field_ty = u.field_types.get(ip)[field_index].toType(); |
| 6860 | return field_ty.abiAlignment(mod); | 6617 | return field_ty.abiAlignment(mod); |
| 6861 | } | 6618 | } |
| ... | @@ -6866,3 +6623,64 @@ pub fn unionTagFieldIndex(mod: *Module, u: InternPool.UnionType, enum_tag: Value | ... | @@ -6866,3 +6623,64 @@ pub fn unionTagFieldIndex(mod: *Module, u: InternPool.UnionType, enum_tag: Value |
| 6866 | const enum_type = ip.indexToKey(u.enum_tag_ty).enum_type; | 6623 | const enum_type = ip.indexToKey(u.enum_tag_ty).enum_type; |
| 6867 | return enum_type.tagValueIndex(ip, enum_tag.toIntern()); | 6624 | return enum_type.tagValueIndex(ip, enum_tag.toIntern()); |
| 6868 | } | 6625 | } |
| 6626 | |||
| 6627 | /// Returns the field alignment of a non-packed struct in byte units. | ||
| 6628 | /// Keep implementation in sync with `Sema.structFieldAlignment`. | ||
| 6629 | /// asserts the layout is not packed. | ||
| 6630 | pub fn structFieldAlignment( | ||
| 6631 | mod: *Module, | ||
| 6632 | explicit_alignment: InternPool.Alignment, | ||
| 6633 | field_ty: Type, | ||
| 6634 | layout: std.builtin.Type.ContainerLayout, | ||
| 6635 | ) Alignment { | ||
| 6636 | assert(layout != .Packed); | ||
| 6637 | if (explicit_alignment != .none) return explicit_alignment; | ||
| 6638 | switch (layout) { | ||
| 6639 | .Packed => unreachable, | ||
| 6640 | .Auto => { | ||
| 6641 | if (mod.getTarget().ofmt == .c) { | ||
| 6642 | return structFieldAlignmentExtern(mod, field_ty); | ||
| 6643 | } else { | ||
| 6644 | return field_ty.abiAlignment(mod); | ||
| 6645 | } | ||
| 6646 | }, | ||
| 6647 | .Extern => return structFieldAlignmentExtern(mod, field_ty), | ||
| 6648 | } | ||
| 6649 | } | ||
| 6650 | |||
| 6651 | /// Returns the field alignment of an extern struct in byte units. | ||
| 6652 | /// This logic is duplicated in Type.abiAlignmentAdvanced. | ||
| 6653 | pub fn structFieldAlignmentExtern(mod: *Module, field_ty: Type) Alignment { | ||
| 6654 | const ty_abi_align = field_ty.abiAlignment(mod); | ||
| 6655 | |||
| 6656 | if (field_ty.isAbiInt(mod) and field_ty.intInfo(mod).bits >= 128) { | ||
| 6657 | // The C ABI requires 128 bit integer fields of structs | ||
| 6658 | // to be 16-bytes aligned. | ||
| 6659 | return ty_abi_align.max(.@"16"); | ||
| 6660 | } | ||
| 6661 | |||
| 6662 | return ty_abi_align; | ||
| 6663 | } | ||
| 6664 | |||
| 6665 | /// TODO: avoid linear search by storing these in trailing data of packed struct types | ||
| 6666 | /// then packedStructFieldByteOffset can be expressed in terms of bits / 8, fixing | ||
| 6667 | /// that one too. | ||
| 6668 | /// https://github.com/ziglang/zig/issues/17178 | ||
| 6669 | pub fn structPackedFieldBitOffset( | ||
| 6670 | mod: *Module, | ||
| 6671 | struct_type: InternPool.Key.StructType, | ||
| 6672 | field_index: usize, | ||
| 6673 | ) u16 { | ||
| 6674 | const ip = &mod.intern_pool; | ||
| 6675 | assert(struct_type.layout == .Packed); | ||
| 6676 | assert(struct_type.haveLayout(ip)); | ||
| 6677 | var bit_sum: u64 = 0; | ||
| 6678 | for (0..struct_type.field_types.len) |i| { | ||
| 6679 | if (i == field_index) { | ||
| 6680 | return @intCast(bit_sum); | ||
| 6681 | } | ||
| 6682 | const field_ty = struct_type.field_types.get(ip)[i].toType(); | ||
| 6683 | bit_sum += field_ty.bitSize(mod); | ||
| 6684 | } | ||
| 6685 | unreachable; // index out of bounds | ||
| 6686 | } |
src/Sema.zig+744-667| ... | @@ -2221,8 +2221,8 @@ fn failWithInvalidComptimeFieldStore(sema: *Sema, block: *Block, init_src: LazyS | ... | @@ -2221,8 +2221,8 @@ fn failWithInvalidComptimeFieldStore(sema: *Sema, block: *Block, init_src: LazyS |
| 2221 | const msg = try sema.errMsg(block, init_src, "value stored in comptime field does not match the default value of the field", .{}); | 2221 | const msg = try sema.errMsg(block, init_src, "value stored in comptime field does not match the default value of the field", .{}); |
| 2222 | errdefer msg.destroy(sema.gpa); | 2222 | errdefer msg.destroy(sema.gpa); |
| 2223 | 2223 | ||
| 2224 | const struct_ty = mod.typeToStruct(container_ty) orelse break :msg msg; | 2224 | const struct_type = mod.typeToStruct(container_ty) orelse break :msg msg; |
| 2225 | const default_value_src = mod.fieldSrcLoc(struct_ty.owner_decl, .{ | 2225 | const default_value_src = mod.fieldSrcLoc(struct_type.decl.unwrap().?, .{ |
| 2226 | .index = field_index, | 2226 | .index = field_index, |
| 2227 | .range = .value, | 2227 | .range = .value, |
| 2228 | }); | 2228 | }); |
| ... | @@ -2504,23 +2504,22 @@ fn analyzeAsAlign( | ... | @@ -2504,23 +2504,22 @@ fn analyzeAsAlign( |
| 2504 | const alignment_big = try sema.analyzeAsInt(block, src, air_ref, align_ty, .{ | 2504 | const alignment_big = try sema.analyzeAsInt(block, src, air_ref, align_ty, .{ |
| 2505 | .needed_comptime_reason = "alignment must be comptime-known", | 2505 | .needed_comptime_reason = "alignment must be comptime-known", |
| 2506 | }); | 2506 | }); |
| 2507 | const alignment: u32 = @intCast(alignment_big); // We coerce to u29 in the prev line. | 2507 | return sema.validateAlign(block, src, alignment_big); |
| 2508 | try sema.validateAlign(block, src, alignment); | ||
| 2509 | return Alignment.fromNonzeroByteUnits(alignment); | ||
| 2510 | } | 2508 | } |
| 2511 | 2509 | ||
| 2512 | fn validateAlign( | 2510 | fn validateAlign( |
| 2513 | sema: *Sema, | 2511 | sema: *Sema, |
| 2514 | block: *Block, | 2512 | block: *Block, |
| 2515 | src: LazySrcLoc, | 2513 | src: LazySrcLoc, |
| 2516 | alignment: u32, | 2514 | alignment: u64, |
| 2517 | ) !void { | 2515 | ) !Alignment { |
| 2518 | if (alignment == 0) return sema.fail(block, src, "alignment must be >= 1", .{}); | 2516 | if (alignment == 0) return sema.fail(block, src, "alignment must be >= 1", .{}); |
| 2519 | if (!std.math.isPowerOfTwo(alignment)) { | 2517 | if (!std.math.isPowerOfTwo(alignment)) { |
| 2520 | return sema.fail(block, src, "alignment value '{d}' is not a power of two", .{ | 2518 | return sema.fail(block, src, "alignment value '{d}' is not a power of two", .{ |
| 2521 | alignment, | 2519 | alignment, |
| 2522 | }); | 2520 | }); |
| 2523 | } | 2521 | } |
| 2522 | return Alignment.fromNonzeroByteUnits(alignment); | ||
| 2524 | } | 2523 | } |
| 2525 | 2524 | ||
| 2526 | pub fn resolveAlign( | 2525 | pub fn resolveAlign( |
| ... | @@ -2801,26 +2800,26 @@ fn coerceResultPtr( | ... | @@ -2801,26 +2800,26 @@ fn coerceResultPtr( |
| 2801 | } | 2800 | } |
| 2802 | } | 2801 | } |
| 2803 | 2802 | ||
| 2804 | pub fn analyzeStructDecl( | 2803 | pub fn getStructType( |
| 2805 | sema: *Sema, | 2804 | sema: *Sema, |
| 2806 | new_decl: *Decl, | 2805 | decl: Module.Decl.Index, |
| 2807 | inst: Zir.Inst.Index, | 2806 | namespace: Module.Namespace.Index, |
| 2808 | struct_index: Module.Struct.Index, | 2807 | zir_index: Zir.Inst.Index, |
| 2809 | ) SemaError!void { | 2808 | ) !InternPool.Index { |
| 2810 | const mod = sema.mod; | 2809 | const mod = sema.mod; |
| 2811 | const struct_obj = mod.structPtr(struct_index); | 2810 | const gpa = sema.gpa; |
| 2812 | const extended = sema.code.instructions.items(.data)[inst].extended; | 2811 | const ip = &mod.intern_pool; |
| 2812 | const extended = sema.code.instructions.items(.data)[zir_index].extended; | ||
| 2813 | assert(extended.opcode == .struct_decl); | 2813 | assert(extended.opcode == .struct_decl); |
| 2814 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); | 2814 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); |
| 2815 | 2815 | ||
| 2816 | struct_obj.known_non_opv = small.known_non_opv; | ||
| 2817 | if (small.known_comptime_only) { | ||
| 2818 | struct_obj.requires_comptime = .yes; | ||
| 2819 | } | ||
| 2820 | |||
| 2821 | var extra_index: usize = extended.operand; | 2816 | var extra_index: usize = extended.operand; |
| 2822 | extra_index += @intFromBool(small.has_src_node); | 2817 | extra_index += @intFromBool(small.has_src_node); |
| 2823 | extra_index += @intFromBool(small.has_fields_len); | 2818 | const fields_len = if (small.has_fields_len) blk: { |
| 2819 | const fields_len = sema.code.extra[extra_index]; | ||
| 2820 | extra_index += 1; | ||
| 2821 | break :blk fields_len; | ||
| 2822 | } else 0; | ||
| 2824 | const decls_len = if (small.has_decls_len) blk: { | 2823 | const decls_len = if (small.has_decls_len) blk: { |
| 2825 | const decls_len = sema.code.extra[extra_index]; | 2824 | const decls_len = sema.code.extra[extra_index]; |
| 2826 | extra_index += 1; | 2825 | extra_index += 1; |
| ... | @@ -2837,7 +2836,20 @@ pub fn analyzeStructDecl( | ... | @@ -2837,7 +2836,20 @@ pub fn analyzeStructDecl( |
| 2837 | } | 2836 | } |
| 2838 | } | 2837 | } |
| 2839 | 2838 | ||
| 2840 | _ = try mod.scanNamespace(struct_obj.namespace, extra_index, decls_len, new_decl); | 2839 | extra_index = try mod.scanNamespace(namespace, extra_index, decls_len, mod.declPtr(decl)); |
| 2840 | |||
| 2841 | const ty = try ip.getStructType(gpa, .{ | ||
| 2842 | .decl = decl, | ||
| 2843 | .namespace = namespace.toOptional(), | ||
| 2844 | .zir_index = zir_index, | ||
| 2845 | .layout = small.layout, | ||
| 2846 | .known_non_opv = small.known_non_opv, | ||
| 2847 | .is_tuple = small.is_tuple, | ||
| 2848 | .fields_len = fields_len, | ||
| 2849 | .requires_comptime = if (small.known_comptime_only) .yes else .unknown, | ||
| 2850 | }); | ||
| 2851 | |||
| 2852 | return ty; | ||
| 2841 | } | 2853 | } |
| 2842 | 2854 | ||
| 2843 | fn zirStructDecl( | 2855 | fn zirStructDecl( |
| ... | @@ -2847,7 +2859,7 @@ fn zirStructDecl( | ... | @@ -2847,7 +2859,7 @@ fn zirStructDecl( |
| 2847 | inst: Zir.Inst.Index, | 2859 | inst: Zir.Inst.Index, |
| 2848 | ) CompileError!Air.Inst.Ref { | 2860 | ) CompileError!Air.Inst.Ref { |
| 2849 | const mod = sema.mod; | 2861 | const mod = sema.mod; |
| 2850 | const gpa = sema.gpa; | 2862 | const ip = &mod.intern_pool; |
| 2851 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); | 2863 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); |
| 2852 | const src: LazySrcLoc = if (small.has_src_node) blk: { | 2864 | const src: LazySrcLoc = if (small.has_src_node) blk: { |
| 2853 | const node_offset: i32 = @bitCast(sema.code.extra[extended.operand]); | 2865 | const node_offset: i32 = @bitCast(sema.code.extra[extended.operand]); |
| ... | @@ -2874,37 +2886,21 @@ fn zirStructDecl( | ... | @@ -2874,37 +2886,21 @@ fn zirStructDecl( |
| 2874 | const new_namespace = mod.namespacePtr(new_namespace_index); | 2886 | const new_namespace = mod.namespacePtr(new_namespace_index); |
| 2875 | errdefer mod.destroyNamespace(new_namespace_index); | 2887 | errdefer mod.destroyNamespace(new_namespace_index); |
| 2876 | 2888 | ||
| 2877 | const struct_index = try mod.createStruct(.{ | ||
| 2878 | .owner_decl = new_decl_index, | ||
| 2879 | .fields = .{}, | ||
| 2880 | .zir_index = inst, | ||
| 2881 | .layout = small.layout, | ||
| 2882 | .status = .none, | ||
| 2883 | .known_non_opv = undefined, | ||
| 2884 | .is_tuple = small.is_tuple, | ||
| 2885 | .namespace = new_namespace_index, | ||
| 2886 | }); | ||
| 2887 | errdefer mod.destroyStruct(struct_index); | ||
| 2888 | |||
| 2889 | const struct_ty = ty: { | 2889 | const struct_ty = ty: { |
| 2890 | const ty = try mod.intern_pool.get(gpa, .{ .struct_type = .{ | 2890 | const ty = try sema.getStructType(new_decl_index, new_namespace_index, inst); |
| 2891 | .index = struct_index.toOptional(), | ||
| 2892 | .namespace = new_namespace_index.toOptional(), | ||
| 2893 | } }); | ||
| 2894 | if (sema.builtin_type_target_index != .none) { | 2891 | if (sema.builtin_type_target_index != .none) { |
| 2895 | mod.intern_pool.resolveBuiltinType(sema.builtin_type_target_index, ty); | 2892 | ip.resolveBuiltinType(sema.builtin_type_target_index, ty); |
| 2896 | break :ty sema.builtin_type_target_index; | 2893 | break :ty sema.builtin_type_target_index; |
| 2897 | } | 2894 | } |
| 2898 | break :ty ty; | 2895 | break :ty ty; |
| 2899 | }; | 2896 | }; |
| 2900 | // TODO: figure out InternPool removals for incremental compilation | 2897 | // TODO: figure out InternPool removals for incremental compilation |
| 2901 | //errdefer mod.intern_pool.remove(struct_ty); | 2898 | //errdefer ip.remove(struct_ty); |
| 2902 | 2899 | ||
| 2903 | new_decl.ty = Type.type; | 2900 | new_decl.ty = Type.type; |
| 2904 | new_decl.val = struct_ty.toValue(); | 2901 | new_decl.val = struct_ty.toValue(); |
| 2905 | new_namespace.ty = struct_ty.toType(); | 2902 | new_namespace.ty = struct_ty.toType(); |
| 2906 | 2903 | ||
| 2907 | try sema.analyzeStructDecl(new_decl, inst, struct_index); | ||
| 2908 | const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); | 2904 | const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); |
| 2909 | try mod.finalizeAnonDecl(new_decl_index); | 2905 | try mod.finalizeAnonDecl(new_decl_index); |
| 2910 | return decl_val; | 2906 | return decl_val; |
| ... | @@ -3196,7 +3192,7 @@ fn zirEnumDecl( | ... | @@ -3196,7 +3192,7 @@ fn zirEnumDecl( |
| 3196 | extra_index += 1; | 3192 | extra_index += 1; |
| 3197 | 3193 | ||
| 3198 | const field_name = try mod.intern_pool.getOrPutString(gpa, field_name_zir); | 3194 | const field_name = try mod.intern_pool.getOrPutString(gpa, field_name_zir); |
| 3199 | if (try incomplete_enum.addFieldName(&mod.intern_pool, gpa, field_name)) |other_index| { | 3195 | if (incomplete_enum.addFieldName(&mod.intern_pool, field_name)) |other_index| { |
| 3200 | const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy; | 3196 | const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy; |
| 3201 | const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy; | 3197 | const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy; |
| 3202 | const msg = msg: { | 3198 | const msg = msg: { |
| ... | @@ -3227,7 +3223,7 @@ fn zirEnumDecl( | ... | @@ -3227,7 +3223,7 @@ fn zirEnumDecl( |
| 3227 | }; | 3223 | }; |
| 3228 | if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) break :overflow true; | 3224 | if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) break :overflow true; |
| 3229 | last_tag_val = try mod.getCoerced(last_tag_val.?, int_tag_ty); | 3225 | last_tag_val = try mod.getCoerced(last_tag_val.?, int_tag_ty); |
| 3230 | if (try incomplete_enum.addFieldValue(&mod.intern_pool, gpa, last_tag_val.?.toIntern())) |other_index| { | 3226 | if (incomplete_enum.addFieldValue(&mod.intern_pool, last_tag_val.?.toIntern())) |other_index| { |
| 3231 | const value_src = mod.fieldSrcLoc(new_decl_index, .{ | 3227 | const value_src = mod.fieldSrcLoc(new_decl_index, .{ |
| 3232 | .index = field_i, | 3228 | .index = field_i, |
| 3233 | .range = .value, | 3229 | .range = .value, |
| ... | @@ -3249,7 +3245,7 @@ fn zirEnumDecl( | ... | @@ -3249,7 +3245,7 @@ fn zirEnumDecl( |
| 3249 | else | 3245 | else |
| 3250 | try mod.intValue(int_tag_ty, 0); | 3246 | try mod.intValue(int_tag_ty, 0); |
| 3251 | if (overflow != null) break :overflow true; | 3247 | if (overflow != null) break :overflow true; |
| 3252 | if (try incomplete_enum.addFieldValue(&mod.intern_pool, gpa, last_tag_val.?.toIntern())) |other_index| { | 3248 | if (incomplete_enum.addFieldValue(&mod.intern_pool, last_tag_val.?.toIntern())) |other_index| { |
| 3253 | const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy; | 3249 | const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy; |
| 3254 | const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy; | 3250 | const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy; |
| 3255 | const msg = msg: { | 3251 | const msg = msg: { |
| ... | @@ -4723,10 +4719,11 @@ fn validateStructInit( | ... | @@ -4723,10 +4719,11 @@ fn validateStructInit( |
| 4723 | } | 4719 | } |
| 4724 | 4720 | ||
| 4725 | if (root_msg) |msg| { | 4721 | if (root_msg) |msg| { |
| 4726 | if (mod.typeToStruct(struct_ty)) |struct_obj| { | 4722 | if (mod.typeToStruct(struct_ty)) |struct_type| { |
| 4727 | const fqn = try struct_obj.getFullyQualifiedName(mod); | 4723 | const decl = mod.declPtr(struct_type.decl.unwrap().?); |
| 4724 | const fqn = try decl.getFullyQualifiedName(mod); | ||
| 4728 | try mod.errNoteNonLazy( | 4725 | try mod.errNoteNonLazy( |
| 4729 | struct_obj.srcLoc(mod), | 4726 | decl.srcLoc(mod), |
| 4730 | msg, | 4727 | msg, |
| 4731 | "struct '{}' declared here", | 4728 | "struct '{}' declared here", |
| 4732 | .{fqn.fmt(ip)}, | 4729 | .{fqn.fmt(ip)}, |
| ... | @@ -4853,10 +4850,11 @@ fn validateStructInit( | ... | @@ -4853,10 +4850,11 @@ fn validateStructInit( |
| 4853 | } | 4850 | } |
| 4854 | 4851 | ||
| 4855 | if (root_msg) |msg| { | 4852 | if (root_msg) |msg| { |
| 4856 | if (mod.typeToStruct(struct_ty)) |struct_obj| { | 4853 | if (mod.typeToStruct(struct_ty)) |struct_type| { |
| 4857 | const fqn = try struct_obj.getFullyQualifiedName(mod); | 4854 | const decl = mod.declPtr(struct_type.decl.unwrap().?); |
| 4855 | const fqn = try decl.getFullyQualifiedName(mod); | ||
| 4858 | try mod.errNoteNonLazy( | 4856 | try mod.errNoteNonLazy( |
| 4859 | struct_obj.srcLoc(mod), | 4857 | decl.srcLoc(mod), |
| 4860 | msg, | 4858 | msg, |
| 4861 | "struct '{}' declared here", | 4859 | "struct '{}' declared here", |
| 4862 | .{fqn.fmt(ip)}, | 4860 | .{fqn.fmt(ip)}, |
| ... | @@ -5255,14 +5253,14 @@ fn failWithBadMemberAccess( | ... | @@ -5255,14 +5253,14 @@ fn failWithBadMemberAccess( |
| 5255 | fn failWithBadStructFieldAccess( | 5253 | fn failWithBadStructFieldAccess( |
| 5256 | sema: *Sema, | 5254 | sema: *Sema, |
| 5257 | block: *Block, | 5255 | block: *Block, |
| 5258 | struct_obj: *Module.Struct, | 5256 | struct_type: InternPool.Key.StructType, |
| 5259 | field_src: LazySrcLoc, | 5257 | field_src: LazySrcLoc, |
| 5260 | field_name: InternPool.NullTerminatedString, | 5258 | field_name: InternPool.NullTerminatedString, |
| 5261 | ) CompileError { | 5259 | ) CompileError { |
| 5262 | const mod = sema.mod; | 5260 | const mod = sema.mod; |
| 5263 | const gpa = sema.gpa; | 5261 | const gpa = sema.gpa; |
| 5264 | 5262 | const decl = mod.declPtr(struct_type.decl.unwrap().?); | |
| 5265 | const fqn = try struct_obj.getFullyQualifiedName(mod); | 5263 | const fqn = try decl.getFullyQualifiedName(mod); |
| 5266 | 5264 | ||
| 5267 | const msg = msg: { | 5265 | const msg = msg: { |
| 5268 | const msg = try sema.errMsg( | 5266 | const msg = try sema.errMsg( |
| ... | @@ -5272,7 +5270,7 @@ fn failWithBadStructFieldAccess( | ... | @@ -5272,7 +5270,7 @@ fn failWithBadStructFieldAccess( |
| 5272 | .{ field_name.fmt(&mod.intern_pool), fqn.fmt(&mod.intern_pool) }, | 5270 | .{ field_name.fmt(&mod.intern_pool), fqn.fmt(&mod.intern_pool) }, |
| 5273 | ); | 5271 | ); |
| 5274 | errdefer msg.destroy(gpa); | 5272 | errdefer msg.destroy(gpa); |
| 5275 | try mod.errNoteNonLazy(struct_obj.srcLoc(mod), msg, "struct declared here", .{}); | 5273 | try mod.errNoteNonLazy(decl.srcLoc(mod), msg, "struct declared here", .{}); |
| 5276 | break :msg msg; | 5274 | break :msg msg; |
| 5277 | }; | 5275 | }; |
| 5278 | return sema.failWithOwnedErrorMsg(block, msg); | 5276 | return sema.failWithOwnedErrorMsg(block, msg); |
| ... | @@ -12953,9 +12951,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -12953,9 +12951,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 12953 | } | 12951 | } |
| 12954 | }, | 12952 | }, |
| 12955 | .struct_type => |struct_type| { | 12953 | .struct_type => |struct_type| { |
| 12956 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :hf false; | 12954 | break :hf struct_type.nameIndex(ip, field_name) != null; |
| 12957 | assert(struct_obj.haveFieldTypes()); | ||
| 12958 | break :hf struct_obj.fields.contains(field_name); | ||
| 12959 | }, | 12955 | }, |
| 12960 | .union_type => |union_type| { | 12956 | .union_type => |union_type| { |
| 12961 | const union_obj = ip.loadUnionType(union_type); | 12957 | const union_obj = ip.loadUnionType(union_type); |
| ... | @@ -16907,7 +16903,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -16907,7 +16903,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16907 | // calling_convention: CallingConvention, | 16903 | // calling_convention: CallingConvention, |
| 16908 | (try mod.enumValueFieldIndex(callconv_ty, @intFromEnum(func_ty_info.cc))).toIntern(), | 16904 | (try mod.enumValueFieldIndex(callconv_ty, @intFromEnum(func_ty_info.cc))).toIntern(), |
| 16909 | // alignment: comptime_int, | 16905 | // alignment: comptime_int, |
| 16910 | (try mod.intValue(Type.comptime_int, ty.abiAlignment(mod))).toIntern(), | 16906 | (try mod.intValue(Type.comptime_int, ty.abiAlignment(mod).toByteUnits(0))).toIntern(), |
| 16911 | // is_generic: bool, | 16907 | // is_generic: bool, |
| 16912 | Value.makeBool(func_ty_info.is_generic).toIntern(), | 16908 | Value.makeBool(func_ty_info.is_generic).toIntern(), |
| 16913 | // is_var_args: bool, | 16909 | // is_var_args: bool, |
| ... | @@ -17461,7 +17457,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -17461,7 +17457,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17461 | 17457 | ||
| 17462 | const alignment = switch (layout) { | 17458 | const alignment = switch (layout) { |
| 17463 | .Auto, .Extern => try sema.unionFieldAlignment(union_obj, @intCast(i)), | 17459 | .Auto, .Extern => try sema.unionFieldAlignment(union_obj, @intCast(i)), |
| 17464 | .Packed => 0, | 17460 | .Packed => .none, |
| 17465 | }; | 17461 | }; |
| 17466 | 17462 | ||
| 17467 | const field_ty = union_obj.field_types.get(ip)[i]; | 17463 | const field_ty = union_obj.field_types.get(ip)[i]; |
| ... | @@ -17471,7 +17467,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -17471,7 +17467,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17471 | // type: type, | 17467 | // type: type, |
| 17472 | field_ty, | 17468 | field_ty, |
| 17473 | // alignment: comptime_int, | 17469 | // alignment: comptime_int, |
| 17474 | (try mod.intValue(Type.comptime_int, alignment)).toIntern(), | 17470 | (try mod.intValue(Type.comptime_int, alignment.toByteUnits(0))).toIntern(), |
| 17475 | }; | 17471 | }; |
| 17476 | field_val.* = try mod.intern(.{ .aggregate = .{ | 17472 | field_val.* = try mod.intern(.{ .aggregate = .{ |
| 17477 | .ty = union_field_ty.toIntern(), | 17473 | .ty = union_field_ty.toIntern(), |
| ... | @@ -17578,7 +17574,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -17578,7 +17574,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17578 | }; | 17574 | }; |
| 17579 | 17575 | ||
| 17580 | try sema.resolveTypeLayout(ty); // Getting alignment requires type layout | 17576 | try sema.resolveTypeLayout(ty); // Getting alignment requires type layout |
| 17581 | const layout = ty.containerLayout(mod); | ||
| 17582 | 17577 | ||
| 17583 | var struct_field_vals: []InternPool.Index = &.{}; | 17578 | var struct_field_vals: []InternPool.Index = &.{}; |
| 17584 | defer gpa.free(struct_field_vals); | 17579 | defer gpa.free(struct_field_vals); |
| ... | @@ -17633,7 +17628,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -17633,7 +17628,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17633 | // is_comptime: bool, | 17628 | // is_comptime: bool, |
| 17634 | Value.makeBool(is_comptime).toIntern(), | 17629 | Value.makeBool(is_comptime).toIntern(), |
| 17635 | // alignment: comptime_int, | 17630 | // alignment: comptime_int, |
| 17636 | (try mod.intValue(Type.comptime_int, field_ty.toType().abiAlignment(mod))).toIntern(), | 17631 | (try mod.intValue(Type.comptime_int, field_ty.toType().abiAlignment(mod).toByteUnits(0))).toIntern(), |
| 17637 | }; | 17632 | }; |
| 17638 | struct_field_val.* = try mod.intern(.{ .aggregate = .{ | 17633 | struct_field_val.* = try mod.intern(.{ .aggregate = .{ |
| 17639 | .ty = struct_field_ty.toIntern(), | 17634 | .ty = struct_field_ty.toIntern(), |
| ... | @@ -17645,14 +17640,13 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -17645,14 +17640,13 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17645 | .struct_type => |s| s, | 17640 | .struct_type => |s| s, |
| 17646 | else => unreachable, | 17641 | else => unreachable, |
| 17647 | }; | 17642 | }; |
| 17648 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :fv; | 17643 | struct_field_vals = try gpa.alloc(InternPool.Index, struct_type.field_types.len); |
| 17649 | struct_field_vals = try gpa.alloc(InternPool.Index, struct_obj.fields.count()); | 17644 | |
| 17650 | 17645 | for (struct_field_vals, 0..) |*field_val, i| { | |
| 17651 | for ( | 17646 | const name_nts = struct_type.fieldName(ip, i).unwrap().?; |
| 17652 | struct_field_vals, | 17647 | const field_ty = struct_type.field_types.get(ip)[i].toType(); |
| 17653 | struct_obj.fields.keys(), | 17648 | const field_init = struct_type.fieldInit(ip, i); |
| 17654 | struct_obj.fields.values(), | 17649 | const field_is_comptime = struct_type.fieldIsComptime(ip, i); |
| 17655 | ) |*field_val, name_nts, field| { | ||
| 17656 | // TODO: write something like getCoercedInts to avoid needing to dupe | 17650 | // TODO: write something like getCoercedInts to avoid needing to dupe |
| 17657 | const name = try sema.arena.dupe(u8, ip.stringToSlice(name_nts)); | 17651 | const name = try sema.arena.dupe(u8, ip.stringToSlice(name_nts)); |
| 17658 | const name_val = v: { | 17652 | const name_val = v: { |
| ... | @@ -17677,24 +17671,25 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -17677,24 +17671,25 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17677 | } }); | 17671 | } }); |
| 17678 | }; | 17672 | }; |
| 17679 | 17673 | ||
| 17680 | const opt_default_val = if (field.default_val == .none) | 17674 | const opt_default_val = if (field_init == .none) null else field_init.toValue(); |
| 17681 | null | 17675 | const default_val_ptr = try sema.optRefValue(block, field_ty, opt_default_val); |
| 17682 | else | 17676 | const alignment = mod.structFieldAlignment( |
| 17683 | field.default_val.toValue(); | 17677 | struct_type.field_aligns.get(ip)[i], |
| 17684 | const default_val_ptr = try sema.optRefValue(block, field.ty, opt_default_val); | 17678 | field_ty, |
| 17685 | const alignment = field.alignment(mod, layout); | 17679 | struct_type.layout, |
| 17680 | ); | ||
| 17686 | 17681 | ||
| 17687 | const struct_field_fields = .{ | 17682 | const struct_field_fields = .{ |
| 17688 | // name: []const u8, | 17683 | // name: []const u8, |
| 17689 | name_val, | 17684 | name_val, |
| 17690 | // type: type, | 17685 | // type: type, |
| 17691 | field.ty.toIntern(), | 17686 | field_ty.toIntern(), |
| 17692 | // default_value: ?*const anyopaque, | 17687 | // default_value: ?*const anyopaque, |
| 17693 | default_val_ptr.toIntern(), | 17688 | default_val_ptr.toIntern(), |
| 17694 | // is_comptime: bool, | 17689 | // is_comptime: bool, |
| 17695 | Value.makeBool(field.is_comptime).toIntern(), | 17690 | Value.makeBool(field_is_comptime).toIntern(), |
| 17696 | // alignment: comptime_int, | 17691 | // alignment: comptime_int, |
| 17697 | (try mod.intValue(Type.comptime_int, alignment)).toIntern(), | 17692 | (try mod.intValue(Type.comptime_int, alignment.toByteUnits(0))).toIntern(), |
| 17698 | }; | 17693 | }; |
| 17699 | field_val.* = try mod.intern(.{ .aggregate = .{ | 17694 | field_val.* = try mod.intern(.{ .aggregate = .{ |
| 17700 | .ty = struct_field_ty.toIntern(), | 17695 | .ty = struct_field_ty.toIntern(), |
| ... | @@ -17733,11 +17728,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -17733,11 +17728,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17733 | 17728 | ||
| 17734 | const backing_integer_val = try mod.intern(.{ .opt = .{ | 17729 | const backing_integer_val = try mod.intern(.{ .opt = .{ |
| 17735 | .ty = (try mod.optionalType(.type_type)).toIntern(), | 17730 | .ty = (try mod.optionalType(.type_type)).toIntern(), |
| 17736 | .val = if (layout == .Packed) val: { | 17731 | .val = if (mod.typeToPackedStruct(ty)) |packed_struct| val: { |
| 17737 | const struct_obj = mod.typeToStruct(ty).?; | 17732 | assert(packed_struct.backingIntType(ip).toType().isInt(mod)); |
| 17738 | assert(struct_obj.haveLayout()); | 17733 | break :val packed_struct.backingIntType(ip).*; |
| 17739 | assert(struct_obj.backing_int_ty.isInt(mod)); | ||
| 17740 | break :val struct_obj.backing_int_ty.toIntern(); | ||
| 17741 | } else .none, | 17734 | } else .none, |
| 17742 | } }); | 17735 | } }); |
| 17743 | 17736 | ||
| ... | @@ -17754,6 +17747,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -17754,6 +17747,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17754 | break :t decl.val.toType(); | 17747 | break :t decl.val.toType(); |
| 17755 | }; | 17748 | }; |
| 17756 | 17749 | ||
| 17750 | const layout = ty.containerLayout(mod); | ||
| 17751 | |||
| 17757 | const field_values = [_]InternPool.Index{ | 17752 | const field_values = [_]InternPool.Index{ |
| 17758 | // layout: ContainerLayout, | 17753 | // layout: ContainerLayout, |
| 17759 | (try mod.enumValueFieldIndex(container_layout_ty, @intFromEnum(layout))).toIntern(), | 17754 | (try mod.enumValueFieldIndex(container_layout_ty, @intFromEnum(layout))).toIntern(), |
| ... | @@ -18924,9 +18919,8 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -18924,9 +18919,8 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 18924 | }, | 18919 | }, |
| 18925 | else => {}, | 18920 | else => {}, |
| 18926 | } | 18921 | } |
| 18927 | const abi_align: u32 = @intCast((try val.getUnsignedIntAdvanced(mod, sema)).?); | 18922 | const align_bytes = (try val.getUnsignedIntAdvanced(mod, sema)).?; |
| 18928 | try sema.validateAlign(block, align_src, abi_align); | 18923 | break :blk try sema.validateAlign(block, align_src, align_bytes); |
| 18929 | break :blk Alignment.fromByteUnits(abi_align); | ||
| 18930 | } else .none; | 18924 | } else .none; |
| 18931 | 18925 | ||
| 18932 | const address_space: std.builtin.AddressSpace = if (inst_data.flags.has_addrspace) blk: { | 18926 | const address_space: std.builtin.AddressSpace = if (inst_data.flags.has_addrspace) blk: { |
| ... | @@ -19291,12 +19285,12 @@ fn finishStructInit( | ... | @@ -19291,12 +19285,12 @@ fn finishStructInit( |
| 19291 | } | 19285 | } |
| 19292 | }, | 19286 | }, |
| 19293 | .struct_type => |struct_type| { | 19287 | .struct_type => |struct_type| { |
| 19294 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | 19288 | for (0..struct_type.field_types.len) |i| { |
| 19295 | for (struct_obj.fields.values(), 0..) |field, i| { | ||
| 19296 | if (field_inits[i] != .none) continue; | 19289 | if (field_inits[i] != .none) continue; |
| 19297 | 19290 | ||
| 19298 | if (field.default_val == .none) { | 19291 | const field_init = struct_type.field_inits.get(ip)[i]; |
| 19299 | const field_name = struct_obj.fields.keys()[i]; | 19292 | if (field_init == .none) { |
| 19293 | const field_name = struct_type.field_names.get(ip)[i]; | ||
| 19300 | const template = "missing struct field: {}"; | 19294 | const template = "missing struct field: {}"; |
| 19301 | const args = .{field_name.fmt(ip)}; | 19295 | const args = .{field_name.fmt(ip)}; |
| 19302 | if (root_msg) |msg| { | 19296 | if (root_msg) |msg| { |
| ... | @@ -19305,7 +19299,7 @@ fn finishStructInit( | ... | @@ -19305,7 +19299,7 @@ fn finishStructInit( |
| 19305 | root_msg = try sema.errMsg(block, init_src, template, args); | 19299 | root_msg = try sema.errMsg(block, init_src, template, args); |
| 19306 | } | 19300 | } |
| 19307 | } else { | 19301 | } else { |
| 19308 | field_inits[i] = Air.internedToRef(field.default_val); | 19302 | field_inits[i] = Air.internedToRef(field_init); |
| 19309 | } | 19303 | } |
| 19310 | } | 19304 | } |
| 19311 | }, | 19305 | }, |
| ... | @@ -19313,10 +19307,11 @@ fn finishStructInit( | ... | @@ -19313,10 +19307,11 @@ fn finishStructInit( |
| 19313 | } | 19307 | } |
| 19314 | 19308 | ||
| 19315 | if (root_msg) |msg| { | 19309 | if (root_msg) |msg| { |
| 19316 | if (mod.typeToStruct(struct_ty)) |struct_obj| { | 19310 | if (mod.typeToStruct(struct_ty)) |struct_type| { |
| 19317 | const fqn = try struct_obj.getFullyQualifiedName(mod); | 19311 | const decl = mod.declPtr(struct_type.decl.unwrap().?); |
| 19312 | const fqn = try decl.getFullyQualifiedName(mod); | ||
| 19318 | try mod.errNoteNonLazy( | 19313 | try mod.errNoteNonLazy( |
| 19319 | struct_obj.srcLoc(mod), | 19314 | decl.srcLoc(mod), |
| 19320 | msg, | 19315 | msg, |
| 19321 | "struct '{}' declared here", | 19316 | "struct '{}' declared here", |
| 19322 | .{fqn.fmt(ip)}, | 19317 | .{fqn.fmt(ip)}, |
| ... | @@ -19848,10 +19843,10 @@ fn fieldType( | ... | @@ -19848,10 +19843,10 @@ fn fieldType( |
| 19848 | return Air.internedToRef(anon_struct.types.get(ip)[field_index]); | 19843 | return Air.internedToRef(anon_struct.types.get(ip)[field_index]); |
| 19849 | }, | 19844 | }, |
| 19850 | .struct_type => |struct_type| { | 19845 | .struct_type => |struct_type| { |
| 19851 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | 19846 | const field_index = struct_type.nameIndex(ip, field_name) orelse |
| 19852 | const field = struct_obj.fields.get(field_name) orelse | 19847 | return sema.failWithBadStructFieldAccess(block, struct_type, field_src, field_name); |
| 19853 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name); | 19848 | const field_ty = struct_type.field_types.get(ip)[field_index]; |
| 19854 | return Air.internedToRef(field.ty.toIntern()); | 19849 | return Air.internedToRef(field_ty); |
| 19855 | }, | 19850 | }, |
| 19856 | else => unreachable, | 19851 | else => unreachable, |
| 19857 | }, | 19852 | }, |
| ... | @@ -20167,14 +20162,14 @@ fn zirReify( | ... | @@ -20167,14 +20162,14 @@ fn zirReify( |
| 20167 | .AnyFrame => return sema.failWithUseOfAsync(block, src), | 20162 | .AnyFrame => return sema.failWithUseOfAsync(block, src), |
| 20168 | .EnumLiteral => return .enum_literal_type, | 20163 | .EnumLiteral => return .enum_literal_type, |
| 20169 | .Int => { | 20164 | .Int => { |
| 20170 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | 20165 | const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type; |
| 20171 | const signedness_val = try union_val.val.toValue().fieldValue( | 20166 | const signedness_val = try union_val.val.toValue().fieldValue( |
| 20172 | mod, | 20167 | mod, |
| 20173 | fields.getIndex(try ip.getOrPutString(gpa, "signedness")).?, | 20168 | struct_type.nameIndex(ip, try ip.getOrPutString(gpa, "signedness")).?, |
| 20174 | ); | 20169 | ); |
| 20175 | const bits_val = try union_val.val.toValue().fieldValue( | 20170 | const bits_val = try union_val.val.toValue().fieldValue( |
| 20176 | mod, | 20171 | mod, |
| 20177 | fields.getIndex(try ip.getOrPutString(gpa, "bits")).?, | 20172 | struct_type.nameIndex(ip, try ip.getOrPutString(gpa, "bits")).?, |
| 20178 | ); | 20173 | ); |
| 20179 | 20174 | ||
| 20180 | const signedness = mod.toEnum(std.builtin.Signedness, signedness_val); | 20175 | const signedness = mod.toEnum(std.builtin.Signedness, signedness_val); |
| ... | @@ -20183,11 +20178,13 @@ fn zirReify( | ... | @@ -20183,11 +20178,13 @@ fn zirReify( |
| 20183 | return Air.internedToRef(ty.toIntern()); | 20178 | return Air.internedToRef(ty.toIntern()); |
| 20184 | }, | 20179 | }, |
| 20185 | .Vector => { | 20180 | .Vector => { |
| 20186 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | 20181 | const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type; |
| 20187 | const len_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20182 | const len_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20183 | ip, | ||
| 20188 | try ip.getOrPutString(gpa, "len"), | 20184 | try ip.getOrPutString(gpa, "len"), |
| 20189 | ).?); | 20185 | ).?); |
| 20190 | const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20186 | const child_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20187 | ip, | ||
| 20191 | try ip.getOrPutString(gpa, "child"), | 20188 | try ip.getOrPutString(gpa, "child"), |
| 20192 | ).?); | 20189 | ).?); |
| 20193 | 20190 | ||
| ... | @@ -20203,8 +20200,9 @@ fn zirReify( | ... | @@ -20203,8 +20200,9 @@ fn zirReify( |
| 20203 | return Air.internedToRef(ty.toIntern()); | 20200 | return Air.internedToRef(ty.toIntern()); |
| 20204 | }, | 20201 | }, |
| 20205 | .Float => { | 20202 | .Float => { |
| 20206 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | 20203 | const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type; |
| 20207 | const bits_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20204 | const bits_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20205 | ip, | ||
| 20208 | try ip.getOrPutString(gpa, "bits"), | 20206 | try ip.getOrPutString(gpa, "bits"), |
| 20209 | ).?); | 20207 | ).?); |
| 20210 | 20208 | ||
| ... | @@ -20220,29 +20218,37 @@ fn zirReify( | ... | @@ -20220,29 +20218,37 @@ fn zirReify( |
| 20220 | return Air.internedToRef(ty.toIntern()); | 20218 | return Air.internedToRef(ty.toIntern()); |
| 20221 | }, | 20219 | }, |
| 20222 | .Pointer => { | 20220 | .Pointer => { |
| 20223 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | 20221 | const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type; |
| 20224 | const size_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20222 | const size_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20223 | ip, | ||
| 20225 | try ip.getOrPutString(gpa, "size"), | 20224 | try ip.getOrPutString(gpa, "size"), |
| 20226 | ).?); | 20225 | ).?); |
| 20227 | const is_const_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20226 | const is_const_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20227 | ip, | ||
| 20228 | try ip.getOrPutString(gpa, "is_const"), | 20228 | try ip.getOrPutString(gpa, "is_const"), |
| 20229 | ).?); | 20229 | ).?); |
| 20230 | const is_volatile_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20230 | const is_volatile_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20231 | ip, | ||
| 20231 | try ip.getOrPutString(gpa, "is_volatile"), | 20232 | try ip.getOrPutString(gpa, "is_volatile"), |
| 20232 | ).?); | 20233 | ).?); |
| 20233 | const alignment_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20234 | const alignment_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20235 | ip, | ||
| 20234 | try ip.getOrPutString(gpa, "alignment"), | 20236 | try ip.getOrPutString(gpa, "alignment"), |
| 20235 | ).?); | 20237 | ).?); |
| 20236 | const address_space_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20238 | const address_space_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20239 | ip, | ||
| 20237 | try ip.getOrPutString(gpa, "address_space"), | 20240 | try ip.getOrPutString(gpa, "address_space"), |
| 20238 | ).?); | 20241 | ).?); |
| 20239 | const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20242 | const child_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20243 | ip, | ||
| 20240 | try ip.getOrPutString(gpa, "child"), | 20244 | try ip.getOrPutString(gpa, "child"), |
| 20241 | ).?); | 20245 | ).?); |
| 20242 | const is_allowzero_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20246 | const is_allowzero_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20247 | ip, | ||
| 20243 | try ip.getOrPutString(gpa, "is_allowzero"), | 20248 | try ip.getOrPutString(gpa, "is_allowzero"), |
| 20244 | ).?); | 20249 | ).?); |
| 20245 | const sentinel_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20250 | const sentinel_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20251 | ip, | ||
| 20246 | try ip.getOrPutString(gpa, "sentinel"), | 20252 | try ip.getOrPutString(gpa, "sentinel"), |
| 20247 | ).?); | 20253 | ).?); |
| 20248 | 20254 | ||
| ... | @@ -20322,14 +20328,17 @@ fn zirReify( | ... | @@ -20322,14 +20328,17 @@ fn zirReify( |
| 20322 | return Air.internedToRef(ty.toIntern()); | 20328 | return Air.internedToRef(ty.toIntern()); |
| 20323 | }, | 20329 | }, |
| 20324 | .Array => { | 20330 | .Array => { |
| 20325 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | 20331 | const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type; |
| 20326 | const len_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20332 | const len_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20333 | ip, | ||
| 20327 | try ip.getOrPutString(gpa, "len"), | 20334 | try ip.getOrPutString(gpa, "len"), |
| 20328 | ).?); | 20335 | ).?); |
| 20329 | const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20336 | const child_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20337 | ip, | ||
| 20330 | try ip.getOrPutString(gpa, "child"), | 20338 | try ip.getOrPutString(gpa, "child"), |
| 20331 | ).?); | 20339 | ).?); |
| 20332 | const sentinel_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20340 | const sentinel_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20341 | ip, | ||
| 20333 | try ip.getOrPutString(gpa, "sentinel"), | 20342 | try ip.getOrPutString(gpa, "sentinel"), |
| 20334 | ).?); | 20343 | ).?); |
| 20335 | 20344 | ||
| ... | @@ -20348,8 +20357,9 @@ fn zirReify( | ... | @@ -20348,8 +20357,9 @@ fn zirReify( |
| 20348 | return Air.internedToRef(ty.toIntern()); | 20357 | return Air.internedToRef(ty.toIntern()); |
| 20349 | }, | 20358 | }, |
| 20350 | .Optional => { | 20359 | .Optional => { |
| 20351 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | 20360 | const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type; |
| 20352 | const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20361 | const child_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20362 | ip, | ||
| 20353 | try ip.getOrPutString(gpa, "child"), | 20363 | try ip.getOrPutString(gpa, "child"), |
| 20354 | ).?); | 20364 | ).?); |
| 20355 | 20365 | ||
| ... | @@ -20359,11 +20369,13 @@ fn zirReify( | ... | @@ -20359,11 +20369,13 @@ fn zirReify( |
| 20359 | return Air.internedToRef(ty.toIntern()); | 20369 | return Air.internedToRef(ty.toIntern()); |
| 20360 | }, | 20370 | }, |
| 20361 | .ErrorUnion => { | 20371 | .ErrorUnion => { |
| 20362 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | 20372 | const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type; |
| 20363 | const error_set_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20373 | const error_set_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20374 | ip, | ||
| 20364 | try ip.getOrPutString(gpa, "error_set"), | 20375 | try ip.getOrPutString(gpa, "error_set"), |
| 20365 | ).?); | 20376 | ).?); |
| 20366 | const payload_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20377 | const payload_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20378 | ip, | ||
| 20367 | try ip.getOrPutString(gpa, "payload"), | 20379 | try ip.getOrPutString(gpa, "payload"), |
| 20368 | ).?); | 20380 | ).?); |
| 20369 | 20381 | ||
| ... | @@ -20386,8 +20398,9 @@ fn zirReify( | ... | @@ -20386,8 +20398,9 @@ fn zirReify( |
| 20386 | try names.ensureUnusedCapacity(sema.arena, len); | 20398 | try names.ensureUnusedCapacity(sema.arena, len); |
| 20387 | for (0..len) |i| { | 20399 | for (0..len) |i| { |
| 20388 | const elem_val = try payload_val.elemValue(mod, i); | 20400 | const elem_val = try payload_val.elemValue(mod, i); |
| 20389 | const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); | 20401 | const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type; |
| 20390 | const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | 20402 | const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( |
| 20403 | ip, | ||
| 20391 | try ip.getOrPutString(gpa, "name"), | 20404 | try ip.getOrPutString(gpa, "name"), |
| 20392 | ).?); | 20405 | ).?); |
| 20393 | 20406 | ||
| ... | @@ -20405,20 +20418,25 @@ fn zirReify( | ... | @@ -20405,20 +20418,25 @@ fn zirReify( |
| 20405 | return Air.internedToRef(ty.toIntern()); | 20418 | return Air.internedToRef(ty.toIntern()); |
| 20406 | }, | 20419 | }, |
| 20407 | .Struct => { | 20420 | .Struct => { |
| 20408 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | 20421 | const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type; |
| 20409 | const layout_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20422 | const layout_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20423 | ip, | ||
| 20410 | try ip.getOrPutString(gpa, "layout"), | 20424 | try ip.getOrPutString(gpa, "layout"), |
| 20411 | ).?); | 20425 | ).?); |
| 20412 | const backing_integer_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20426 | const backing_integer_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20427 | ip, | ||
| 20413 | try ip.getOrPutString(gpa, "backing_integer"), | 20428 | try ip.getOrPutString(gpa, "backing_integer"), |
| 20414 | ).?); | 20429 | ).?); |
| 20415 | const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20430 | const fields_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20431 | ip, | ||
| 20416 | try ip.getOrPutString(gpa, "fields"), | 20432 | try ip.getOrPutString(gpa, "fields"), |
| 20417 | ).?); | 20433 | ).?); |
| 20418 | const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20434 | const decls_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20435 | ip, | ||
| 20419 | try ip.getOrPutString(gpa, "decls"), | 20436 | try ip.getOrPutString(gpa, "decls"), |
| 20420 | ).?); | 20437 | ).?); |
| 20421 | const is_tuple_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20438 | const is_tuple_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20439 | ip, | ||
| 20422 | try ip.getOrPutString(gpa, "is_tuple"), | 20440 | try ip.getOrPutString(gpa, "is_tuple"), |
| 20423 | ).?); | 20441 | ).?); |
| 20424 | 20442 | ||
| ... | @@ -20436,17 +20454,21 @@ fn zirReify( | ... | @@ -20436,17 +20454,21 @@ fn zirReify( |
| 20436 | return try sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_val, name_strategy, is_tuple_val.toBool()); | 20454 | return try sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_val, name_strategy, is_tuple_val.toBool()); |
| 20437 | }, | 20455 | }, |
| 20438 | .Enum => { | 20456 | .Enum => { |
| 20439 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | 20457 | const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type; |
| 20440 | const tag_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20458 | const tag_type_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20459 | ip, | ||
| 20441 | try ip.getOrPutString(gpa, "tag_type"), | 20460 | try ip.getOrPutString(gpa, "tag_type"), |
| 20442 | ).?); | 20461 | ).?); |
| 20443 | const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20462 | const fields_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20463 | ip, | ||
| 20444 | try ip.getOrPutString(gpa, "fields"), | 20464 | try ip.getOrPutString(gpa, "fields"), |
| 20445 | ).?); | 20465 | ).?); |
| 20446 | const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20466 | const decls_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20467 | ip, | ||
| 20447 | try ip.getOrPutString(gpa, "decls"), | 20468 | try ip.getOrPutString(gpa, "decls"), |
| 20448 | ).?); | 20469 | ).?); |
| 20449 | const is_exhaustive_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20470 | const is_exhaustive_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20471 | ip, | ||
| 20450 | try ip.getOrPutString(gpa, "is_exhaustive"), | 20472 | try ip.getOrPutString(gpa, "is_exhaustive"), |
| 20451 | ).?); | 20473 | ).?); |
| 20452 | 20474 | ||
| ... | @@ -20496,11 +20518,13 @@ fn zirReify( | ... | @@ -20496,11 +20518,13 @@ fn zirReify( |
| 20496 | 20518 | ||
| 20497 | for (0..fields_len) |field_i| { | 20519 | for (0..fields_len) |field_i| { |
| 20498 | const elem_val = try fields_val.elemValue(mod, field_i); | 20520 | const elem_val = try fields_val.elemValue(mod, field_i); |
| 20499 | const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); | 20521 | const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type; |
| 20500 | const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | 20522 | const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( |
| 20523 | ip, | ||
| 20501 | try ip.getOrPutString(gpa, "name"), | 20524 | try ip.getOrPutString(gpa, "name"), |
| 20502 | ).?); | 20525 | ).?); |
| 20503 | const value_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | 20526 | const value_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( |
| 20527 | ip, | ||
| 20504 | try ip.getOrPutString(gpa, "value"), | 20528 | try ip.getOrPutString(gpa, "value"), |
| 20505 | ).?); | 20529 | ).?); |
| 20506 | 20530 | ||
| ... | @@ -20515,7 +20539,7 @@ fn zirReify( | ... | @@ -20515,7 +20539,7 @@ fn zirReify( |
| 20515 | }); | 20539 | }); |
| 20516 | } | 20540 | } |
| 20517 | 20541 | ||
| 20518 | if (try incomplete_enum.addFieldName(ip, gpa, field_name)) |other_index| { | 20542 | if (incomplete_enum.addFieldName(ip, field_name)) |other_index| { |
| 20519 | const msg = msg: { | 20543 | const msg = msg: { |
| 20520 | const msg = try sema.errMsg(block, src, "duplicate enum field '{}'", .{ | 20544 | const msg = try sema.errMsg(block, src, "duplicate enum field '{}'", .{ |
| 20521 | field_name.fmt(ip), | 20545 | field_name.fmt(ip), |
| ... | @@ -20528,7 +20552,7 @@ fn zirReify( | ... | @@ -20528,7 +20552,7 @@ fn zirReify( |
| 20528 | return sema.failWithOwnedErrorMsg(block, msg); | 20552 | return sema.failWithOwnedErrorMsg(block, msg); |
| 20529 | } | 20553 | } |
| 20530 | 20554 | ||
| 20531 | if (try incomplete_enum.addFieldValue(ip, gpa, (try mod.getCoerced(value_val, int_tag_ty)).toIntern())) |other| { | 20555 | if (incomplete_enum.addFieldValue(ip, (try mod.getCoerced(value_val, int_tag_ty)).toIntern())) |other| { |
| 20532 | const msg = msg: { | 20556 | const msg = msg: { |
| 20533 | const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{value_val.fmtValue(Type.comptime_int, mod)}); | 20557 | const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{value_val.fmtValue(Type.comptime_int, mod)}); |
| 20534 | errdefer msg.destroy(gpa); | 20558 | errdefer msg.destroy(gpa); |
| ... | @@ -20545,8 +20569,9 @@ fn zirReify( | ... | @@ -20545,8 +20569,9 @@ fn zirReify( |
| 20545 | return decl_val; | 20569 | return decl_val; |
| 20546 | }, | 20570 | }, |
| 20547 | .Opaque => { | 20571 | .Opaque => { |
| 20548 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | 20572 | const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type; |
| 20549 | const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20573 | const decls_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20574 | ip, | ||
| 20550 | try ip.getOrPutString(gpa, "decls"), | 20575 | try ip.getOrPutString(gpa, "decls"), |
| 20551 | ).?); | 20576 | ).?); |
| 20552 | 20577 | ||
| ... | @@ -20594,17 +20619,21 @@ fn zirReify( | ... | @@ -20594,17 +20619,21 @@ fn zirReify( |
| 20594 | return decl_val; | 20619 | return decl_val; |
| 20595 | }, | 20620 | }, |
| 20596 | .Union => { | 20621 | .Union => { |
| 20597 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | 20622 | const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type; |
| 20598 | const layout_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20623 | const layout_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20624 | ip, | ||
| 20599 | try ip.getOrPutString(gpa, "layout"), | 20625 | try ip.getOrPutString(gpa, "layout"), |
| 20600 | ).?); | 20626 | ).?); |
| 20601 | const tag_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20627 | const tag_type_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20628 | ip, | ||
| 20602 | try ip.getOrPutString(gpa, "tag_type"), | 20629 | try ip.getOrPutString(gpa, "tag_type"), |
| 20603 | ).?); | 20630 | ).?); |
| 20604 | const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20631 | const fields_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20632 | ip, | ||
| 20605 | try ip.getOrPutString(gpa, "fields"), | 20633 | try ip.getOrPutString(gpa, "fields"), |
| 20606 | ).?); | 20634 | ).?); |
| 20607 | const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20635 | const decls_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20636 | ip, | ||
| 20608 | try ip.getOrPutString(gpa, "decls"), | 20637 | try ip.getOrPutString(gpa, "decls"), |
| 20609 | ).?); | 20638 | ).?); |
| 20610 | 20639 | ||
| ... | @@ -20644,14 +20673,17 @@ fn zirReify( | ... | @@ -20644,14 +20673,17 @@ fn zirReify( |
| 20644 | 20673 | ||
| 20645 | for (0..fields_len) |i| { | 20674 | for (0..fields_len) |i| { |
| 20646 | const elem_val = try fields_val.elemValue(mod, i); | 20675 | const elem_val = try fields_val.elemValue(mod, i); |
| 20647 | const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); | 20676 | const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type; |
| 20648 | const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | 20677 | const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( |
| 20678 | ip, | ||
| 20649 | try ip.getOrPutString(gpa, "name"), | 20679 | try ip.getOrPutString(gpa, "name"), |
| 20650 | ).?); | 20680 | ).?); |
| 20651 | const type_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | 20681 | const type_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( |
| 20682 | ip, | ||
| 20652 | try ip.getOrPutString(gpa, "type"), | 20683 | try ip.getOrPutString(gpa, "type"), |
| 20653 | ).?); | 20684 | ).?); |
| 20654 | const alignment_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | 20685 | const alignment_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( |
| 20686 | ip, | ||
| 20655 | try ip.getOrPutString(gpa, "alignment"), | 20687 | try ip.getOrPutString(gpa, "alignment"), |
| 20656 | ).?); | 20688 | ).?); |
| 20657 | 20689 | ||
| ... | @@ -20812,23 +20844,29 @@ fn zirReify( | ... | @@ -20812,23 +20844,29 @@ fn zirReify( |
| 20812 | return decl_val; | 20844 | return decl_val; |
| 20813 | }, | 20845 | }, |
| 20814 | .Fn => { | 20846 | .Fn => { |
| 20815 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | 20847 | const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type; |
| 20816 | const calling_convention_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20848 | const calling_convention_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20849 | ip, | ||
| 20817 | try ip.getOrPutString(gpa, "calling_convention"), | 20850 | try ip.getOrPutString(gpa, "calling_convention"), |
| 20818 | ).?); | 20851 | ).?); |
| 20819 | const alignment_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20852 | const alignment_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20853 | ip, | ||
| 20820 | try ip.getOrPutString(gpa, "alignment"), | 20854 | try ip.getOrPutString(gpa, "alignment"), |
| 20821 | ).?); | 20855 | ).?); |
| 20822 | const is_generic_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20856 | const is_generic_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20857 | ip, | ||
| 20823 | try ip.getOrPutString(gpa, "is_generic"), | 20858 | try ip.getOrPutString(gpa, "is_generic"), |
| 20824 | ).?); | 20859 | ).?); |
| 20825 | const is_var_args_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20860 | const is_var_args_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20861 | ip, | ||
| 20826 | try ip.getOrPutString(gpa, "is_var_args"), | 20862 | try ip.getOrPutString(gpa, "is_var_args"), |
| 20827 | ).?); | 20863 | ).?); |
| 20828 | const return_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20864 | const return_type_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20865 | ip, | ||
| 20829 | try ip.getOrPutString(gpa, "return_type"), | 20866 | try ip.getOrPutString(gpa, "return_type"), |
| 20830 | ).?); | 20867 | ).?); |
| 20831 | const params_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | 20868 | const params_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( |
| 20869 | ip, | ||
| 20832 | try ip.getOrPutString(gpa, "params"), | 20870 | try ip.getOrPutString(gpa, "params"), |
| 20833 | ).?); | 20871 | ).?); |
| 20834 | 20872 | ||
| ... | @@ -20844,15 +20882,9 @@ fn zirReify( | ... | @@ -20844,15 +20882,9 @@ fn zirReify( |
| 20844 | } | 20882 | } |
| 20845 | 20883 | ||
| 20846 | const alignment = alignment: { | 20884 | const alignment = alignment: { |
| 20847 | if (!try sema.intFitsInType(alignment_val, Type.u32, null)) { | 20885 | const alignment = try sema.validateAlign(block, src, alignment_val.toUnsignedInt(mod)); |
| 20848 | return sema.fail(block, src, "alignment must fit in 'u32'", .{}); | 20886 | const default = target_util.defaultFunctionAlignment(target); |
| 20849 | } | 20887 | break :alignment if (alignment == default) .none else alignment; |
| 20850 | const alignment: u29 = @intCast(alignment_val.toUnsignedInt(mod)); | ||
| 20851 | if (alignment == target_util.defaultFunctionAlignment(target)) { | ||
| 20852 | break :alignment .none; | ||
| 20853 | } else { | ||
| 20854 | break :alignment Alignment.fromByteUnits(alignment); | ||
| 20855 | } | ||
| 20856 | }; | 20888 | }; |
| 20857 | const return_type = return_type_val.optionalValue(mod) orelse | 20889 | const return_type = return_type_val.optionalValue(mod) orelse |
| 20858 | return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{}); | 20890 | return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{}); |
| ... | @@ -20863,14 +20895,17 @@ fn zirReify( | ... | @@ -20863,14 +20895,17 @@ fn zirReify( |
| 20863 | var noalias_bits: u32 = 0; | 20895 | var noalias_bits: u32 = 0; |
| 20864 | for (param_types, 0..) |*param_type, i| { | 20896 | for (param_types, 0..) |*param_type, i| { |
| 20865 | const elem_val = try params_val.elemValue(mod, i); | 20897 | const elem_val = try params_val.elemValue(mod, i); |
| 20866 | const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); | 20898 | const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type; |
| 20867 | const param_is_generic_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | 20899 | const param_is_generic_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( |
| 20900 | ip, | ||
| 20868 | try ip.getOrPutString(gpa, "is_generic"), | 20901 | try ip.getOrPutString(gpa, "is_generic"), |
| 20869 | ).?); | 20902 | ).?); |
| 20870 | const param_is_noalias_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | 20903 | const param_is_noalias_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( |
| 20904 | ip, | ||
| 20871 | try ip.getOrPutString(gpa, "is_noalias"), | 20905 | try ip.getOrPutString(gpa, "is_noalias"), |
| 20872 | ).?); | 20906 | ).?); |
| 20873 | const opt_param_type_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | 20907 | const opt_param_type_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( |
| 20908 | ip, | ||
| 20874 | try ip.getOrPutString(gpa, "type"), | 20909 | try ip.getOrPutString(gpa, "type"), |
| 20875 | ).?); | 20910 | ).?); |
| 20876 | 20911 | ||
| ... | @@ -20931,6 +20966,8 @@ fn reifyStruct( | ... | @@ -20931,6 +20966,8 @@ fn reifyStruct( |
| 20931 | .Auto => {}, | 20966 | .Auto => {}, |
| 20932 | }; | 20967 | }; |
| 20933 | 20968 | ||
| 20969 | const fields_len: u32 = @intCast(try sema.usizeCast(block, src, fields_val.sliceLen(mod))); | ||
| 20970 | |||
| 20934 | // Because these three things each reference each other, `undefined` | 20971 | // Because these three things each reference each other, `undefined` |
| 20935 | // placeholders are used before being set after the struct type gains an | 20972 | // placeholders are used before being set after the struct type gains an |
| 20936 | // InternPool index. | 20973 | // InternPool index. |
| ... | @@ -20946,58 +20983,45 @@ fn reifyStruct( | ... | @@ -20946,58 +20983,45 @@ fn reifyStruct( |
| 20946 | mod.abortAnonDecl(new_decl_index); | 20983 | mod.abortAnonDecl(new_decl_index); |
| 20947 | } | 20984 | } |
| 20948 | 20985 | ||
| 20949 | const new_namespace_index = try mod.createNamespace(.{ | 20986 | const ty = try ip.getStructType(gpa, .{ |
| 20950 | .parent = block.namespace.toOptional(), | 20987 | .decl = new_decl_index, |
| 20951 | .ty = undefined, | 20988 | .namespace = .none, |
| 20952 | .file_scope = block.getFileScope(mod), | ||
| 20953 | }); | ||
| 20954 | const new_namespace = mod.namespacePtr(new_namespace_index); | ||
| 20955 | errdefer mod.destroyNamespace(new_namespace_index); | ||
| 20956 | |||
| 20957 | const struct_index = try mod.createStruct(.{ | ||
| 20958 | .owner_decl = new_decl_index, | ||
| 20959 | .fields = .{}, | ||
| 20960 | .zir_index = inst, | 20989 | .zir_index = inst, |
| 20961 | .layout = layout, | 20990 | .layout = layout, |
| 20962 | .status = .have_field_types, | ||
| 20963 | .known_non_opv = false, | 20991 | .known_non_opv = false, |
| 20992 | .fields_len = fields_len, | ||
| 20993 | .requires_comptime = .unknown, | ||
| 20964 | .is_tuple = is_tuple, | 20994 | .is_tuple = is_tuple, |
| 20965 | .namespace = new_namespace_index, | ||
| 20966 | }); | 20995 | }); |
| 20967 | const struct_obj = mod.structPtr(struct_index); | ||
| 20968 | errdefer mod.destroyStruct(struct_index); | ||
| 20969 | |||
| 20970 | const struct_ty = try ip.get(gpa, .{ .struct_type = .{ | ||
| 20971 | .index = struct_index.toOptional(), | ||
| 20972 | .namespace = new_namespace_index.toOptional(), | ||
| 20973 | } }); | ||
| 20974 | // TODO: figure out InternPool removals for incremental compilation | 20996 | // TODO: figure out InternPool removals for incremental compilation |
| 20975 | //errdefer ip.remove(struct_ty); | 20997 | //errdefer ip.remove(ty); |
| 20998 | const struct_type = ip.indexToKey(ty).struct_type; | ||
| 20976 | 20999 | ||
| 20977 | new_decl.ty = Type.type; | 21000 | new_decl.ty = Type.type; |
| 20978 | new_decl.val = struct_ty.toValue(); | 21001 | new_decl.val = ty.toValue(); |
| 20979 | new_namespace.ty = struct_ty.toType(); | ||
| 20980 | 21002 | ||
| 20981 | // Fields | 21003 | // Fields |
| 20982 | const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod)); | 21004 | for (0..fields_len) |i| { |
| 20983 | try struct_obj.fields.ensureTotalCapacity(mod.tmp_hack_arena.allocator(), fields_len); | ||
| 20984 | var i: usize = 0; | ||
| 20985 | while (i < fields_len) : (i += 1) { | ||
| 20986 | const elem_val = try fields_val.elemValue(mod, i); | 21005 | const elem_val = try fields_val.elemValue(mod, i); |
| 20987 | const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); | 21006 | const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type; |
| 20988 | const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | 21007 | const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( |
| 21008 | ip, | ||
| 20989 | try ip.getOrPutString(gpa, "name"), | 21009 | try ip.getOrPutString(gpa, "name"), |
| 20990 | ).?); | 21010 | ).?); |
| 20991 | const type_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | 21011 | const type_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( |
| 21012 | ip, | ||
| 20992 | try ip.getOrPutString(gpa, "type"), | 21013 | try ip.getOrPutString(gpa, "type"), |
| 20993 | ).?); | 21014 | ).?); |
| 20994 | const default_value_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | 21015 | const default_value_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( |
| 21016 | ip, | ||
| 20995 | try ip.getOrPutString(gpa, "default_value"), | 21017 | try ip.getOrPutString(gpa, "default_value"), |
| 20996 | ).?); | 21018 | ).?); |
| 20997 | const is_comptime_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | 21019 | const is_comptime_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( |
| 21020 | ip, | ||
| 20998 | try ip.getOrPutString(gpa, "is_comptime"), | 21021 | try ip.getOrPutString(gpa, "is_comptime"), |
| 20999 | ).?); | 21022 | ).?); |
| 21000 | const alignment_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | 21023 | const alignment_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( |
| 21024 | ip, | ||
| 21001 | try ip.getOrPutString(gpa, "alignment"), | 21025 | try ip.getOrPutString(gpa, "alignment"), |
| 21002 | ).?); | 21026 | ).?); |
| 21003 | 21027 | ||
| ... | @@ -21033,9 +21057,8 @@ fn reifyStruct( | ... | @@ -21033,9 +21057,8 @@ fn reifyStruct( |
| 21033 | ); | 21057 | ); |
| 21034 | } | 21058 | } |
| 21035 | } | 21059 | } |
| 21036 | const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name); | 21060 | if (struct_type.addFieldName(ip, field_name)) |prev_index| { |
| 21037 | if (gop.found_existing) { | 21061 | _ = prev_index; // TODO: better source location |
| 21038 | // TODO: better source location | ||
| 21039 | return sema.fail(block, src, "duplicate struct field {}", .{field_name.fmt(ip)}); | 21062 | return sema.fail(block, src, "duplicate struct field {}", .{field_name.fmt(ip)}); |
| 21040 | } | 21063 | } |
| 21041 | 21064 | ||
| ... | @@ -21051,13 +21074,11 @@ fn reifyStruct( | ... | @@ -21051,13 +21074,11 @@ fn reifyStruct( |
| 21051 | return sema.fail(block, src, "comptime field without default initialization value", .{}); | 21074 | return sema.fail(block, src, "comptime field without default initialization value", .{}); |
| 21052 | } | 21075 | } |
| 21053 | 21076 | ||
| 21054 | gop.value_ptr.* = .{ | 21077 | struct_type.field_types.get(ip)[i] = field_ty.toIntern(); |
| 21055 | .ty = field_ty, | 21078 | struct_type.field_aligns.get(ip)[i] = Alignment.fromByteUnits(abi_align); |
| 21056 | .abi_align = Alignment.fromByteUnits(abi_align), | 21079 | struct_type.field_inits.get(ip)[i] = default_val; |
| 21057 | .default_val = default_val, | 21080 | if (is_comptime_val.toBool()) |
| 21058 | .is_comptime = is_comptime_val.toBool(), | 21081 | struct_type.setFieldComptime(ip, i); |
| 21059 | .offset = undefined, | ||
| 21060 | }; | ||
| 21061 | 21082 | ||
| 21062 | if (field_ty.zigTypeTag(mod) == .Opaque) { | 21083 | if (field_ty.zigTypeTag(mod) == .Opaque) { |
| 21063 | const msg = msg: { | 21084 | const msg = msg: { |
| ... | @@ -21079,7 +21100,7 @@ fn reifyStruct( | ... | @@ -21079,7 +21100,7 @@ fn reifyStruct( |
| 21079 | }; | 21100 | }; |
| 21080 | return sema.failWithOwnedErrorMsg(block, msg); | 21101 | return sema.failWithOwnedErrorMsg(block, msg); |
| 21081 | } | 21102 | } |
| 21082 | if (struct_obj.layout == .Extern and !try sema.validateExternType(field_ty, .struct_field)) { | 21103 | if (layout == .Extern and !try sema.validateExternType(field_ty, .struct_field)) { |
| 21083 | const msg = msg: { | 21104 | const msg = msg: { |
| 21084 | const msg = try sema.errMsg(block, src, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); | 21105 | const msg = try sema.errMsg(block, src, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); |
| 21085 | errdefer msg.destroy(gpa); | 21106 | errdefer msg.destroy(gpa); |
| ... | @@ -21091,7 +21112,7 @@ fn reifyStruct( | ... | @@ -21091,7 +21112,7 @@ fn reifyStruct( |
| 21091 | break :msg msg; | 21112 | break :msg msg; |
| 21092 | }; | 21113 | }; |
| 21093 | return sema.failWithOwnedErrorMsg(block, msg); | 21114 | return sema.failWithOwnedErrorMsg(block, msg); |
| 21094 | } else if (struct_obj.layout == .Packed and !(validatePackedType(field_ty, mod))) { | 21115 | } else if (layout == .Packed and !(validatePackedType(field_ty, mod))) { |
| 21095 | const msg = msg: { | 21116 | const msg = msg: { |
| 21096 | const msg = try sema.errMsg(block, src, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); | 21117 | const msg = try sema.errMsg(block, src, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); |
| 21097 | errdefer msg.destroy(gpa); | 21118 | errdefer msg.destroy(gpa); |
| ... | @@ -21107,13 +21128,12 @@ fn reifyStruct( | ... | @@ -21107,13 +21128,12 @@ fn reifyStruct( |
| 21107 | } | 21128 | } |
| 21108 | 21129 | ||
| 21109 | if (layout == .Packed) { | 21130 | if (layout == .Packed) { |
| 21110 | struct_obj.status = .layout_wip; | 21131 | for (0..struct_type.field_types.len) |index| { |
| 21111 | 21132 | const field_ty = struct_type.field_types.get(ip)[index].toType(); | |
| 21112 | for (struct_obj.fields.values(), 0..) |field, index| { | 21133 | sema.resolveTypeLayout(field_ty) catch |err| switch (err) { |
| 21113 | sema.resolveTypeLayout(field.ty) catch |err| switch (err) { | ||
| 21114 | error.AnalysisFail => { | 21134 | error.AnalysisFail => { |
| 21115 | const msg = sema.err orelse return err; | 21135 | const msg = sema.err orelse return err; |
| 21116 | try sema.addFieldErrNote(struct_ty.toType(), index, msg, "while checking this field", .{}); | 21136 | try sema.addFieldErrNote(ty.toType(), index, msg, "while checking this field", .{}); |
| 21117 | return err; | 21137 | return err; |
| 21118 | }, | 21138 | }, |
| 21119 | else => return err, | 21139 | else => return err, |
| ... | @@ -21121,19 +21141,18 @@ fn reifyStruct( | ... | @@ -21121,19 +21141,18 @@ fn reifyStruct( |
| 21121 | } | 21141 | } |
| 21122 | 21142 | ||
| 21123 | var fields_bit_sum: u64 = 0; | 21143 | var fields_bit_sum: u64 = 0; |
| 21124 | for (struct_obj.fields.values()) |field| { | 21144 | for (struct_type.field_types.get(ip)) |field_ty| { |
| 21125 | fields_bit_sum += field.ty.bitSize(mod); | 21145 | fields_bit_sum += field_ty.toType().bitSize(mod); |
| 21126 | } | 21146 | } |
| 21127 | 21147 | ||
| 21128 | if (backing_int_val.optionalValue(mod)) |payload| { | 21148 | if (backing_int_val.optionalValue(mod)) |backing_int_ty_val| { |
| 21129 | const backing_int_ty = payload.toType(); | 21149 | const backing_int_ty = backing_int_ty_val.toType(); |
| 21130 | try sema.checkBackingIntType(block, src, backing_int_ty, fields_bit_sum); | 21150 | try sema.checkBackingIntType(block, src, backing_int_ty, fields_bit_sum); |
| 21131 | struct_obj.backing_int_ty = backing_int_ty; | 21151 | struct_type.backingIntType(ip).* = backing_int_ty.toIntern(); |
| 21132 | } else { | 21152 | } else { |
| 21133 | struct_obj.backing_int_ty = try mod.intType(.unsigned, @intCast(fields_bit_sum)); | 21153 | const backing_int_ty = try mod.intType(.unsigned, @intCast(fields_bit_sum)); |
| 21154 | struct_type.backingIntType(ip).* = backing_int_ty.toIntern(); | ||
| 21134 | } | 21155 | } |
| 21135 | |||
| 21136 | struct_obj.status = .have_layout; | ||
| 21137 | } | 21156 | } |
| 21138 | 21157 | ||
| 21139 | const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); | 21158 | const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); |
| ... | @@ -21439,8 +21458,9 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! | ... | @@ -21439,8 +21458,9 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 21439 | const is_non_zero = try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize); | 21458 | const is_non_zero = try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize); |
| 21440 | try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null); | 21459 | try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null); |
| 21441 | } | 21460 | } |
| 21442 | if (ptr_align > 1) { | 21461 | if (ptr_align.compare(.gt, .@"1")) { |
| 21443 | const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, ptr_align - 1)).toIntern()); | 21462 | const align_bytes_minus_1 = ptr_align.toByteUnitsOptional().? - 1; |
| 21463 | const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, align_bytes_minus_1)).toIntern()); | ||
| 21444 | const remainder = try block.addBinOp(.bit_and, operand_coerced, align_minus_1); | 21464 | const remainder = try block.addBinOp(.bit_and, operand_coerced, align_minus_1); |
| 21445 | const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize); | 21465 | const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize); |
| 21446 | try sema.addSafetyCheck(block, src, is_aligned, .incorrect_alignment); | 21466 | try sema.addSafetyCheck(block, src, is_aligned, .incorrect_alignment); |
| ... | @@ -21458,8 +21478,9 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! | ... | @@ -21458,8 +21478,9 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 21458 | const is_non_zero = try block.addBinOp(.cmp_neq, elem_coerced, .zero_usize); | 21478 | const is_non_zero = try block.addBinOp(.cmp_neq, elem_coerced, .zero_usize); |
| 21459 | try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null); | 21479 | try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null); |
| 21460 | } | 21480 | } |
| 21461 | if (ptr_align > 1) { | 21481 | if (ptr_align.compare(.gt, .@"1")) { |
| 21462 | const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, ptr_align - 1)).toIntern()); | 21482 | const align_bytes_minus_1 = ptr_align.toByteUnitsOptional().? - 1; |
| 21483 | const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, align_bytes_minus_1)).toIntern()); | ||
| 21463 | const remainder = try block.addBinOp(.bit_and, elem_coerced, align_minus_1); | 21484 | const remainder = try block.addBinOp(.bit_and, elem_coerced, align_minus_1); |
| 21464 | const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize); | 21485 | const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize); |
| 21465 | try sema.addSafetyCheck(block, src, is_aligned, .incorrect_alignment); | 21486 | try sema.addSafetyCheck(block, src, is_aligned, .incorrect_alignment); |
| ... | @@ -21476,12 +21497,19 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! | ... | @@ -21476,12 +21497,19 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 21476 | return block.addAggregateInit(dest_ty, new_elems); | 21497 | return block.addAggregateInit(dest_ty, new_elems); |
| 21477 | } | 21498 | } |
| 21478 | 21499 | ||
| 21479 | fn ptrFromIntVal(sema: *Sema, block: *Block, operand_src: LazySrcLoc, operand_val: Value, ptr_ty: Type, ptr_align: u32) !Value { | 21500 | fn ptrFromIntVal( |
| 21501 | sema: *Sema, | ||
| 21502 | block: *Block, | ||
| 21503 | operand_src: LazySrcLoc, | ||
| 21504 | operand_val: Value, | ||
| 21505 | ptr_ty: Type, | ||
| 21506 | ptr_align: Alignment, | ||
| 21507 | ) !Value { | ||
| 21480 | const mod = sema.mod; | 21508 | const mod = sema.mod; |
| 21481 | const addr = operand_val.toUnsignedInt(mod); | 21509 | const addr = operand_val.toUnsignedInt(mod); |
| 21482 | if (!ptr_ty.isAllowzeroPtr(mod) and addr == 0) | 21510 | if (!ptr_ty.isAllowzeroPtr(mod) and addr == 0) |
| 21483 | return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{ptr_ty.fmt(sema.mod)}); | 21511 | return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{ptr_ty.fmt(sema.mod)}); |
| 21484 | if (addr != 0 and ptr_align != 0 and addr % ptr_align != 0) | 21512 | if (addr != 0 and ptr_align != .none and !ptr_align.check(addr)) |
| 21485 | return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{ptr_ty.fmt(sema.mod)}); | 21513 | return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{ptr_ty.fmt(sema.mod)}); |
| 21486 | 21514 | ||
| 21487 | return switch (ptr_ty.zigTypeTag(mod)) { | 21515 | return switch (ptr_ty.zigTypeTag(mod)) { |
| ... | @@ -21795,10 +21823,18 @@ fn ptrCastFull( | ... | @@ -21795,10 +21823,18 @@ fn ptrCastFull( |
| 21795 | // TODO: vector index? | 21823 | // TODO: vector index? |
| 21796 | } | 21824 | } |
| 21797 | 21825 | ||
| 21798 | const src_align = src_info.flags.alignment.toByteUnitsOptional() orelse src_info.child.toType().abiAlignment(mod); | 21826 | const src_align = if (src_info.flags.alignment != .none) |
| 21799 | const dest_align = dest_info.flags.alignment.toByteUnitsOptional() orelse dest_info.child.toType().abiAlignment(mod); | 21827 | src_info.flags.alignment |
| 21828 | else | ||
| 21829 | src_info.child.toType().abiAlignment(mod); | ||
| 21830 | |||
| 21831 | const dest_align = if (dest_info.flags.alignment != .none) | ||
| 21832 | dest_info.flags.alignment | ||
| 21833 | else | ||
| 21834 | dest_info.child.toType().abiAlignment(mod); | ||
| 21835 | |||
| 21800 | if (!flags.align_cast) { | 21836 | if (!flags.align_cast) { |
| 21801 | if (dest_align > src_align) { | 21837 | if (dest_align.compare(.gt, src_align)) { |
| 21802 | return sema.failWithOwnedErrorMsg(block, msg: { | 21838 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 21803 | const msg = try sema.errMsg(block, src, "cast increases pointer alignment", .{}); | 21839 | const msg = try sema.errMsg(block, src, "cast increases pointer alignment", .{}); |
| 21804 | errdefer msg.destroy(sema.gpa); | 21840 | errdefer msg.destroy(sema.gpa); |
| ... | @@ -21891,10 +21927,13 @@ fn ptrCastFull( | ... | @@ -21891,10 +21927,13 @@ fn ptrCastFull( |
| 21891 | if (!dest_ty.ptrAllowsZero(mod) and ptr_val.isNull(mod)) { | 21927 | if (!dest_ty.ptrAllowsZero(mod) and ptr_val.isNull(mod)) { |
| 21892 | return sema.fail(block, operand_src, "null pointer casted to type '{}'", .{dest_ty.fmt(mod)}); | 21928 | return sema.fail(block, operand_src, "null pointer casted to type '{}'", .{dest_ty.fmt(mod)}); |
| 21893 | } | 21929 | } |
| 21894 | if (dest_align > src_align) { | 21930 | if (dest_align.compare(.gt, src_align)) { |
| 21895 | if (try ptr_val.getUnsignedIntAdvanced(mod, null)) |addr| { | 21931 | if (try ptr_val.getUnsignedIntAdvanced(mod, null)) |addr| { |
| 21896 | if (addr % dest_align != 0) { | 21932 | if (!dest_align.check(addr)) { |
| 21897 | return sema.fail(block, operand_src, "pointer address 0x{X} is not aligned to {d} bytes", .{ addr, dest_align }); | 21933 | return sema.fail(block, operand_src, "pointer address 0x{X} is not aligned to {d} bytes", .{ |
| 21934 | addr, | ||
| 21935 | dest_align.toByteUnitsOptional().?, | ||
| 21936 | }); | ||
| 21898 | } | 21937 | } |
| 21899 | } | 21938 | } |
| 21900 | } | 21939 | } |
| ... | @@ -21928,8 +21967,12 @@ fn ptrCastFull( | ... | @@ -21928,8 +21967,12 @@ fn ptrCastFull( |
| 21928 | try sema.addSafetyCheck(block, src, ok, .cast_to_null); | 21967 | try sema.addSafetyCheck(block, src, ok, .cast_to_null); |
| 21929 | } | 21968 | } |
| 21930 | 21969 | ||
| 21931 | if (block.wantSafety() and dest_align > src_align and try sema.typeHasRuntimeBits(dest_info.child.toType())) { | 21970 | if (block.wantSafety() and |
| 21932 | const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, dest_align - 1)).toIntern()); | 21971 | dest_align.compare(.gt, src_align) and |
| 21972 | try sema.typeHasRuntimeBits(dest_info.child.toType())) | ||
| 21973 | { | ||
| 21974 | const align_bytes_minus_1 = dest_align.toByteUnitsOptional().? - 1; | ||
| 21975 | const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, align_bytes_minus_1)).toIntern()); | ||
| 21933 | const ptr_int = try block.addUnOp(.int_from_ptr, ptr); | 21976 | const ptr_int = try block.addUnOp(.int_from_ptr, ptr); |
| 21934 | const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1); | 21977 | const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1); |
| 21935 | const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize); | 21978 | const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize); |
| ... | @@ -22285,6 +22328,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6 | ... | @@ -22285,6 +22328,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6 |
| 22285 | }); | 22328 | }); |
| 22286 | 22329 | ||
| 22287 | const mod = sema.mod; | 22330 | const mod = sema.mod; |
| 22331 | const ip = &mod.intern_pool; | ||
| 22288 | try sema.resolveTypeLayout(ty); | 22332 | try sema.resolveTypeLayout(ty); |
| 22289 | switch (ty.zigTypeTag(mod)) { | 22333 | switch (ty.zigTypeTag(mod)) { |
| 22290 | .Struct => {}, | 22334 | .Struct => {}, |
| ... | @@ -22300,7 +22344,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6 | ... | @@ -22300,7 +22344,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6 |
| 22300 | } | 22344 | } |
| 22301 | 22345 | ||
| 22302 | const field_index = if (ty.isTuple(mod)) blk: { | 22346 | const field_index = if (ty.isTuple(mod)) blk: { |
| 22303 | if (mod.intern_pool.stringEqlSlice(field_name, "len")) { | 22347 | if (ip.stringEqlSlice(field_name, "len")) { |
| 22304 | return sema.fail(block, src, "no offset available for 'len' field of tuple", .{}); | 22348 | return sema.fail(block, src, "no offset available for 'len' field of tuple", .{}); |
| 22305 | } | 22349 | } |
| 22306 | break :blk try sema.tupleFieldIndex(block, ty, field_name, rhs_src); | 22350 | break :blk try sema.tupleFieldIndex(block, ty, field_name, rhs_src); |
| ... | @@ -22313,12 +22357,13 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6 | ... | @@ -22313,12 +22357,13 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6 |
| 22313 | switch (ty.containerLayout(mod)) { | 22357 | switch (ty.containerLayout(mod)) { |
| 22314 | .Packed => { | 22358 | .Packed => { |
| 22315 | var bit_sum: u64 = 0; | 22359 | var bit_sum: u64 = 0; |
| 22316 | const fields = ty.structFields(mod); | 22360 | const struct_type = ip.indexToKey(ty.toIntern()).struct_type; |
| 22317 | for (fields.values(), 0..) |field, i| { | 22361 | for (0..struct_type.field_types.len) |i| { |
| 22318 | if (i == field_index) { | 22362 | if (i == field_index) { |
| 22319 | return bit_sum; | 22363 | return bit_sum; |
| 22320 | } | 22364 | } |
| 22321 | bit_sum += field.ty.bitSize(mod); | 22365 | const field_ty = struct_type.field_types.get(ip)[i].toType(); |
| 22366 | bit_sum += field_ty.bitSize(mod); | ||
| 22322 | } else unreachable; | 22367 | } else unreachable; |
| 22323 | }, | 22368 | }, |
| 22324 | else => return ty.structFieldOffset(field_index, mod) * 8, | 22369 | else => return ty.structFieldOffset(field_index, mod) * 8, |
| ... | @@ -23717,8 +23762,8 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr | ... | @@ -23717,8 +23762,8 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr |
| 23717 | return sema.fail(block, src, "TODO handle packed structs/unions with @fieldParentPtr", .{}); | 23762 | return sema.fail(block, src, "TODO handle packed structs/unions with @fieldParentPtr", .{}); |
| 23718 | } else { | 23763 | } else { |
| 23719 | ptr_ty_data.flags.alignment = blk: { | 23764 | ptr_ty_data.flags.alignment = blk: { |
| 23720 | if (mod.typeToStruct(parent_ty)) |struct_obj| { | 23765 | if (mod.typeToStruct(parent_ty)) |struct_type| { |
| 23721 | break :blk struct_obj.fields.values()[field_index].abi_align; | 23766 | break :blk struct_type.field_aligns.get(ip)[field_index]; |
| 23722 | } else if (mod.typeToUnion(parent_ty)) |union_obj| { | 23767 | } else if (mod.typeToUnion(parent_ty)) |union_obj| { |
| 23723 | break :blk union_obj.fieldAlign(ip, field_index); | 23768 | break :blk union_obj.fieldAlign(ip, field_index); |
| 23724 | } else { | 23769 | } else { |
| ... | @@ -24528,13 +24573,9 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -24528,13 +24573,9 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 24528 | if (val.isGenericPoison()) { | 24573 | if (val.isGenericPoison()) { |
| 24529 | break :blk null; | 24574 | break :blk null; |
| 24530 | } | 24575 | } |
| 24531 | const alignment: u32 = @intCast(val.toUnsignedInt(mod)); | 24576 | const alignment = try sema.validateAlign(block, align_src, val.toUnsignedInt(mod)); |
| 24532 | try sema.validateAlign(block, align_src, alignment); | 24577 | const default = target_util.defaultFunctionAlignment(target); |
| 24533 | if (alignment == target_util.defaultFunctionAlignment(target)) { | 24578 | break :blk if (alignment == default) .none else alignment; |
| 24534 | break :blk .none; | ||
| 24535 | } else { | ||
| 24536 | break :blk Alignment.fromNonzeroByteUnits(alignment); | ||
| 24537 | } | ||
| 24538 | } else if (extra.data.bits.has_align_ref) blk: { | 24579 | } else if (extra.data.bits.has_align_ref) blk: { |
| 24539 | const align_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]); | 24580 | const align_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]); |
| 24540 | extra_index += 1; | 24581 | extra_index += 1; |
| ... | @@ -24546,13 +24587,9 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -24546,13 +24587,9 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 24546 | }, | 24587 | }, |
| 24547 | else => |e| return e, | 24588 | else => |e| return e, |
| 24548 | }; | 24589 | }; |
| 24549 | const alignment: u32 = @intCast(align_tv.val.toUnsignedInt(mod)); | 24590 | const alignment = try sema.validateAlign(block, align_src, align_tv.val.toUnsignedInt(mod)); |
| 24550 | try sema.validateAlign(block, align_src, alignment); | 24591 | const default = target_util.defaultFunctionAlignment(target); |
| 24551 | if (alignment == target_util.defaultFunctionAlignment(target)) { | 24592 | break :blk if (alignment == default) .none else alignment; |
| 24552 | break :blk .none; | ||
| 24553 | } else { | ||
| 24554 | break :blk Alignment.fromNonzeroByteUnits(alignment); | ||
| 24555 | } | ||
| 24556 | } else .none; | 24593 | } else .none; |
| 24557 | 24594 | ||
| 24558 | const @"addrspace": ?std.builtin.AddressSpace = if (extra.data.bits.has_addrspace_body) blk: { | 24595 | const @"addrspace": ?std.builtin.AddressSpace = if (extra.data.bits.has_addrspace_body) blk: { |
| ... | @@ -25237,16 +25274,17 @@ fn explainWhyTypeIsComptimeInner( | ... | @@ -25237,16 +25274,17 @@ fn explainWhyTypeIsComptimeInner( |
| 25237 | .Struct => { | 25274 | .Struct => { |
| 25238 | if ((try type_set.getOrPut(sema.gpa, ty.toIntern())).found_existing) return; | 25275 | if ((try type_set.getOrPut(sema.gpa, ty.toIntern())).found_existing) return; |
| 25239 | 25276 | ||
| 25240 | if (mod.typeToStruct(ty)) |struct_obj| { | 25277 | if (mod.typeToStruct(ty)) |struct_type| { |
| 25241 | for (struct_obj.fields.values(), 0..) |field, i| { | 25278 | for (0..struct_type.field_types.len) |i| { |
| 25242 | const field_src_loc = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | 25279 | const field_ty = struct_type.field_types.get(ip)[i].toType(); |
| 25280 | const field_src_loc = mod.fieldSrcLoc(struct_type.decl.unwrap().?, .{ | ||
| 25243 | .index = i, | 25281 | .index = i, |
| 25244 | .range = .type, | 25282 | .range = .type, |
| 25245 | }); | 25283 | }); |
| 25246 | 25284 | ||
| 25247 | if (try sema.typeRequiresComptime(field.ty)) { | 25285 | if (try sema.typeRequiresComptime(field_ty)) { |
| 25248 | try mod.errNoteNonLazy(field_src_loc, msg, "struct requires comptime because of this field", .{}); | 25286 | try mod.errNoteNonLazy(field_src_loc, msg, "struct requires comptime because of this field", .{}); |
| 25249 | try sema.explainWhyTypeIsComptimeInner(msg, field_src_loc, field.ty, type_set); | 25287 | try sema.explainWhyTypeIsComptimeInner(msg, field_src_loc, field_ty, type_set); |
| 25250 | } | 25288 | } |
| 25251 | } | 25289 | } |
| 25252 | } | 25290 | } |
| ... | @@ -26297,13 +26335,12 @@ fn fieldCallBind( | ... | @@ -26297,13 +26335,12 @@ fn fieldCallBind( |
| 26297 | switch (concrete_ty.zigTypeTag(mod)) { | 26335 | switch (concrete_ty.zigTypeTag(mod)) { |
| 26298 | .Struct => { | 26336 | .Struct => { |
| 26299 | try sema.resolveTypeFields(concrete_ty); | 26337 | try sema.resolveTypeFields(concrete_ty); |
| 26300 | if (mod.typeToStruct(concrete_ty)) |struct_obj| { | 26338 | if (mod.typeToStruct(concrete_ty)) |struct_type| { |
| 26301 | const field_index_usize = struct_obj.fields.getIndex(field_name) orelse | 26339 | const field_index = struct_type.nameIndex(ip, field_name) orelse |
| 26302 | break :find_field; | 26340 | break :find_field; |
| 26303 | const field_index: u32 = @intCast(field_index_usize); | 26341 | const field_ty = struct_type.field_types.get(ip)[field_index].toType(); |
| 26304 | const field = struct_obj.fields.values()[field_index]; | ||
| 26305 | 26342 | ||
| 26306 | return sema.finishFieldCallBind(block, src, ptr_ty, field.ty, field_index, object_ptr); | 26343 | return sema.finishFieldCallBind(block, src, ptr_ty, field_ty, field_index, object_ptr); |
| 26307 | } else if (concrete_ty.isTuple(mod)) { | 26344 | } else if (concrete_ty.isTuple(mod)) { |
| 26308 | if (ip.stringEqlSlice(field_name, "len")) { | 26345 | if (ip.stringEqlSlice(field_name, "len")) { |
| 26309 | return .{ .direct = try mod.intRef(Type.usize, concrete_ty.structFieldCount(mod)) }; | 26346 | return .{ .direct = try mod.intRef(Type.usize, concrete_ty.structFieldCount(mod)) }; |
| ... | @@ -26526,13 +26563,14 @@ fn structFieldPtr( | ... | @@ -26526,13 +26563,14 @@ fn structFieldPtr( |
| 26526 | initializing: bool, | 26563 | initializing: bool, |
| 26527 | ) CompileError!Air.Inst.Ref { | 26564 | ) CompileError!Air.Inst.Ref { |
| 26528 | const mod = sema.mod; | 26565 | const mod = sema.mod; |
| 26566 | const ip = &mod.intern_pool; | ||
| 26529 | assert(struct_ty.zigTypeTag(mod) == .Struct); | 26567 | assert(struct_ty.zigTypeTag(mod) == .Struct); |
| 26530 | 26568 | ||
| 26531 | try sema.resolveTypeFields(struct_ty); | 26569 | try sema.resolveTypeFields(struct_ty); |
| 26532 | try sema.resolveStructLayout(struct_ty); | 26570 | try sema.resolveStructLayout(struct_ty); |
| 26533 | 26571 | ||
| 26534 | if (struct_ty.isTuple(mod)) { | 26572 | if (struct_ty.isTuple(mod)) { |
| 26535 | if (mod.intern_pool.stringEqlSlice(field_name, "len")) { | 26573 | if (ip.stringEqlSlice(field_name, "len")) { |
| 26536 | const len_inst = try mod.intRef(Type.usize, struct_ty.structFieldCount(mod)); | 26574 | const len_inst = try mod.intRef(Type.usize, struct_ty.structFieldCount(mod)); |
| 26537 | return sema.analyzeRef(block, src, len_inst); | 26575 | return sema.analyzeRef(block, src, len_inst); |
| 26538 | } | 26576 | } |
| ... | @@ -26543,11 +26581,10 @@ fn structFieldPtr( | ... | @@ -26543,11 +26581,10 @@ fn structFieldPtr( |
| 26543 | return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing); | 26581 | return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing); |
| 26544 | } | 26582 | } |
| 26545 | 26583 | ||
| 26546 | const struct_obj = mod.typeToStruct(struct_ty).?; | 26584 | const struct_type = mod.typeToStruct(struct_ty).?; |
| 26547 | 26585 | ||
| 26548 | const field_index_big = struct_obj.fields.getIndex(field_name) orelse | 26586 | const field_index = struct_type.nameIndex(ip, field_name) orelse |
| 26549 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name); | 26587 | return sema.failWithBadStructFieldAccess(block, struct_type, field_name_src, field_name); |
| 26550 | const field_index: u32 = @intCast(field_index_big); | ||
| 26551 | 26588 | ||
| 26552 | return sema.structFieldPtrByIndex(block, src, struct_ptr, field_index, field_name_src, struct_ty, initializing); | 26589 | return sema.structFieldPtrByIndex(block, src, struct_ptr, field_index, field_name_src, struct_ty, initializing); |
| 26553 | } | 26590 | } |
| ... | @@ -26563,17 +26600,18 @@ fn structFieldPtrByIndex( | ... | @@ -26563,17 +26600,18 @@ fn structFieldPtrByIndex( |
| 26563 | initializing: bool, | 26600 | initializing: bool, |
| 26564 | ) CompileError!Air.Inst.Ref { | 26601 | ) CompileError!Air.Inst.Ref { |
| 26565 | const mod = sema.mod; | 26602 | const mod = sema.mod; |
| 26603 | const ip = &mod.intern_pool; | ||
| 26566 | if (struct_ty.isAnonStruct(mod)) { | 26604 | if (struct_ty.isAnonStruct(mod)) { |
| 26567 | return sema.tupleFieldPtr(block, src, struct_ptr, field_src, field_index, initializing); | 26605 | return sema.tupleFieldPtr(block, src, struct_ptr, field_src, field_index, initializing); |
| 26568 | } | 26606 | } |
| 26569 | 26607 | ||
| 26570 | const struct_obj = mod.typeToStruct(struct_ty).?; | 26608 | const struct_type = mod.typeToStruct(struct_ty).?; |
| 26571 | const field = struct_obj.fields.values()[field_index]; | 26609 | const field_ty = struct_type.field_types.get(ip)[field_index]; |
| 26572 | const struct_ptr_ty = sema.typeOf(struct_ptr); | 26610 | const struct_ptr_ty = sema.typeOf(struct_ptr); |
| 26573 | const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(mod); | 26611 | const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(mod); |
| 26574 | 26612 | ||
| 26575 | var ptr_ty_data: InternPool.Key.PtrType = .{ | 26613 | var ptr_ty_data: InternPool.Key.PtrType = .{ |
| 26576 | .child = field.ty.toIntern(), | 26614 | .child = field_ty, |
| 26577 | .flags = .{ | 26615 | .flags = .{ |
| 26578 | .is_const = struct_ptr_ty_info.flags.is_const, | 26616 | .is_const = struct_ptr_ty_info.flags.is_const, |
| 26579 | .is_volatile = struct_ptr_ty_info.flags.is_volatile, | 26617 | .is_volatile = struct_ptr_ty_info.flags.is_volatile, |
| ... | @@ -26583,20 +26621,23 @@ fn structFieldPtrByIndex( | ... | @@ -26583,20 +26621,23 @@ fn structFieldPtrByIndex( |
| 26583 | 26621 | ||
| 26584 | const target = mod.getTarget(); | 26622 | const target = mod.getTarget(); |
| 26585 | 26623 | ||
| 26586 | const parent_align = struct_ptr_ty_info.flags.alignment.toByteUnitsOptional() orelse | 26624 | const parent_align = if (struct_ptr_ty_info.flags.alignment != .none) |
| 26625 | struct_ptr_ty_info.flags.alignment | ||
| 26626 | else | ||
| 26587 | try sema.typeAbiAlignment(struct_ptr_ty_info.child.toType()); | 26627 | try sema.typeAbiAlignment(struct_ptr_ty_info.child.toType()); |
| 26588 | 26628 | ||
| 26589 | if (struct_obj.layout == .Packed) { | 26629 | if (struct_type.layout == .Packed) { |
| 26590 | comptime assert(Type.packed_struct_layout_version == 2); | 26630 | comptime assert(Type.packed_struct_layout_version == 2); |
| 26591 | 26631 | ||
| 26592 | var running_bits: u16 = 0; | 26632 | var running_bits: u16 = 0; |
| 26593 | for (struct_obj.fields.values(), 0..) |f, i| { | 26633 | for (0..struct_type.field_types.len) |i| { |
| 26594 | if (!(try sema.typeHasRuntimeBits(f.ty))) continue; | 26634 | const f_ty = struct_type.field_types.get(ip)[i].toType(); |
| 26635 | if (!(try sema.typeHasRuntimeBits(f_ty))) continue; | ||
| 26595 | 26636 | ||
| 26596 | if (i == field_index) { | 26637 | if (i == field_index) { |
| 26597 | ptr_ty_data.packed_offset.bit_offset = running_bits; | 26638 | ptr_ty_data.packed_offset.bit_offset = running_bits; |
| 26598 | } | 26639 | } |
| 26599 | running_bits += @intCast(f.ty.bitSize(mod)); | 26640 | running_bits += @intCast(f_ty.bitSize(mod)); |
| 26600 | } | 26641 | } |
| 26601 | ptr_ty_data.packed_offset.host_size = (running_bits + 7) / 8; | 26642 | ptr_ty_data.packed_offset.host_size = (running_bits + 7) / 8; |
| 26602 | 26643 | ||
| ... | @@ -26607,7 +26648,7 @@ fn structFieldPtrByIndex( | ... | @@ -26607,7 +26648,7 @@ fn structFieldPtrByIndex( |
| 26607 | ptr_ty_data.packed_offset.bit_offset += struct_ptr_ty_info.packed_offset.bit_offset; | 26648 | ptr_ty_data.packed_offset.bit_offset += struct_ptr_ty_info.packed_offset.bit_offset; |
| 26608 | } | 26649 | } |
| 26609 | 26650 | ||
| 26610 | ptr_ty_data.flags.alignment = Alignment.fromByteUnits(parent_align); | 26651 | ptr_ty_data.flags.alignment = parent_align; |
| 26611 | 26652 | ||
| 26612 | // If the field happens to be byte-aligned, simplify the pointer type. | 26653 | // If the field happens to be byte-aligned, simplify the pointer type. |
| 26613 | // The pointee type bit size must match its ABI byte size so that loads and stores | 26654 | // The pointee type bit size must match its ABI byte size so that loads and stores |
| ... | @@ -26617,38 +26658,43 @@ fn structFieldPtrByIndex( | ... | @@ -26617,38 +26658,43 @@ fn structFieldPtrByIndex( |
| 26617 | // targets before adding the necessary complications to this code. This will not | 26658 | // targets before adding the necessary complications to this code. This will not |
| 26618 | // cause miscompilations; it only means the field pointer uses bit masking when it | 26659 | // cause miscompilations; it only means the field pointer uses bit masking when it |
| 26619 | // might not be strictly necessary. | 26660 | // might not be strictly necessary. |
| 26620 | if (parent_align != 0 and ptr_ty_data.packed_offset.bit_offset % 8 == 0 and | 26661 | if (parent_align != .none and ptr_ty_data.packed_offset.bit_offset % 8 == 0 and |
| 26621 | target.cpu.arch.endian() == .Little) | 26662 | target.cpu.arch.endian() == .Little) |
| 26622 | { | 26663 | { |
| 26623 | const elem_size_bytes = ptr_ty_data.child.toType().abiSize(mod); | 26664 | const elem_size_bytes = ptr_ty_data.child.toType().abiSize(mod); |
| 26624 | const elem_size_bits = ptr_ty_data.child.toType().bitSize(mod); | 26665 | const elem_size_bits = ptr_ty_data.child.toType().bitSize(mod); |
| 26625 | if (elem_size_bytes * 8 == elem_size_bits) { | 26666 | if (elem_size_bytes * 8 == elem_size_bits) { |
| 26626 | const byte_offset = ptr_ty_data.packed_offset.bit_offset / 8; | 26667 | const byte_offset = ptr_ty_data.packed_offset.bit_offset / 8; |
| 26627 | const new_align: Alignment = @enumFromInt(@ctz(byte_offset | parent_align)); | 26668 | const new_align: Alignment = @enumFromInt(@ctz(byte_offset | parent_align.toByteUnitsOptional().?)); |
| 26628 | assert(new_align != .none); | 26669 | assert(new_align != .none); |
| 26629 | ptr_ty_data.flags.alignment = new_align; | 26670 | ptr_ty_data.flags.alignment = new_align; |
| 26630 | ptr_ty_data.packed_offset = .{ .host_size = 0, .bit_offset = 0 }; | 26671 | ptr_ty_data.packed_offset = .{ .host_size = 0, .bit_offset = 0 }; |
| 26631 | } | 26672 | } |
| 26632 | } | 26673 | } |
| 26633 | } else if (struct_obj.layout == .Extern) { | 26674 | } else if (struct_type.layout == .Extern) { |
| 26634 | // For extern structs, field aligment might be bigger than type's natural alignment. Eg, in | 26675 | // For extern structs, field aligment might be bigger than type's natural alignment. Eg, in |
| 26635 | // `extern struct { x: u32, y: u16 }` the second field is aligned as u32. | 26676 | // `extern struct { x: u32, y: u16 }` the second field is aligned as u32. |
| 26636 | const field_offset = struct_ty.structFieldOffset(field_index, mod); | 26677 | const field_offset = struct_ty.structFieldOffset(field_index, mod); |
| 26637 | ptr_ty_data.flags.alignment = Alignment.fromByteUnits( | 26678 | ptr_ty_data.flags.alignment = if (parent_align == .none) |
| 26638 | if (parent_align == 0) 0 else std.math.gcd(field_offset, parent_align), | 26679 | .none |
| 26639 | ); | 26680 | else |
| 26681 | @enumFromInt(@min(@intFromEnum(parent_align), @ctz(field_offset))); | ||
| 26640 | } else { | 26682 | } else { |
| 26641 | // Our alignment is capped at the field alignment | 26683 | // Our alignment is capped at the field alignment |
| 26642 | const field_align = try sema.structFieldAlignment(field, struct_obj.layout); | 26684 | const field_align = try sema.structFieldAlignment( |
| 26643 | ptr_ty_data.flags.alignment = Alignment.fromByteUnits(@min(field_align, parent_align)); | 26685 | struct_type.field_aligns.get(ip)[field_index], |
| 26686 | field_ty.toType(), | ||
| 26687 | struct_type.layout, | ||
| 26688 | ); | ||
| 26689 | ptr_ty_data.flags.alignment = field_align.min(parent_align); | ||
| 26644 | } | 26690 | } |
| 26645 | 26691 | ||
| 26646 | const ptr_field_ty = try mod.ptrType(ptr_ty_data); | 26692 | const ptr_field_ty = try mod.ptrType(ptr_ty_data); |
| 26647 | 26693 | ||
| 26648 | if (field.is_comptime) { | 26694 | if (struct_type.comptime_bits.getBit(ip, field_index)) { |
| 26649 | const val = try mod.intern(.{ .ptr = .{ | 26695 | const val = try mod.intern(.{ .ptr = .{ |
| 26650 | .ty = ptr_field_ty.toIntern(), | 26696 | .ty = ptr_field_ty.toIntern(), |
| 26651 | .addr = .{ .comptime_field = field.default_val }, | 26697 | .addr = .{ .comptime_field = struct_type.field_inits.get(ip)[field_index] }, |
| 26652 | } }); | 26698 | } }); |
| 26653 | return Air.internedToRef(val); | 26699 | return Air.internedToRef(val); |
| 26654 | } | 26700 | } |
| ... | @@ -26678,33 +26724,33 @@ fn structFieldVal( | ... | @@ -26678,33 +26724,33 @@ fn structFieldVal( |
| 26678 | struct_ty: Type, | 26724 | struct_ty: Type, |
| 26679 | ) CompileError!Air.Inst.Ref { | 26725 | ) CompileError!Air.Inst.Ref { |
| 26680 | const mod = sema.mod; | 26726 | const mod = sema.mod; |
| 26727 | const ip = &mod.intern_pool; | ||
| 26681 | assert(struct_ty.zigTypeTag(mod) == .Struct); | 26728 | assert(struct_ty.zigTypeTag(mod) == .Struct); |
| 26682 | 26729 | ||
| 26683 | try sema.resolveTypeFields(struct_ty); | 26730 | try sema.resolveTypeFields(struct_ty); |
| 26684 | switch (mod.intern_pool.indexToKey(struct_ty.toIntern())) { | 26731 | switch (ip.indexToKey(struct_ty.toIntern())) { |
| 26685 | .struct_type => |struct_type| { | 26732 | .struct_type => |struct_type| { |
| 26686 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | 26733 | if (struct_type.isTuple(ip)) |
| 26687 | if (struct_obj.is_tuple) return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty); | 26734 | return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty); |
| 26688 | |||
| 26689 | const field_index_usize = struct_obj.fields.getIndex(field_name) orelse | ||
| 26690 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name); | ||
| 26691 | const field_index: u32 = @intCast(field_index_usize); | ||
| 26692 | const field = struct_obj.fields.values()[field_index]; | ||
| 26693 | 26735 | ||
| 26694 | if (field.is_comptime) { | 26736 | const field_index = struct_type.nameIndex(ip, field_name) orelse |
| 26695 | return Air.internedToRef(field.default_val); | 26737 | return sema.failWithBadStructFieldAccess(block, struct_type, field_name_src, field_name); |
| 26738 | if (struct_type.comptime_bits.getBit(ip, field_index)) { | ||
| 26739 | return Air.internedToRef(struct_type.field_inits.get(ip)[field_index]); | ||
| 26696 | } | 26740 | } |
| 26697 | 26741 | ||
| 26742 | const field_ty = struct_type.field_types.get(ip)[field_index].toType(); | ||
| 26743 | |||
| 26698 | if (try sema.resolveMaybeUndefVal(struct_byval)) |struct_val| { | 26744 | if (try sema.resolveMaybeUndefVal(struct_byval)) |struct_val| { |
| 26699 | if (struct_val.isUndef(mod)) return mod.undefRef(field.ty); | 26745 | if (struct_val.isUndef(mod)) return mod.undefRef(field_ty); |
| 26700 | if ((try sema.typeHasOnePossibleValue(field.ty))) |opv| { | 26746 | if ((try sema.typeHasOnePossibleValue(field_ty))) |opv| { |
| 26701 | return Air.internedToRef(opv.toIntern()); | 26747 | return Air.internedToRef(opv.toIntern()); |
| 26702 | } | 26748 | } |
| 26703 | return Air.internedToRef((try struct_val.fieldValue(mod, field_index)).toIntern()); | 26749 | return Air.internedToRef((try struct_val.fieldValue(mod, field_index)).toIntern()); |
| 26704 | } | 26750 | } |
| 26705 | 26751 | ||
| 26706 | try sema.requireRuntimeBlock(block, src, null); | 26752 | try sema.requireRuntimeBlock(block, src, null); |
| 26707 | return block.addStructFieldVal(struct_byval, field_index, field.ty); | 26753 | return block.addStructFieldVal(struct_byval, field_index, field_ty); |
| 26708 | }, | 26754 | }, |
| 26709 | .anon_struct_type => |anon_struct| { | 26755 | .anon_struct_type => |anon_struct| { |
| 26710 | if (anon_struct.names.len == 0) { | 26756 | if (anon_struct.names.len == 0) { |
| ... | @@ -26823,9 +26869,12 @@ fn unionFieldPtr( | ... | @@ -26823,9 +26869,12 @@ fn unionFieldPtr( |
| 26823 | .is_volatile = union_ptr_info.flags.is_volatile, | 26869 | .is_volatile = union_ptr_info.flags.is_volatile, |
| 26824 | .address_space = union_ptr_info.flags.address_space, | 26870 | .address_space = union_ptr_info.flags.address_space, |
| 26825 | .alignment = if (union_obj.getLayout(ip) == .Auto) blk: { | 26871 | .alignment = if (union_obj.getLayout(ip) == .Auto) blk: { |
| 26826 | const union_align = union_ptr_info.flags.alignment.toByteUnitsOptional() orelse try sema.typeAbiAlignment(union_ty); | 26872 | const union_align = if (union_ptr_info.flags.alignment != .none) |
| 26873 | union_ptr_info.flags.alignment | ||
| 26874 | else | ||
| 26875 | try sema.typeAbiAlignment(union_ty); | ||
| 26827 | const field_align = try sema.unionFieldAlignment(union_obj, field_index); | 26876 | const field_align = try sema.unionFieldAlignment(union_obj, field_index); |
| 26828 | break :blk InternPool.Alignment.fromByteUnits(@min(union_align, field_align)); | 26877 | break :blk union_align.min(field_align); |
| 26829 | } else union_ptr_info.flags.alignment, | 26878 | } else union_ptr_info.flags.alignment, |
| 26830 | }, | 26879 | }, |
| 26831 | .packed_offset = union_ptr_info.packed_offset, | 26880 | .packed_offset = union_ptr_info.packed_offset, |
| ... | @@ -28266,7 +28315,7 @@ const InMemoryCoercionResult = union(enum) { | ... | @@ -28266,7 +28315,7 @@ const InMemoryCoercionResult = union(enum) { |
| 28266 | ptr_qualifiers: Qualifiers, | 28315 | ptr_qualifiers: Qualifiers, |
| 28267 | ptr_allowzero: Pair, | 28316 | ptr_allowzero: Pair, |
| 28268 | ptr_bit_range: BitRange, | 28317 | ptr_bit_range: BitRange, |
| 28269 | ptr_alignment: IntPair, | 28318 | ptr_alignment: AlignPair, |
| 28270 | double_ptr_to_anyopaque: Pair, | 28319 | double_ptr_to_anyopaque: Pair, |
| 28271 | slice_to_anyopaque: Pair, | 28320 | slice_to_anyopaque: Pair, |
| 28272 | 28321 | ||
| ... | @@ -28312,6 +28361,11 @@ const InMemoryCoercionResult = union(enum) { | ... | @@ -28312,6 +28361,11 @@ const InMemoryCoercionResult = union(enum) { |
| 28312 | wanted: u64, | 28361 | wanted: u64, |
| 28313 | }; | 28362 | }; |
| 28314 | 28363 | ||
| 28364 | const AlignPair = struct { | ||
| 28365 | actual: Alignment, | ||
| 28366 | wanted: Alignment, | ||
| 28367 | }; | ||
| 28368 | |||
| 28315 | const Size = struct { | 28369 | const Size = struct { |
| 28316 | actual: std.builtin.Type.Pointer.Size, | 28370 | actual: std.builtin.Type.Pointer.Size, |
| 28317 | wanted: std.builtin.Type.Pointer.Size, | 28371 | wanted: std.builtin.Type.Pointer.Size, |
| ... | @@ -29133,13 +29187,17 @@ fn coerceInMemoryAllowedPtrs( | ... | @@ -29133,13 +29187,17 @@ fn coerceInMemoryAllowedPtrs( |
| 29133 | if (src_info.flags.alignment != .none or dest_info.flags.alignment != .none or | 29187 | if (src_info.flags.alignment != .none or dest_info.flags.alignment != .none or |
| 29134 | dest_info.child != src_info.child) | 29188 | dest_info.child != src_info.child) |
| 29135 | { | 29189 | { |
| 29136 | const src_align = src_info.flags.alignment.toByteUnitsOptional() orelse | 29190 | const src_align = if (src_info.flags.alignment != .none) |
| 29191 | src_info.flags.alignment | ||
| 29192 | else | ||
| 29137 | src_info.child.toType().abiAlignment(mod); | 29193 | src_info.child.toType().abiAlignment(mod); |
| 29138 | 29194 | ||
| 29139 | const dest_align = dest_info.flags.alignment.toByteUnitsOptional() orelse | 29195 | const dest_align = if (dest_info.flags.alignment != .none) |
| 29196 | dest_info.flags.alignment | ||
| 29197 | else | ||
| 29140 | dest_info.child.toType().abiAlignment(mod); | 29198 | dest_info.child.toType().abiAlignment(mod); |
| 29141 | 29199 | ||
| 29142 | if (dest_align > src_align) { | 29200 | if (dest_align.compare(.gt, src_align)) { |
| 29143 | return InMemoryCoercionResult{ .ptr_alignment = .{ | 29201 | return InMemoryCoercionResult{ .ptr_alignment = .{ |
| 29144 | .actual = src_align, | 29202 | .actual = src_align, |
| 29145 | .wanted = dest_align, | 29203 | .wanted = dest_align, |
| ... | @@ -30378,13 +30436,17 @@ fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_resul | ... | @@ -30378,13 +30436,17 @@ fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_resul |
| 30378 | if (inst_info.flags.alignment == .none and dest_info.flags.alignment == .none) return true; | 30436 | if (inst_info.flags.alignment == .none and dest_info.flags.alignment == .none) return true; |
| 30379 | if (len0) return true; | 30437 | if (len0) return true; |
| 30380 | 30438 | ||
| 30381 | const inst_align = inst_info.flags.alignment.toByteUnitsOptional() orelse | 30439 | const inst_align = if (inst_info.flags.alignment != .none) |
| 30440 | inst_info.flags.alignment | ||
| 30441 | else | ||
| 30382 | inst_info.child.toType().abiAlignment(mod); | 30442 | inst_info.child.toType().abiAlignment(mod); |
| 30383 | 30443 | ||
| 30384 | const dest_align = dest_info.flags.alignment.toByteUnitsOptional() orelse | 30444 | const dest_align = if (dest_info.flags.alignment != .none) |
| 30445 | dest_info.flags.alignment | ||
| 30446 | else | ||
| 30385 | dest_info.child.toType().abiAlignment(mod); | 30447 | dest_info.child.toType().abiAlignment(mod); |
| 30386 | 30448 | ||
| 30387 | if (dest_align > inst_align) { | 30449 | if (dest_align.compare(.gt, inst_align)) { |
| 30388 | in_memory_result.* = .{ .ptr_alignment = .{ | 30450 | in_memory_result.* = .{ .ptr_alignment = .{ |
| 30389 | .actual = inst_align, | 30451 | .actual = inst_align, |
| 30390 | .wanted = dest_align, | 30452 | .wanted = dest_align, |
| ... | @@ -30598,7 +30660,7 @@ fn coerceAnonStructToUnion( | ... | @@ -30598,7 +30660,7 @@ fn coerceAnonStructToUnion( |
| 30598 | else | 30660 | else |
| 30599 | .{ .count = anon_struct_type.names.len }, | 30661 | .{ .count = anon_struct_type.names.len }, |
| 30600 | .struct_type => |struct_type| name: { | 30662 | .struct_type => |struct_type| name: { |
| 30601 | const field_names = mod.structPtrUnwrap(struct_type.index).?.fields.keys(); | 30663 | const field_names = struct_type.field_names.get(ip); |
| 30602 | break :name if (field_names.len == 1) | 30664 | break :name if (field_names.len == 1) |
| 30603 | .{ .name = field_names[0] } | 30665 | .{ .name = field_names[0] } |
| 30604 | else | 30666 | else |
| ... | @@ -30869,8 +30931,8 @@ fn coerceTupleToStruct( | ... | @@ -30869,8 +30931,8 @@ fn coerceTupleToStruct( |
| 30869 | return sema.coerceTupleToTuple(block, struct_ty, inst, inst_src); | 30931 | return sema.coerceTupleToTuple(block, struct_ty, inst, inst_src); |
| 30870 | } | 30932 | } |
| 30871 | 30933 | ||
| 30872 | const fields = struct_ty.structFields(mod); | 30934 | const struct_type = mod.typeToStruct(struct_ty).?; |
| 30873 | const field_vals = try sema.arena.alloc(InternPool.Index, fields.count()); | 30935 | const field_vals = try sema.arena.alloc(InternPool.Index, struct_type.field_types.len); |
| 30874 | const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len); | 30936 | const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len); |
| 30875 | @memset(field_refs, .none); | 30937 | @memset(field_refs, .none); |
| 30876 | 30938 | ||
| ... | @@ -30878,10 +30940,7 @@ fn coerceTupleToStruct( | ... | @@ -30878,10 +30940,7 @@ fn coerceTupleToStruct( |
| 30878 | var runtime_src: ?LazySrcLoc = null; | 30940 | var runtime_src: ?LazySrcLoc = null; |
| 30879 | const field_count = switch (ip.indexToKey(inst_ty.toIntern())) { | 30941 | const field_count = switch (ip.indexToKey(inst_ty.toIntern())) { |
| 30880 | .anon_struct_type => |anon_struct_type| anon_struct_type.types.len, | 30942 | .anon_struct_type => |anon_struct_type| anon_struct_type.types.len, |
| 30881 | .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| | 30943 | .struct_type => |s| s.field_types.len, |
| 30882 | struct_obj.fields.count() | ||
| 30883 | else | ||
| 30884 | 0, | ||
| 30885 | else => unreachable, | 30944 | else => unreachable, |
| 30886 | }; | 30945 | }; |
| 30887 | for (0..field_count) |field_index_usize| { | 30946 | for (0..field_count) |field_index_usize| { |
| ... | @@ -30893,22 +30952,23 @@ fn coerceTupleToStruct( | ... | @@ -30893,22 +30952,23 @@ fn coerceTupleToStruct( |
| 30893 | anon_struct_type.names.get(ip)[field_i] | 30952 | anon_struct_type.names.get(ip)[field_i] |
| 30894 | else | 30953 | else |
| 30895 | try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}), | 30954 | try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}), |
| 30896 | .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.keys()[field_i], | 30955 | .struct_type => |s| s.field_names.get(ip)[field_i], |
| 30897 | else => unreachable, | 30956 | else => unreachable, |
| 30898 | }; | 30957 | }; |
| 30899 | const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src); | 30958 | const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src); |
| 30900 | const field = fields.values()[field_index]; | 30959 | const field_ty = struct_type.field_types.get(ip)[field_index].toType(); |
| 30901 | const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i); | 30960 | const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i); |
| 30902 | const coerced = try sema.coerce(block, field.ty, elem_ref, field_src); | 30961 | const coerced = try sema.coerce(block, field_ty, elem_ref, field_src); |
| 30903 | field_refs[field_index] = coerced; | 30962 | field_refs[field_index] = coerced; |
| 30904 | if (field.is_comptime) { | 30963 | if (struct_type.comptime_bits.getBit(ip, field_index)) { |
| 30905 | const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse { | 30964 | const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse { |
| 30906 | return sema.failWithNeededComptime(block, field_src, .{ | 30965 | return sema.failWithNeededComptime(block, field_src, .{ |
| 30907 | .needed_comptime_reason = "value stored in comptime field must be comptime-known", | 30966 | .needed_comptime_reason = "value stored in comptime field must be comptime-known", |
| 30908 | }); | 30967 | }); |
| 30909 | }; | 30968 | }; |
| 30910 | 30969 | ||
| 30911 | if (!init_val.eql(field.default_val.toValue(), field.ty, sema.mod)) { | 30970 | const field_init = struct_type.field_inits.get(ip)[field_index].toValue(); |
| 30971 | if (!init_val.eql(field_init, field_ty, sema.mod)) { | ||
| 30912 | return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i); | 30972 | return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i); |
| 30913 | } | 30973 | } |
| 30914 | } | 30974 | } |
| ... | @@ -30928,10 +30988,10 @@ fn coerceTupleToStruct( | ... | @@ -30928,10 +30988,10 @@ fn coerceTupleToStruct( |
| 30928 | for (field_refs, 0..) |*field_ref, i| { | 30988 | for (field_refs, 0..) |*field_ref, i| { |
| 30929 | if (field_ref.* != .none) continue; | 30989 | if (field_ref.* != .none) continue; |
| 30930 | 30990 | ||
| 30931 | const field_name = fields.keys()[i]; | 30991 | const field_name = struct_type.field_names.get(ip)[i]; |
| 30932 | const field = fields.values()[i]; | 30992 | const field_default_val = struct_type.field_inits.get(ip)[i]; |
| 30933 | const field_src = inst_src; // TODO better source location | 30993 | const field_src = inst_src; // TODO better source location |
| 30934 | if (field.default_val == .none) { | 30994 | if (field_default_val == .none) { |
| 30935 | const template = "missing struct field: {}"; | 30995 | const template = "missing struct field: {}"; |
| 30936 | const args = .{field_name.fmt(ip)}; | 30996 | const args = .{field_name.fmt(ip)}; |
| 30937 | if (root_msg) |msg| { | 30997 | if (root_msg) |msg| { |
| ... | @@ -30942,9 +31002,9 @@ fn coerceTupleToStruct( | ... | @@ -30942,9 +31002,9 @@ fn coerceTupleToStruct( |
| 30942 | continue; | 31002 | continue; |
| 30943 | } | 31003 | } |
| 30944 | if (runtime_src == null) { | 31004 | if (runtime_src == null) { |
| 30945 | field_vals[i] = field.default_val; | 31005 | field_vals[i] = field_default_val; |
| 30946 | } else { | 31006 | } else { |
| 30947 | field_ref.* = Air.internedToRef(field.default_val); | 31007 | field_ref.* = Air.internedToRef(field_default_val); |
| 30948 | } | 31008 | } |
| 30949 | } | 31009 | } |
| 30950 | 31010 | ||
| ... | @@ -30980,10 +31040,7 @@ fn coerceTupleToTuple( | ... | @@ -30980,10 +31040,7 @@ fn coerceTupleToTuple( |
| 30980 | const ip = &mod.intern_pool; | 31040 | const ip = &mod.intern_pool; |
| 30981 | const dest_field_count = switch (ip.indexToKey(tuple_ty.toIntern())) { | 31041 | const dest_field_count = switch (ip.indexToKey(tuple_ty.toIntern())) { |
| 30982 | .anon_struct_type => |anon_struct_type| anon_struct_type.types.len, | 31042 | .anon_struct_type => |anon_struct_type| anon_struct_type.types.len, |
| 30983 | .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| | 31043 | .struct_type => |struct_type| struct_type.field_types.len, |
| 30984 | struct_obj.fields.count() | ||
| 30985 | else | ||
| 30986 | 0, | ||
| 30987 | else => unreachable, | 31044 | else => unreachable, |
| 30988 | }; | 31045 | }; |
| 30989 | const field_vals = try sema.arena.alloc(InternPool.Index, dest_field_count); | 31046 | const field_vals = try sema.arena.alloc(InternPool.Index, dest_field_count); |
| ... | @@ -30993,10 +31050,7 @@ fn coerceTupleToTuple( | ... | @@ -30993,10 +31050,7 @@ fn coerceTupleToTuple( |
| 30993 | const inst_ty = sema.typeOf(inst); | 31050 | const inst_ty = sema.typeOf(inst); |
| 30994 | const src_field_count = switch (ip.indexToKey(inst_ty.toIntern())) { | 31051 | const src_field_count = switch (ip.indexToKey(inst_ty.toIntern())) { |
| 30995 | .anon_struct_type => |anon_struct_type| anon_struct_type.types.len, | 31052 | .anon_struct_type => |anon_struct_type| anon_struct_type.types.len, |
| 30996 | .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| | 31053 | .struct_type => |struct_type| struct_type.field_types.len, |
| 30997 | struct_obj.fields.count() | ||
| 30998 | else | ||
| 30999 | 0, | ||
| 31000 | else => unreachable, | 31054 | else => unreachable, |
| 31001 | }; | 31055 | }; |
| 31002 | if (src_field_count > dest_field_count) return error.NotCoercible; | 31056 | if (src_field_count > dest_field_count) return error.NotCoercible; |
| ... | @@ -31011,7 +31065,7 @@ fn coerceTupleToTuple( | ... | @@ -31011,7 +31065,7 @@ fn coerceTupleToTuple( |
| 31011 | anon_struct_type.names.get(ip)[field_i] | 31065 | anon_struct_type.names.get(ip)[field_i] |
| 31012 | else | 31066 | else |
| 31013 | try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}), | 31067 | try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}), |
| 31014 | .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.keys()[field_i], | 31068 | .struct_type => |struct_type| struct_type.field_names.get(ip)[field_i], |
| 31015 | else => unreachable, | 31069 | else => unreachable, |
| 31016 | }; | 31070 | }; |
| 31017 | 31071 | ||
| ... | @@ -31019,20 +31073,20 @@ fn coerceTupleToTuple( | ... | @@ -31019,20 +31073,20 @@ fn coerceTupleToTuple( |
| 31019 | return sema.fail(block, field_src, "cannot assign to 'len' field of tuple", .{}); | 31073 | return sema.fail(block, field_src, "cannot assign to 'len' field of tuple", .{}); |
| 31020 | 31074 | ||
| 31021 | const field_ty = switch (ip.indexToKey(tuple_ty.toIntern())) { | 31075 | const field_ty = switch (ip.indexToKey(tuple_ty.toIntern())) { |
| 31022 | .anon_struct_type => |anon_struct_type| anon_struct_type.types.get(ip)[field_index_usize].toType(), | 31076 | .anon_struct_type => |anon_struct_type| anon_struct_type.types.get(ip)[field_index_usize], |
| 31023 | .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.values()[field_index_usize].ty, | 31077 | .struct_type => |struct_type| struct_type.field_types.get(ip)[field_index_usize], |
| 31024 | else => unreachable, | 31078 | else => unreachable, |
| 31025 | }; | 31079 | }; |
| 31026 | const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) { | 31080 | const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) { |
| 31027 | .anon_struct_type => |anon_struct_type| anon_struct_type.values.get(ip)[field_index_usize], | 31081 | .anon_struct_type => |anon_struct_type| anon_struct_type.values.get(ip)[field_index_usize], |
| 31028 | .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.values()[field_index_usize].default_val, | 31082 | .struct_type => |struct_type| struct_type.field_inits.get(ip)[field_index_usize], |
| 31029 | else => unreachable, | 31083 | else => unreachable, |
| 31030 | }; | 31084 | }; |
| 31031 | 31085 | ||
| 31032 | const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_src); | 31086 | const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_src); |
| 31033 | 31087 | ||
| 31034 | const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i); | 31088 | const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i); |
| 31035 | const coerced = try sema.coerce(block, field_ty, elem_ref, field_src); | 31089 | const coerced = try sema.coerce(block, field_ty.toType(), elem_ref, field_src); |
| 31036 | field_refs[field_index] = coerced; | 31090 | field_refs[field_index] = coerced; |
| 31037 | if (default_val != .none) { | 31091 | if (default_val != .none) { |
| 31038 | const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse { | 31092 | const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse { |
| ... | @@ -31041,7 +31095,7 @@ fn coerceTupleToTuple( | ... | @@ -31041,7 +31095,7 @@ fn coerceTupleToTuple( |
| 31041 | }); | 31095 | }); |
| 31042 | }; | 31096 | }; |
| 31043 | 31097 | ||
| 31044 | if (!init_val.eql(default_val.toValue(), field_ty, sema.mod)) { | 31098 | if (!init_val.eql(default_val.toValue(), field_ty.toType(), sema.mod)) { |
| 31045 | return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i); | 31099 | return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i); |
| 31046 | } | 31100 | } |
| 31047 | } | 31101 | } |
| ... | @@ -31063,7 +31117,7 @@ fn coerceTupleToTuple( | ... | @@ -31063,7 +31117,7 @@ fn coerceTupleToTuple( |
| 31063 | 31117 | ||
| 31064 | const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) { | 31118 | const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) { |
| 31065 | .anon_struct_type => |anon_struct_type| anon_struct_type.values.get(ip)[i], | 31119 | .anon_struct_type => |anon_struct_type| anon_struct_type.values.get(ip)[i], |
| 31066 | .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.values()[i].default_val, | 31120 | .struct_type => |struct_type| struct_type.field_inits.get(ip)[i], |
| 31067 | else => unreachable, | 31121 | else => unreachable, |
| 31068 | }; | 31122 | }; |
| 31069 | 31123 | ||
| ... | @@ -33181,12 +33235,17 @@ fn resolvePeerTypesInner( | ... | @@ -33181,12 +33235,17 @@ fn resolvePeerTypesInner( |
| 33181 | } | 33235 | } |
| 33182 | 33236 | ||
| 33183 | // Note that the align can be always non-zero; Module.ptrType will canonicalize it | 33237 | // Note that the align can be always non-zero; Module.ptrType will canonicalize it |
| 33184 | ptr_info.flags.alignment = Alignment.fromByteUnits(@min( | 33238 | ptr_info.flags.alignment = InternPool.Alignment.min( |
| 33185 | ptr_info.flags.alignment.toByteUnitsOptional() orelse | 33239 | if (ptr_info.flags.alignment != .none) |
| 33240 | ptr_info.flags.alignment | ||
| 33241 | else | ||
| 33186 | ptr_info.child.toType().abiAlignment(mod), | 33242 | ptr_info.child.toType().abiAlignment(mod), |
| 33187 | peer_info.flags.alignment.toByteUnitsOptional() orelse | 33243 | |
| 33244 | if (peer_info.flags.alignment != .none) | ||
| 33245 | peer_info.flags.alignment | ||
| 33246 | else | ||
| 33188 | peer_info.child.toType().abiAlignment(mod), | 33247 | peer_info.child.toType().abiAlignment(mod), |
| 33189 | )); | 33248 | ); |
| 33190 | if (ptr_info.flags.address_space != peer_info.flags.address_space) { | 33249 | if (ptr_info.flags.address_space != peer_info.flags.address_space) { |
| 33191 | return .{ .conflict = .{ | 33250 | return .{ .conflict = .{ |
| 33192 | .peer_idx_a = first_idx, | 33251 | .peer_idx_a = first_idx, |
| ... | @@ -33260,12 +33319,17 @@ fn resolvePeerTypesInner( | ... | @@ -33260,12 +33319,17 @@ fn resolvePeerTypesInner( |
| 33260 | } }; | 33319 | } }; |
| 33261 | 33320 | ||
| 33262 | // Note that the align can be always non-zero; Type.ptr will canonicalize it | 33321 | // Note that the align can be always non-zero; Type.ptr will canonicalize it |
| 33263 | ptr_info.flags.alignment = Alignment.fromByteUnits(@min( | 33322 | ptr_info.flags.alignment = Alignment.min( |
| 33264 | ptr_info.flags.alignment.toByteUnitsOptional() orelse | 33323 | if (ptr_info.flags.alignment != .none) |
| 33324 | ptr_info.flags.alignment | ||
| 33325 | else | ||
| 33265 | ptr_info.child.toType().abiAlignment(mod), | 33326 | ptr_info.child.toType().abiAlignment(mod), |
| 33266 | peer_info.flags.alignment.toByteUnitsOptional() orelse | 33327 | |
| 33328 | if (peer_info.flags.alignment != .none) | ||
| 33329 | peer_info.flags.alignment | ||
| 33330 | else | ||
| 33267 | peer_info.child.toType().abiAlignment(mod), | 33331 | peer_info.child.toType().abiAlignment(mod), |
| 33268 | )); | 33332 | ); |
| 33269 | 33333 | ||
| 33270 | if (ptr_info.flags.address_space != peer_info.flags.address_space) { | 33334 | if (ptr_info.flags.address_space != peer_info.flags.address_space) { |
| 33271 | return generic_err; | 33335 | return generic_err; |
| ... | @@ -34191,103 +34255,117 @@ pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void { | ... | @@ -34191,103 +34255,117 @@ pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void { |
| 34191 | } | 34255 | } |
| 34192 | 34256 | ||
| 34193 | fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { | 34257 | fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { |
| 34194 | const mod = sema.mod; | ||
| 34195 | try sema.resolveTypeFields(ty); | 34258 | try sema.resolveTypeFields(ty); |
| 34196 | if (mod.typeToStruct(ty)) |struct_obj| { | 34259 | |
| 34197 | switch (struct_obj.status) { | 34260 | const mod = sema.mod; |
| 34198 | .none, .have_field_types => {}, | 34261 | const ip = &mod.intern_pool; |
| 34199 | .field_types_wip, .layout_wip => { | 34262 | const struct_type = mod.typeToStruct(ty) orelse return; |
| 34200 | const msg = try Module.ErrorMsg.create( | 34263 | |
| 34201 | sema.gpa, | 34264 | if (struct_type.haveLayout(ip)) |
| 34202 | struct_obj.srcLoc(mod), | 34265 | return; |
| 34203 | "struct '{}' depends on itself", | 34266 | |
| 34204 | .{ty.fmt(mod)}, | 34267 | if (struct_type.layout == .Packed) { |
| 34205 | ); | 34268 | try semaBackingIntType(mod, struct_type); |
| 34206 | return sema.failWithOwnedErrorMsg(null, msg); | 34269 | return; |
| 34270 | } | ||
| 34271 | |||
| 34272 | if (struct_type.setLayoutWip(ip)) { | ||
| 34273 | const msg = try Module.ErrorMsg.create( | ||
| 34274 | sema.gpa, | ||
| 34275 | mod.declPtr(struct_type.decl.unwrap().?).srcLoc(mod), | ||
| 34276 | "struct '{}' depends on itself", | ||
| 34277 | .{ty.fmt(mod)}, | ||
| 34278 | ); | ||
| 34279 | return sema.failWithOwnedErrorMsg(null, msg); | ||
| 34280 | } | ||
| 34281 | |||
| 34282 | if (try sema.typeRequiresComptime(ty)) | ||
| 34283 | return; | ||
| 34284 | |||
| 34285 | const aligns = try sema.arena.alloc(Alignment, struct_type.field_types.len); | ||
| 34286 | const sizes = try sema.arena.alloc(u64, struct_type.field_types.len); | ||
| 34287 | |||
| 34288 | for (aligns, sizes, 0..) |*field_align, *field_size, i| { | ||
| 34289 | const field_ty = struct_type.field_types.get(ip)[i].toType(); | ||
| 34290 | field_size.* = sema.typeAbiSize(field_ty) catch |err| switch (err) { | ||
| 34291 | error.AnalysisFail => { | ||
| 34292 | const msg = sema.err orelse return err; | ||
| 34293 | try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{}); | ||
| 34294 | return err; | ||
| 34207 | }, | 34295 | }, |
| 34208 | .have_layout, .fully_resolved_wip, .fully_resolved => return, | 34296 | else => return err, |
| 34209 | } | ||
| 34210 | const prev_status = struct_obj.status; | ||
| 34211 | errdefer if (struct_obj.status == .layout_wip) { | ||
| 34212 | struct_obj.status = prev_status; | ||
| 34213 | }; | 34297 | }; |
| 34298 | field_align.* = try sema.structFieldAlignment( | ||
| 34299 | struct_type.fieldAlign(ip, i), | ||
| 34300 | field_ty, | ||
| 34301 | struct_type.layout, | ||
| 34302 | ); | ||
| 34303 | } | ||
| 34214 | 34304 | ||
| 34215 | struct_obj.status = .layout_wip; | 34305 | if (struct_type.flagsPtr(ip).assumed_runtime_bits and !(try sema.typeHasRuntimeBits(ty))) { |
| 34216 | for (struct_obj.fields.values(), 0..) |field, i| { | 34306 | const msg = try Module.ErrorMsg.create( |
| 34217 | sema.resolveTypeLayout(field.ty) catch |err| switch (err) { | 34307 | sema.gpa, |
| 34218 | error.AnalysisFail => { | 34308 | mod.declPtr(struct_type.decl.unwrap().?).srcLoc(mod), |
| 34219 | const msg = sema.err orelse return err; | 34309 | "struct layout depends on it having runtime bits", |
| 34220 | try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{}); | 34310 | .{}, |
| 34221 | return err; | 34311 | ); |
| 34222 | }, | 34312 | return sema.failWithOwnedErrorMsg(null, msg); |
| 34223 | else => return err, | 34313 | } |
| 34224 | }; | ||
| 34225 | } | ||
| 34226 | 34314 | ||
| 34227 | if (struct_obj.layout == .Packed) { | 34315 | if (struct_type.hasReorderedFields(ip)) { |
| 34228 | try semaBackingIntType(mod, struct_obj); | 34316 | for (sizes, struct_type.runtime_order.get(ip), 0..) |size, *ro, i| { |
| 34317 | ro.* = if (size != 0) @enumFromInt(i) else .omitted; | ||
| 34229 | } | 34318 | } |
| 34230 | 34319 | ||
| 34231 | struct_obj.status = .have_layout; | 34320 | const RuntimeOrder = InternPool.Key.StructType.RuntimeOrder; |
| 34232 | _ = try sema.typeRequiresComptime(ty); | ||
| 34233 | 34321 | ||
| 34234 | if (struct_obj.assumed_runtime_bits and !(try sema.typeHasRuntimeBits(ty))) { | 34322 | const AlignSortContext = struct { |
| 34235 | const msg = try Module.ErrorMsg.create( | 34323 | aligns: []const Alignment, |
| 34236 | sema.gpa, | ||
| 34237 | struct_obj.srcLoc(mod), | ||
| 34238 | "struct layout depends on it having runtime bits", | ||
| 34239 | .{}, | ||
| 34240 | ); | ||
| 34241 | return sema.failWithOwnedErrorMsg(null, msg); | ||
| 34242 | } | ||
| 34243 | 34324 | ||
| 34244 | if (struct_obj.layout == .Auto and !struct_obj.is_tuple and | 34325 | fn lessThan(ctx: @This(), a: RuntimeOrder, b: RuntimeOrder) bool { |
| 34245 | mod.backendSupportsFeature(.field_reordering)) | 34326 | if (a == .omitted) return false; |
| 34246 | { | 34327 | if (b == .omitted) return true; |
| 34247 | const optimized_order = try mod.tmp_hack_arena.allocator().alloc(u32, struct_obj.fields.count()); | 34328 | const a_align = ctx.aligns[@intFromEnum(a)]; |
| 34248 | 34329 | const b_align = ctx.aligns[@intFromEnum(b)]; | |
| 34249 | for (struct_obj.fields.values(), 0..) |field, i| { | 34330 | return a_align.compare(.gt, b_align); |
| 34250 | optimized_order[i] = if (try sema.typeHasRuntimeBits(field.ty)) | ||
| 34251 | @intCast(i) | ||
| 34252 | else | ||
| 34253 | Module.Struct.omitted_field; | ||
| 34254 | } | 34331 | } |
| 34332 | }; | ||
| 34333 | mem.sortUnstable(RuntimeOrder, struct_type.runtime_order.get(ip), AlignSortContext{ | ||
| 34334 | .aligns = aligns, | ||
| 34335 | }, AlignSortContext.lessThan); | ||
| 34336 | } | ||
| 34255 | 34337 | ||
| 34256 | const AlignSortContext = struct { | 34338 | // Calculate size, alignment, and field offsets. |
| 34257 | struct_obj: *Module.Struct, | 34339 | const offsets = struct_type.offsets.get(ip); |
| 34258 | sema: *Sema, | 34340 | var it = struct_type.iterateRuntimeOrder(ip); |
| 34259 | 34341 | var offset: u64 = 0; | |
| 34260 | fn lessThan(ctx: @This(), a: u32, b: u32) bool { | 34342 | var big_align: Alignment = .none; |
| 34261 | const m = ctx.sema.mod; | 34343 | while (it.next()) |i| { |
| 34262 | if (a == Module.Struct.omitted_field) return false; | 34344 | big_align = big_align.max(aligns[i]); |
| 34263 | if (b == Module.Struct.omitted_field) return true; | 34345 | offsets[i] = @intCast(aligns[i].forward(offset)); |
| 34264 | return ctx.struct_obj.fields.values()[a].ty.abiAlignment(m) > | 34346 | offset = offsets[i] + sizes[i]; |
| 34265 | ctx.struct_obj.fields.values()[b].ty.abiAlignment(m); | ||
| 34266 | } | ||
| 34267 | }; | ||
| 34268 | mem.sort(u32, optimized_order, AlignSortContext{ | ||
| 34269 | .struct_obj = struct_obj, | ||
| 34270 | .sema = sema, | ||
| 34271 | }, AlignSortContext.lessThan); | ||
| 34272 | struct_obj.optimized_order = optimized_order.ptr; | ||
| 34273 | } | ||
| 34274 | } | 34347 | } |
| 34275 | // otherwise it's a tuple; no need to resolve anything | 34348 | struct_type.size(ip).* = @intCast(big_align.forward(offset)); |
| 34349 | const flags = struct_type.flagsPtr(ip); | ||
| 34350 | flags.alignment = big_align; | ||
| 34351 | flags.layout_resolved = true; | ||
| 34276 | } | 34352 | } |
| 34277 | 34353 | ||
| 34278 | fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!void { | 34354 | fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) CompileError!void { |
| 34279 | const gpa = mod.gpa; | 34355 | const gpa = mod.gpa; |
| 34356 | const ip = &mod.intern_pool; | ||
| 34280 | 34357 | ||
| 34281 | var fields_bit_sum: u64 = 0; | 34358 | var fields_bit_sum: u64 = 0; |
| 34282 | for (struct_obj.fields.values()) |field| { | 34359 | for (0..struct_type.field_types.len) |i| { |
| 34283 | fields_bit_sum += field.ty.bitSize(mod); | 34360 | const field_ty = struct_type.field_types.get(ip)[i].toType(); |
| 34361 | fields_bit_sum += field_ty.bitSize(mod); | ||
| 34284 | } | 34362 | } |
| 34285 | 34363 | ||
| 34286 | const decl_index = struct_obj.owner_decl; | 34364 | const decl_index = struct_type.decl.unwrap().?; |
| 34287 | const decl = mod.declPtr(decl_index); | 34365 | const decl = mod.declPtr(decl_index); |
| 34288 | 34366 | ||
| 34289 | const zir = mod.namespacePtr(struct_obj.namespace).file_scope.zir; | 34367 | const zir = mod.namespacePtr(struct_type.namespace.unwrap().?).file_scope.zir; |
| 34290 | const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended; | 34368 | const extended = zir.instructions.items(.data)[struct_type.zir_index].extended; |
| 34291 | assert(extended.opcode == .struct_decl); | 34369 | assert(extended.opcode == .struct_decl); |
| 34292 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); | 34370 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); |
| 34293 | 34371 | ||
| ... | @@ -34326,7 +34404,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi | ... | @@ -34326,7 +34404,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi |
| 34326 | .parent = null, | 34404 | .parent = null, |
| 34327 | .sema = &sema, | 34405 | .sema = &sema, |
| 34328 | .src_decl = decl_index, | 34406 | .src_decl = decl_index, |
| 34329 | .namespace = struct_obj.namespace, | 34407 | .namespace = struct_type.namespace.unwrap() orelse decl.src_namespace, |
| 34330 | .wip_capture_scope = try mod.createCaptureScope(decl.src_scope), | 34408 | .wip_capture_scope = try mod.createCaptureScope(decl.src_scope), |
| 34331 | .instructions = .{}, | 34409 | .instructions = .{}, |
| 34332 | .inlining = null, | 34410 | .inlining = null, |
| ... | @@ -34341,13 +34419,13 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi | ... | @@ -34341,13 +34419,13 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi |
| 34341 | break :blk try sema.resolveType(&block, backing_int_src, backing_int_ref); | 34419 | break :blk try sema.resolveType(&block, backing_int_src, backing_int_ref); |
| 34342 | } else { | 34420 | } else { |
| 34343 | const body = zir.extra[extra_index..][0..backing_int_body_len]; | 34421 | const body = zir.extra[extra_index..][0..backing_int_body_len]; |
| 34344 | const ty_ref = try sema.resolveBody(&block, body, struct_obj.zir_index); | 34422 | const ty_ref = try sema.resolveBody(&block, body, struct_type.zir_index); |
| 34345 | break :blk try sema.analyzeAsType(&block, backing_int_src, ty_ref); | 34423 | break :blk try sema.analyzeAsType(&block, backing_int_src, ty_ref); |
| 34346 | } | 34424 | } |
| 34347 | }; | 34425 | }; |
| 34348 | 34426 | ||
| 34349 | try sema.checkBackingIntType(&block, backing_int_src, backing_int_ty, fields_bit_sum); | 34427 | try sema.checkBackingIntType(&block, backing_int_src, backing_int_ty, fields_bit_sum); |
| 34350 | struct_obj.backing_int_ty = backing_int_ty; | 34428 | struct_type.backingIntType(ip).* = backing_int_ty.toIntern(); |
| 34351 | for (comptime_mutable_decls.items) |ct_decl_index| { | 34429 | for (comptime_mutable_decls.items) |ct_decl_index| { |
| 34352 | const ct_decl = mod.declPtr(ct_decl_index); | 34430 | const ct_decl = mod.declPtr(ct_decl_index); |
| 34353 | _ = try ct_decl.internValue(mod); | 34431 | _ = try ct_decl.internValue(mod); |
| ... | @@ -34374,7 +34452,8 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi | ... | @@ -34374,7 +34452,8 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi |
| 34374 | .parent = null, | 34452 | .parent = null, |
| 34375 | .sema = &sema, | 34453 | .sema = &sema, |
| 34376 | .src_decl = decl_index, | 34454 | .src_decl = decl_index, |
| 34377 | .namespace = struct_obj.namespace, | 34455 | .namespace = struct_type.namespace.unwrap() orelse |
| 34456 | mod.declPtr(struct_type.decl.unwrap().?).src_namespace, | ||
| 34378 | .wip_capture_scope = undefined, | 34457 | .wip_capture_scope = undefined, |
| 34379 | .instructions = .{}, | 34458 | .instructions = .{}, |
| 34380 | .inlining = null, | 34459 | .inlining = null, |
| ... | @@ -34382,7 +34461,8 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi | ... | @@ -34382,7 +34461,8 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi |
| 34382 | }; | 34461 | }; |
| 34383 | return sema.fail(&block, LazySrcLoc.nodeOffset(0), "size of packed struct '{d}' exceeds maximum bit width of 65535", .{fields_bit_sum}); | 34462 | return sema.fail(&block, LazySrcLoc.nodeOffset(0), "size of packed struct '{d}' exceeds maximum bit width of 65535", .{fields_bit_sum}); |
| 34384 | } | 34463 | } |
| 34385 | struct_obj.backing_int_ty = try mod.intType(.unsigned, @intCast(fields_bit_sum)); | 34464 | const backing_int_ty = try mod.intType(.unsigned, @intCast(fields_bit_sum)); |
| 34465 | struct_type.backingIntType(ip).* = backing_int_ty.toIntern(); | ||
| 34386 | } | 34466 | } |
| 34387 | } | 34467 | } |
| 34388 | 34468 | ||
| ... | @@ -34532,30 +34612,20 @@ fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void { | ... | @@ -34532,30 +34612,20 @@ fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void { |
| 34532 | try sema.resolveStructLayout(ty); | 34612 | try sema.resolveStructLayout(ty); |
| 34533 | 34613 | ||
| 34534 | const mod = sema.mod; | 34614 | const mod = sema.mod; |
| 34535 | try sema.resolveTypeFields(ty); | 34615 | const ip = &mod.intern_pool; |
| 34536 | const struct_obj = mod.typeToStruct(ty).?; | 34616 | const struct_type = mod.typeToStruct(ty).?; |
| 34537 | 34617 | ||
| 34538 | switch (struct_obj.status) { | 34618 | if (struct_type.setFullyResolved(ip)) return; |
| 34539 | .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, | 34619 | errdefer struct_type.clearFullyResolved(ip); |
| 34540 | .fully_resolved_wip, .fully_resolved => return, | ||
| 34541 | } | ||
| 34542 | 34620 | ||
| 34543 | { | 34621 | // After we have resolve struct layout we have to go over the fields again to |
| 34544 | // After we have resolve struct layout we have to go over the fields again to | 34622 | // make sure pointer fields get their child types resolved as well. |
| 34545 | // make sure pointer fields get their child types resolved as well. | 34623 | // See also similar code for unions. |
| 34546 | // See also similar code for unions. | ||
| 34547 | const prev_status = struct_obj.status; | ||
| 34548 | errdefer struct_obj.status = prev_status; | ||
| 34549 | 34624 | ||
| 34550 | struct_obj.status = .fully_resolved_wip; | 34625 | for (0..struct_type.field_types.len) |i| { |
| 34551 | for (struct_obj.fields.values()) |field| { | 34626 | const field_ty = struct_type.field_types.get(ip)[i].toType(); |
| 34552 | try sema.resolveTypeFully(field.ty); | 34627 | try sema.resolveTypeFully(field_ty); |
| 34553 | } | ||
| 34554 | struct_obj.status = .fully_resolved; | ||
| 34555 | } | 34628 | } |
| 34556 | |||
| 34557 | // And let's not forget comptime-only status. | ||
| 34558 | _ = try sema.typeRequiresComptime(ty); | ||
| 34559 | } | 34629 | } |
| 34560 | 34630 | ||
| 34561 | fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void { | 34631 | fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void { |
| ... | @@ -34591,8 +34661,10 @@ fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void { | ... | @@ -34591,8 +34661,10 @@ fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void { |
| 34591 | 34661 | ||
| 34592 | pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void { | 34662 | pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void { |
| 34593 | const mod = sema.mod; | 34663 | const mod = sema.mod; |
| 34664 | const ip = &mod.intern_pool; | ||
| 34665 | const ty_ip = ty.toIntern(); | ||
| 34594 | 34666 | ||
| 34595 | switch (ty.toIntern()) { | 34667 | switch (ty_ip) { |
| 34596 | .var_args_param_type => unreachable, | 34668 | .var_args_param_type => unreachable, |
| 34597 | 34669 | ||
| 34598 | .none => unreachable, | 34670 | .none => unreachable, |
| ... | @@ -34673,20 +34745,15 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void { | ... | @@ -34673,20 +34745,15 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void { |
| 34673 | .empty_struct => unreachable, | 34745 | .empty_struct => unreachable, |
| 34674 | .generic_poison => unreachable, | 34746 | .generic_poison => unreachable, |
| 34675 | 34747 | ||
| 34676 | else => switch (mod.intern_pool.items.items(.tag)[@intFromEnum(ty.toIntern())]) { | 34748 | else => switch (ip.items.items(.tag)[@intFromEnum(ty_ip)]) { |
| 34677 | .type_struct, | 34749 | .type_struct, |
| 34678 | .type_struct_ns, | 34750 | .type_struct_ns, |
| 34679 | .type_union, | 34751 | .type_struct_packed, |
| 34680 | .simple_type, | 34752 | .type_struct_packed_inits, |
| 34681 | => switch (mod.intern_pool.indexToKey(ty.toIntern())) { | 34753 | => try sema.resolveTypeFieldsStruct(ty_ip, ip.indexToKey(ty_ip).struct_type), |
| 34682 | .struct_type => |struct_type| { | 34754 | |
| 34683 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return; | 34755 | .type_union => try sema.resolveTypeFieldsUnion(ty_ip.toType(), ip.indexToKey(ty_ip).union_type), |
| 34684 | try sema.resolveTypeFieldsStruct(ty, struct_obj); | 34756 | .simple_type => try sema.resolveSimpleType(ip.indexToKey(ty_ip).simple_type), |
| 34685 | }, | ||
| 34686 | .union_type => |union_type| try sema.resolveTypeFieldsUnion(ty, union_type), | ||
| 34687 | .simple_type => |simple_type| try sema.resolveSimpleType(simple_type), | ||
| 34688 | else => unreachable, | ||
| 34689 | }, | ||
| 34690 | else => {}, | 34757 | else => {}, |
| 34691 | }, | 34758 | }, |
| 34692 | } | 34759 | } |
| ... | @@ -34716,43 +34783,44 @@ fn resolveSimpleType(sema: *Sema, simple_type: InternPool.SimpleType) CompileErr | ... | @@ -34716,43 +34783,44 @@ fn resolveSimpleType(sema: *Sema, simple_type: InternPool.SimpleType) CompileErr |
| 34716 | 34783 | ||
| 34717 | fn resolveTypeFieldsStruct( | 34784 | fn resolveTypeFieldsStruct( |
| 34718 | sema: *Sema, | 34785 | sema: *Sema, |
| 34719 | ty: Type, | 34786 | ty: InternPool.Index, |
| 34720 | struct_obj: *Module.Struct, | 34787 | struct_type: InternPool.Key.StructType, |
| 34721 | ) CompileError!void { | 34788 | ) CompileError!void { |
| 34722 | switch (sema.mod.declPtr(struct_obj.owner_decl).analysis) { | 34789 | const mod = sema.mod; |
| 34790 | const ip = &mod.intern_pool; | ||
| 34791 | // If there is no owner decl it means the struct has no fields. | ||
| 34792 | const owner_decl = struct_type.decl.unwrap() orelse return; | ||
| 34793 | |||
| 34794 | switch (mod.declPtr(owner_decl).analysis) { | ||
| 34723 | .file_failure, | 34795 | .file_failure, |
| 34724 | .dependency_failure, | 34796 | .dependency_failure, |
| 34725 | .sema_failure, | 34797 | .sema_failure, |
| 34726 | .sema_failure_retryable, | 34798 | .sema_failure_retryable, |
| 34727 | => { | 34799 | => { |
| 34728 | sema.owner_decl.analysis = .dependency_failure; | 34800 | sema.owner_decl.analysis = .dependency_failure; |
| 34729 | sema.owner_decl.generation = sema.mod.generation; | 34801 | sema.owner_decl.generation = mod.generation; |
| 34730 | return error.AnalysisFail; | 34802 | return error.AnalysisFail; |
| 34731 | }, | 34803 | }, |
| 34732 | else => {}, | 34804 | else => {}, |
| 34733 | } | 34805 | } |
| 34734 | switch (struct_obj.status) { | 34806 | |
| 34735 | .none => {}, | 34807 | if (struct_type.haveFieldTypes(ip)) |
| 34736 | .field_types_wip => { | 34808 | return; |
| 34737 | const msg = try Module.ErrorMsg.create( | 34809 | |
| 34738 | sema.gpa, | 34810 | if (struct_type.flagsPtr(ip).field_types_wip) { |
| 34739 | struct_obj.srcLoc(sema.mod), | 34811 | const msg = try Module.ErrorMsg.create( |
| 34740 | "struct '{}' depends on itself", | 34812 | sema.gpa, |
| 34741 | .{ty.fmt(sema.mod)}, | 34813 | mod.declPtr(owner_decl).srcLoc(mod), |
| 34742 | ); | 34814 | "struct '{}' depends on itself", |
| 34743 | return sema.failWithOwnedErrorMsg(null, msg); | 34815 | .{ty.toType().fmt(mod)}, |
| 34744 | }, | 34816 | ); |
| 34745 | .have_field_types, | 34817 | return sema.failWithOwnedErrorMsg(null, msg); |
| 34746 | .have_layout, | ||
| 34747 | .layout_wip, | ||
| 34748 | .fully_resolved_wip, | ||
| 34749 | .fully_resolved, | ||
| 34750 | => return, | ||
| 34751 | } | 34818 | } |
| 34752 | 34819 | ||
| 34753 | struct_obj.status = .field_types_wip; | 34820 | struct_type.flagsPtr(ip).field_types_wip = true; |
| 34754 | errdefer struct_obj.status = .none; | 34821 | errdefer struct_type.flagsPtr(ip).field_types_wip = false; |
| 34755 | try semaStructFields(sema.mod, struct_obj); | 34822 | |
| 34823 | try semaStructFields(mod, sema.arena, struct_type); | ||
| 34756 | } | 34824 | } |
| 34757 | 34825 | ||
| 34758 | fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Key.UnionType) CompileError!void { | 34826 | fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Key.UnionType) CompileError!void { |
| ... | @@ -34936,12 +35004,19 @@ fn resolveInferredErrorSetTy( | ... | @@ -34936,12 +35004,19 @@ fn resolveInferredErrorSetTy( |
| 34936 | } | 35004 | } |
| 34937 | } | 35005 | } |
| 34938 | 35006 | ||
| 34939 | fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void { | 35007 | fn semaStructFields( |
| 35008 | mod: *Module, | ||
| 35009 | arena: Allocator, | ||
| 35010 | struct_type: InternPool.Key.StructType, | ||
| 35011 | ) CompileError!void { | ||
| 34940 | const gpa = mod.gpa; | 35012 | const gpa = mod.gpa; |
| 34941 | const ip = &mod.intern_pool; | 35013 | const ip = &mod.intern_pool; |
| 34942 | const decl_index = struct_obj.owner_decl; | 35014 | const decl_index = struct_type.decl.unwrap() orelse return; |
| 34943 | const zir = mod.namespacePtr(struct_obj.namespace).file_scope.zir; | 35015 | const decl = mod.declPtr(decl_index); |
| 34944 | const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended; | 35016 | const namespace_index = struct_type.namespace.unwrap() orelse decl.src_namespace; |
| 35017 | const zir = mod.namespacePtr(namespace_index).file_scope.zir; | ||
| 35018 | const zir_index = struct_type.zir_index; | ||
| 35019 | const extended = zir.instructions.items(.data)[zir_index].extended; | ||
| 34945 | assert(extended.opcode == .struct_decl); | 35020 | assert(extended.opcode == .struct_decl); |
| 34946 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); | 35021 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); |
| 34947 | var extra_index: usize = extended.operand; | 35022 | var extra_index: usize = extended.operand; |
| ... | @@ -34977,18 +35052,16 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -34977,18 +35052,16 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 34977 | while (decls_it.next()) |_| {} | 35052 | while (decls_it.next()) |_| {} |
| 34978 | extra_index = decls_it.extra_index; | 35053 | extra_index = decls_it.extra_index; |
| 34979 | 35054 | ||
| 34980 | if (fields_len == 0) { | 35055 | if (fields_len == 0) switch (struct_type.layout) { |
| 34981 | if (struct_obj.layout == .Packed) { | 35056 | .Packed => { |
| 34982 | try semaBackingIntType(mod, struct_obj); | 35057 | try semaBackingIntType(mod, struct_type); |
| 34983 | } | 35058 | return; |
| 34984 | struct_obj.status = .have_layout; | 35059 | }, |
| 34985 | return; | 35060 | .Auto, .Extern => { |
| 34986 | } | 35061 | struct_type.flagsPtr(ip).layout_resolved = true; |
| 34987 | 35062 | return; | |
| 34988 | const decl = mod.declPtr(decl_index); | 35063 | }, |
| 34989 | 35064 | }; | |
| 34990 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); | ||
| 34991 | defer analysis_arena.deinit(); | ||
| 34992 | 35065 | ||
| 34993 | var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa); | 35066 | var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa); |
| 34994 | defer comptime_mutable_decls.deinit(); | 35067 | defer comptime_mutable_decls.deinit(); |
| ... | @@ -34996,7 +35069,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -34996,7 +35069,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 34996 | var sema: Sema = .{ | 35069 | var sema: Sema = .{ |
| 34997 | .mod = mod, | 35070 | .mod = mod, |
| 34998 | .gpa = gpa, | 35071 | .gpa = gpa, |
| 34999 | .arena = analysis_arena.allocator(), | 35072 | .arena = arena, |
| 35000 | .code = zir, | 35073 | .code = zir, |
| 35001 | .owner_decl = decl, | 35074 | .owner_decl = decl, |
| 35002 | .owner_decl_index = decl_index, | 35075 | .owner_decl_index = decl_index, |
| ... | @@ -35013,7 +35086,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -35013,7 +35086,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 35013 | .parent = null, | 35086 | .parent = null, |
| 35014 | .sema = &sema, | 35087 | .sema = &sema, |
| 35015 | .src_decl = decl_index, | 35088 | .src_decl = decl_index, |
| 35016 | .namespace = struct_obj.namespace, | 35089 | .namespace = namespace_index, |
| 35017 | .wip_capture_scope = try mod.createCaptureScope(decl.src_scope), | 35090 | .wip_capture_scope = try mod.createCaptureScope(decl.src_scope), |
| 35018 | .instructions = .{}, | 35091 | .instructions = .{}, |
| 35019 | .inlining = null, | 35092 | .inlining = null, |
| ... | @@ -35021,9 +35094,6 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -35021,9 +35094,6 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 35021 | }; | 35094 | }; |
| 35022 | defer assert(block_scope.instructions.items.len == 0); | 35095 | defer assert(block_scope.instructions.items.len == 0); |
| 35023 | 35096 | ||
| 35024 | struct_obj.fields = .{}; | ||
| 35025 | try struct_obj.fields.ensureTotalCapacity(mod.tmp_hack_arena.allocator(), fields_len); | ||
| 35026 | |||
| 35027 | const Field = struct { | 35097 | const Field = struct { |
| 35028 | type_body_len: u32 = 0, | 35098 | type_body_len: u32 = 0, |
| 35029 | align_body_len: u32 = 0, | 35099 | align_body_len: u32 = 0, |
| ... | @@ -35031,7 +35101,9 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -35031,7 +35101,9 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 35031 | type_ref: Zir.Inst.Ref = .none, | 35101 | type_ref: Zir.Inst.Ref = .none, |
| 35032 | }; | 35102 | }; |
| 35033 | const fields = try sema.arena.alloc(Field, fields_len); | 35103 | const fields = try sema.arena.alloc(Field, fields_len); |
| 35104 | |||
| 35034 | var any_inits = false; | 35105 | var any_inits = false; |
| 35106 | var any_aligned = false; | ||
| 35035 | 35107 | ||
| 35036 | { | 35108 | { |
| 35037 | const bits_per_field = 4; | 35109 | const bits_per_field = 4; |
| ... | @@ -35056,9 +35128,11 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -35056,9 +35128,11 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 35056 | const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0; | 35128 | const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0; |
| 35057 | cur_bit_bag >>= 1; | 35129 | cur_bit_bag >>= 1; |
| 35058 | 35130 | ||
| 35059 | var field_name_zir: ?[:0]const u8 = null; | 35131 | if (is_comptime) struct_type.setFieldComptime(ip, field_i); |
| 35132 | |||
| 35133 | var opt_field_name_zir: ?[:0]const u8 = null; | ||
| 35060 | if (!small.is_tuple) { | 35134 | if (!small.is_tuple) { |
| 35061 | field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]); | 35135 | opt_field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]); |
| 35062 | extra_index += 1; | 35136 | extra_index += 1; |
| 35063 | } | 35137 | } |
| 35064 | extra_index += 1; // doc_comment | 35138 | extra_index += 1; // doc_comment |
| ... | @@ -35073,37 +35147,27 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -35073,37 +35147,27 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 35073 | extra_index += 1; | 35147 | extra_index += 1; |
| 35074 | 35148 | ||
| 35075 | // This string needs to outlive the ZIR code. | 35149 | // This string needs to outlive the ZIR code. |
| 35076 | const field_name = try ip.getOrPutString(gpa, if (field_name_zir) |s| | 35150 | if (opt_field_name_zir) |field_name_zir| { |
| 35077 | s | 35151 | const field_name = try ip.getOrPutString(gpa, field_name_zir); |
| 35078 | else | 35152 | if (struct_type.addFieldName(ip, field_name)) |other_index| { |
| 35079 | try std.fmt.allocPrint(sema.arena, "{d}", .{field_i})); | 35153 | const msg = msg: { |
| 35080 | 35154 | const field_src = mod.fieldSrcLoc(decl_index, .{ .index = field_i }).lazy; | |
| 35081 | const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name); | 35155 | const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{}'", .{field_name.fmt(ip)}); |
| 35082 | if (gop.found_existing) { | 35156 | errdefer msg.destroy(gpa); |
| 35083 | const msg = msg: { | ||
| 35084 | const field_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ .index = field_i }).lazy; | ||
| 35085 | const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{}'", .{field_name.fmt(ip)}); | ||
| 35086 | errdefer msg.destroy(gpa); | ||
| 35087 | 35157 | ||
| 35088 | const prev_field_index = struct_obj.fields.getIndex(field_name).?; | 35158 | const prev_field_src = mod.fieldSrcLoc(decl_index, .{ .index = other_index }); |
| 35089 | const prev_field_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ .index = prev_field_index }); | 35159 | try mod.errNoteNonLazy(prev_field_src, msg, "other field here", .{}); |
| 35090 | try mod.errNoteNonLazy(prev_field_src, msg, "other field here", .{}); | 35160 | try sema.errNote(&block_scope, src, msg, "struct declared here", .{}); |
| 35091 | try sema.errNote(&block_scope, src, msg, "struct declared here", .{}); | 35161 | break :msg msg; |
| 35092 | break :msg msg; | 35162 | }; |
| 35093 | }; | 35163 | return sema.failWithOwnedErrorMsg(&block_scope, msg); |
| 35094 | return sema.failWithOwnedErrorMsg(&block_scope, msg); | 35164 | } |
| 35095 | } | 35165 | } |
| 35096 | gop.value_ptr.* = .{ | ||
| 35097 | .ty = Type.noreturn, | ||
| 35098 | .abi_align = .none, | ||
| 35099 | .default_val = .none, | ||
| 35100 | .is_comptime = is_comptime, | ||
| 35101 | .offset = undefined, | ||
| 35102 | }; | ||
| 35103 | 35166 | ||
| 35104 | if (has_align) { | 35167 | if (has_align) { |
| 35105 | fields[field_i].align_body_len = zir.extra[extra_index]; | 35168 | fields[field_i].align_body_len = zir.extra[extra_index]; |
| 35106 | extra_index += 1; | 35169 | extra_index += 1; |
| 35170 | any_aligned = true; | ||
| 35107 | } | 35171 | } |
| 35108 | if (has_init) { | 35172 | if (has_init) { |
| 35109 | fields[field_i].init_body_len = zir.extra[extra_index]; | 35173 | fields[field_i].init_body_len = zir.extra[extra_index]; |
| ... | @@ -35122,7 +35186,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -35122,7 +35186,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 35122 | if (zir_field.type_ref != .none) { | 35186 | if (zir_field.type_ref != .none) { |
| 35123 | break :ty sema.resolveType(&block_scope, .unneeded, zir_field.type_ref) catch |err| switch (err) { | 35187 | break :ty sema.resolveType(&block_scope, .unneeded, zir_field.type_ref) catch |err| switch (err) { |
| 35124 | error.NeededSourceLocation => { | 35188 | error.NeededSourceLocation => { |
| 35125 | const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | 35189 | const ty_src = mod.fieldSrcLoc(decl_index, .{ |
| 35126 | .index = field_i, | 35190 | .index = field_i, |
| 35127 | .range = .type, | 35191 | .range = .type, |
| 35128 | }).lazy; | 35192 | }).lazy; |
| ... | @@ -35135,10 +35199,10 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -35135,10 +35199,10 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 35135 | assert(zir_field.type_body_len != 0); | 35199 | assert(zir_field.type_body_len != 0); |
| 35136 | const body = zir.extra[extra_index..][0..zir_field.type_body_len]; | 35200 | const body = zir.extra[extra_index..][0..zir_field.type_body_len]; |
| 35137 | extra_index += body.len; | 35201 | extra_index += body.len; |
| 35138 | const ty_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index); | 35202 | const ty_ref = try sema.resolveBody(&block_scope, body, zir_index); |
| 35139 | break :ty sema.analyzeAsType(&block_scope, .unneeded, ty_ref) catch |err| switch (err) { | 35203 | break :ty sema.analyzeAsType(&block_scope, .unneeded, ty_ref) catch |err| switch (err) { |
| 35140 | error.NeededSourceLocation => { | 35204 | error.NeededSourceLocation => { |
| 35141 | const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | 35205 | const ty_src = mod.fieldSrcLoc(decl_index, .{ |
| 35142 | .index = field_i, | 35206 | .index = field_i, |
| 35143 | .range = .type, | 35207 | .range = .type, |
| 35144 | }).lazy; | 35208 | }).lazy; |
| ... | @@ -35152,12 +35216,11 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -35152,12 +35216,11 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 35152 | return error.GenericPoison; | 35216 | return error.GenericPoison; |
| 35153 | } | 35217 | } |
| 35154 | 35218 | ||
| 35155 | const field = &struct_obj.fields.values()[field_i]; | 35219 | struct_type.field_types.get(ip)[field_i] = field_ty.toIntern(); |
| 35156 | field.ty = field_ty; | ||
| 35157 | 35220 | ||
| 35158 | if (field_ty.zigTypeTag(mod) == .Opaque) { | 35221 | if (field_ty.zigTypeTag(mod) == .Opaque) { |
| 35159 | const msg = msg: { | 35222 | const msg = msg: { |
| 35160 | const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | 35223 | const ty_src = mod.fieldSrcLoc(decl_index, .{ |
| 35161 | .index = field_i, | 35224 | .index = field_i, |
| 35162 | .range = .type, | 35225 | .range = .type, |
| 35163 | }).lazy; | 35226 | }).lazy; |
| ... | @@ -35171,7 +35234,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -35171,7 +35234,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 35171 | } | 35234 | } |
| 35172 | if (field_ty.zigTypeTag(mod) == .NoReturn) { | 35235 | if (field_ty.zigTypeTag(mod) == .NoReturn) { |
| 35173 | const msg = msg: { | 35236 | const msg = msg: { |
| 35174 | const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | 35237 | const ty_src = mod.fieldSrcLoc(decl_index, .{ |
| 35175 | .index = field_i, | 35238 | .index = field_i, |
| 35176 | .range = .type, | 35239 | .range = .type, |
| 35177 | }).lazy; | 35240 | }).lazy; |
| ... | @@ -35183,45 +35246,49 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -35183,45 +35246,49 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 35183 | }; | 35246 | }; |
| 35184 | return sema.failWithOwnedErrorMsg(&block_scope, msg); | 35247 | return sema.failWithOwnedErrorMsg(&block_scope, msg); |
| 35185 | } | 35248 | } |
| 35186 | if (struct_obj.layout == .Extern and !try sema.validateExternType(field.ty, .struct_field)) { | 35249 | switch (struct_type.layout) { |
| 35187 | const msg = msg: { | 35250 | .Extern => if (!try sema.validateExternType(field_ty, .struct_field)) { |
| 35188 | const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | 35251 | const msg = msg: { |
| 35189 | .index = field_i, | 35252 | const ty_src = mod.fieldSrcLoc(decl_index, .{ |
| 35190 | .range = .type, | 35253 | .index = field_i, |
| 35191 | }); | 35254 | .range = .type, |
| 35192 | const msg = try sema.errMsg(&block_scope, ty_src.lazy, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(mod)}); | 35255 | }); |
| 35193 | errdefer msg.destroy(sema.gpa); | 35256 | const msg = try sema.errMsg(&block_scope, ty_src.lazy, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(mod)}); |
| 35257 | errdefer msg.destroy(sema.gpa); | ||
| 35194 | 35258 | ||
| 35195 | try sema.explainWhyTypeIsNotExtern(msg, ty_src, field.ty, .struct_field); | 35259 | try sema.explainWhyTypeIsNotExtern(msg, ty_src, field_ty, .struct_field); |
| 35196 | 35260 | ||
| 35197 | try sema.addDeclaredHereNote(msg, field.ty); | 35261 | try sema.addDeclaredHereNote(msg, field_ty); |
| 35198 | break :msg msg; | 35262 | break :msg msg; |
| 35199 | }; | 35263 | }; |
| 35200 | return sema.failWithOwnedErrorMsg(&block_scope, msg); | 35264 | return sema.failWithOwnedErrorMsg(&block_scope, msg); |
| 35201 | } else if (struct_obj.layout == .Packed and !(validatePackedType(field.ty, mod))) { | 35265 | }, |
| 35202 | const msg = msg: { | 35266 | .Packed => if (!validatePackedType(field_ty, mod)) { |
| 35203 | const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | 35267 | const msg = msg: { |
| 35204 | .index = field_i, | 35268 | const ty_src = mod.fieldSrcLoc(decl_index, .{ |
| 35205 | .range = .type, | 35269 | .index = field_i, |
| 35206 | }); | 35270 | .range = .type, |
| 35207 | const msg = try sema.errMsg(&block_scope, ty_src.lazy, "packed structs cannot contain fields of type '{}'", .{field.ty.fmt(mod)}); | 35271 | }); |
| 35208 | errdefer msg.destroy(sema.gpa); | 35272 | const msg = try sema.errMsg(&block_scope, ty_src.lazy, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(mod)}); |
| 35273 | errdefer msg.destroy(sema.gpa); | ||
| 35209 | 35274 | ||
| 35210 | try sema.explainWhyTypeIsNotPacked(msg, ty_src, field.ty); | 35275 | try sema.explainWhyTypeIsNotPacked(msg, ty_src, field_ty); |
| 35211 | 35276 | ||
| 35212 | try sema.addDeclaredHereNote(msg, field.ty); | 35277 | try sema.addDeclaredHereNote(msg, field_ty); |
| 35213 | break :msg msg; | 35278 | break :msg msg; |
| 35214 | }; | 35279 | }; |
| 35215 | return sema.failWithOwnedErrorMsg(&block_scope, msg); | 35280 | return sema.failWithOwnedErrorMsg(&block_scope, msg); |
| 35281 | }, | ||
| 35282 | else => {}, | ||
| 35216 | } | 35283 | } |
| 35217 | 35284 | ||
| 35218 | if (zir_field.align_body_len > 0) { | 35285 | if (zir_field.align_body_len > 0) { |
| 35219 | const body = zir.extra[extra_index..][0..zir_field.align_body_len]; | 35286 | const body = zir.extra[extra_index..][0..zir_field.align_body_len]; |
| 35220 | extra_index += body.len; | 35287 | extra_index += body.len; |
| 35221 | const align_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index); | 35288 | const align_ref = try sema.resolveBody(&block_scope, body, zir_index); |
| 35222 | field.abi_align = sema.analyzeAsAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) { | 35289 | const field_align = sema.analyzeAsAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) { |
| 35223 | error.NeededSourceLocation => { | 35290 | error.NeededSourceLocation => { |
| 35224 | const align_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | 35291 | const align_src = mod.fieldSrcLoc(decl_index, .{ |
| 35225 | .index = field_i, | 35292 | .index = field_i, |
| 35226 | .range = .alignment, | 35293 | .range = .alignment, |
| 35227 | }).lazy; | 35294 | }).lazy; |
| ... | @@ -35230,36 +35297,38 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -35230,36 +35297,38 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 35230 | }, | 35297 | }, |
| 35231 | else => |e| return e, | 35298 | else => |e| return e, |
| 35232 | }; | 35299 | }; |
| 35300 | struct_type.field_aligns.get(ip)[field_i] = field_align; | ||
| 35233 | } | 35301 | } |
| 35234 | 35302 | ||
| 35235 | extra_index += zir_field.init_body_len; | 35303 | extra_index += zir_field.init_body_len; |
| 35236 | } | 35304 | } |
| 35237 | 35305 | ||
| 35238 | struct_obj.status = .have_field_types; | 35306 | // TODO: there seems to be no mechanism to catch when an init depends on |
| 35307 | // another init that hasn't been resolved. | ||
| 35239 | 35308 | ||
| 35240 | if (any_inits) { | 35309 | if (any_inits) { |
| 35241 | extra_index = bodies_index; | 35310 | extra_index = bodies_index; |
| 35242 | for (fields, 0..) |zir_field, field_i| { | 35311 | for (fields, 0..) |zir_field, field_i| { |
| 35312 | const field_ty = struct_type.field_types.get(ip)[field_i].toType(); | ||
| 35243 | extra_index += zir_field.type_body_len; | 35313 | extra_index += zir_field.type_body_len; |
| 35244 | extra_index += zir_field.align_body_len; | 35314 | extra_index += zir_field.align_body_len; |
| 35245 | if (zir_field.init_body_len > 0) { | 35315 | if (zir_field.init_body_len > 0) { |
| 35246 | const body = zir.extra[extra_index..][0..zir_field.init_body_len]; | 35316 | const body = zir.extra[extra_index..][0..zir_field.init_body_len]; |
| 35247 | extra_index += body.len; | 35317 | extra_index += body.len; |
| 35248 | const init = try sema.resolveBody(&block_scope, body, struct_obj.zir_index); | 35318 | const init = try sema.resolveBody(&block_scope, body, zir_index); |
| 35249 | const field = &struct_obj.fields.values()[field_i]; | 35319 | const coerced = sema.coerce(&block_scope, field_ty, init, .unneeded) catch |err| switch (err) { |
| 35250 | const coerced = sema.coerce(&block_scope, field.ty, init, .unneeded) catch |err| switch (err) { | ||
| 35251 | error.NeededSourceLocation => { | 35320 | error.NeededSourceLocation => { |
| 35252 | const init_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | 35321 | const init_src = mod.fieldSrcLoc(decl_index, .{ |
| 35253 | .index = field_i, | 35322 | .index = field_i, |
| 35254 | .range = .value, | 35323 | .range = .value, |
| 35255 | }).lazy; | 35324 | }).lazy; |
| 35256 | _ = try sema.coerce(&block_scope, field.ty, init, init_src); | 35325 | _ = try sema.coerce(&block_scope, field_ty, init, init_src); |
| 35257 | unreachable; | 35326 | unreachable; |
| 35258 | }, | 35327 | }, |
| 35259 | else => |e| return e, | 35328 | else => |e| return e, |
| 35260 | }; | 35329 | }; |
| 35261 | const default_val = (try sema.resolveMaybeUndefVal(coerced)) orelse { | 35330 | const default_val = (try sema.resolveMaybeUndefVal(coerced)) orelse { |
| 35262 | const init_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | 35331 | const init_src = mod.fieldSrcLoc(decl_index, .{ |
| 35263 | .index = field_i, | 35332 | .index = field_i, |
| 35264 | .range = .value, | 35333 | .range = .value, |
| 35265 | }).lazy; | 35334 | }).lazy; |
| ... | @@ -35267,7 +35336,8 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -35267,7 +35336,8 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 35267 | .needed_comptime_reason = "struct field default value must be comptime-known", | 35336 | .needed_comptime_reason = "struct field default value must be comptime-known", |
| 35268 | }); | 35337 | }); |
| 35269 | }; | 35338 | }; |
| 35270 | field.default_val = try default_val.intern(field.ty, mod); | 35339 | const field_init = try default_val.intern(field_ty, mod); |
| 35340 | struct_type.field_inits.get(ip)[field_i] = field_init; | ||
| 35271 | } | 35341 | } |
| 35272 | } | 35342 | } |
| 35273 | } | 35343 | } |
| ... | @@ -35275,8 +35345,6 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -35275,8 +35345,6 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 35275 | const ct_decl = mod.declPtr(ct_decl_index); | 35345 | const ct_decl = mod.declPtr(ct_decl_index); |
| 35276 | _ = try ct_decl.internValue(mod); | 35346 | _ = try ct_decl.internValue(mod); |
| 35277 | } | 35347 | } |
| 35278 | |||
| 35279 | struct_obj.have_field_inits = true; | ||
| 35280 | } | 35348 | } |
| 35281 | 35349 | ||
| 35282 | fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.UnionType) CompileError!void { | 35350 | fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.UnionType) CompileError!void { |
| ... | @@ -36060,6 +36128,8 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { | ... | @@ -36060,6 +36128,8 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { |
| 36060 | .type_struct, | 36128 | .type_struct, |
| 36061 | .type_struct_ns, | 36129 | .type_struct_ns, |
| 36062 | .type_struct_anon, | 36130 | .type_struct_anon, |
| 36131 | .type_struct_packed, | ||
| 36132 | .type_struct_packed_inits, | ||
| 36063 | .type_tuple_anon, | 36133 | .type_tuple_anon, |
| 36064 | .type_union, | 36134 | .type_union, |
| 36065 | => switch (ip.indexToKey(ty.toIntern())) { | 36135 | => switch (ip.indexToKey(ty.toIntern())) { |
| ... | @@ -36081,41 +36151,46 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { | ... | @@ -36081,41 +36151,46 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { |
| 36081 | 36151 | ||
| 36082 | .struct_type => |struct_type| { | 36152 | .struct_type => |struct_type| { |
| 36083 | try sema.resolveTypeFields(ty); | 36153 | try sema.resolveTypeFields(ty); |
| 36084 | if (mod.structPtrUnwrap(struct_type.index)) |s| { | ||
| 36085 | const field_vals = try sema.arena.alloc(InternPool.Index, s.fields.count()); | ||
| 36086 | for (field_vals, s.fields.values(), 0..) |*field_val, field, i| { | ||
| 36087 | if (field.is_comptime) { | ||
| 36088 | field_val.* = field.default_val; | ||
| 36089 | continue; | ||
| 36090 | } | ||
| 36091 | if (field.ty.eql(ty, mod)) { | ||
| 36092 | const msg = try Module.ErrorMsg.create( | ||
| 36093 | sema.gpa, | ||
| 36094 | s.srcLoc(mod), | ||
| 36095 | "struct '{}' depends on itself", | ||
| 36096 | .{ty.fmt(mod)}, | ||
| 36097 | ); | ||
| 36098 | try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{}); | ||
| 36099 | return sema.failWithOwnedErrorMsg(null, msg); | ||
| 36100 | } | ||
| 36101 | if (try sema.typeHasOnePossibleValue(field.ty)) |field_opv| { | ||
| 36102 | field_val.* = try field_opv.intern(field.ty, mod); | ||
| 36103 | } else return null; | ||
| 36104 | } | ||
| 36105 | 36154 | ||
| 36106 | // In this case the struct has no runtime-known fields and | 36155 | if (struct_type.field_types.len == 0) { |
| 36156 | // In this case the struct has no fields at all and | ||
| 36107 | // therefore has one possible value. | 36157 | // therefore has one possible value. |
| 36108 | return (try mod.intern(.{ .aggregate = .{ | 36158 | return (try mod.intern(.{ .aggregate = .{ |
| 36109 | .ty = ty.toIntern(), | 36159 | .ty = ty.toIntern(), |
| 36110 | .storage = .{ .elems = field_vals }, | 36160 | .storage = .{ .elems = &.{} }, |
| 36111 | } })).toValue(); | 36161 | } })).toValue(); |
| 36112 | } | 36162 | } |
| 36113 | 36163 | ||
| 36114 | // In this case the struct has no fields at all and | 36164 | const field_vals = try sema.arena.alloc( |
| 36165 | InternPool.Index, | ||
| 36166 | struct_type.field_types.len, | ||
| 36167 | ); | ||
| 36168 | for (field_vals, 0..) |*field_val, i| { | ||
| 36169 | if (struct_type.comptime_bits.getBit(ip, i)) { | ||
| 36170 | field_val.* = struct_type.field_inits.get(ip)[i]; | ||
| 36171 | continue; | ||
| 36172 | } | ||
| 36173 | const field_ty = struct_type.field_types.get(ip)[i].toType(); | ||
| 36174 | if (field_ty.eql(ty, mod)) { | ||
| 36175 | const msg = try Module.ErrorMsg.create( | ||
| 36176 | sema.gpa, | ||
| 36177 | mod.declPtr(struct_type.decl.unwrap().?).srcLoc(mod), | ||
| 36178 | "struct '{}' depends on itself", | ||
| 36179 | .{ty.fmt(mod)}, | ||
| 36180 | ); | ||
| 36181 | try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{}); | ||
| 36182 | return sema.failWithOwnedErrorMsg(null, msg); | ||
| 36183 | } | ||
| 36184 | if (try sema.typeHasOnePossibleValue(field_ty)) |field_opv| { | ||
| 36185 | field_val.* = try field_opv.intern(field_ty, mod); | ||
| 36186 | } else return null; | ||
| 36187 | } | ||
| 36188 | |||
| 36189 | // In this case the struct has no runtime-known fields and | ||
| 36115 | // therefore has one possible value. | 36190 | // therefore has one possible value. |
| 36116 | return (try mod.intern(.{ .aggregate = .{ | 36191 | return (try mod.intern(.{ .aggregate = .{ |
| 36117 | .ty = ty.toIntern(), | 36192 | .ty = ty.toIntern(), |
| 36118 | .storage = .{ .elems = &.{} }, | 36193 | .storage = .{ .elems = field_vals }, |
| 36119 | } })).toValue(); | 36194 | } })).toValue(); |
| 36120 | }, | 36195 | }, |
| 36121 | 36196 | ||
| ... | @@ -36574,25 +36649,32 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { | ... | @@ -36574,25 +36649,32 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { |
| 36574 | => true, | 36649 | => true, |
| 36575 | }, | 36650 | }, |
| 36576 | .struct_type => |struct_type| { | 36651 | .struct_type => |struct_type| { |
| 36577 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false; | 36652 | if (struct_type.layout == .Packed) { |
| 36578 | switch (struct_obj.requires_comptime) { | 36653 | // packed structs cannot be comptime-only because they have a well-defined |
| 36654 | // memory layout and every field has a well-defined bit pattern. | ||
| 36655 | return false; | ||
| 36656 | } | ||
| 36657 | switch (struct_type.flagsPtr(ip).requires_comptime) { | ||
| 36579 | .no, .wip => return false, | 36658 | .no, .wip => return false, |
| 36580 | .yes => return true, | 36659 | .yes => return true, |
| 36581 | .unknown => { | 36660 | .unknown => { |
| 36582 | if (struct_obj.status == .field_types_wip) | 36661 | if (struct_type.flagsPtr(ip).field_types_wip) |
| 36583 | return false; | 36662 | return false; |
| 36584 | 36663 | ||
| 36585 | try sema.resolveTypeFieldsStruct(ty, struct_obj); | 36664 | try sema.resolveTypeFieldsStruct(ty.toIntern(), struct_type); |
| 36665 | |||
| 36666 | struct_type.flagsPtr(ip).requires_comptime = .wip; | ||
| 36586 | 36667 | ||
| 36587 | struct_obj.requires_comptime = .wip; | 36668 | for (0..struct_type.field_types.len) |i_usize| { |
| 36588 | for (struct_obj.fields.values()) |field| { | 36669 | const i: u32 = @intCast(i_usize); |
| 36589 | if (field.is_comptime) continue; | 36670 | if (struct_type.fieldIsComptime(ip, i)) continue; |
| 36590 | if (try sema.typeRequiresComptime(field.ty)) { | 36671 | const field_ty = struct_type.field_types.get(ip)[i]; |
| 36591 | struct_obj.requires_comptime = .yes; | 36672 | if (try sema.typeRequiresComptime(field_ty.toType())) { |
| 36673 | struct_type.setRequiresComptime(ip); | ||
| 36592 | return true; | 36674 | return true; |
| 36593 | } | 36675 | } |
| 36594 | } | 36676 | } |
| 36595 | struct_obj.requires_comptime = .no; | 36677 | struct_type.flagsPtr(ip).requires_comptime = .no; |
| 36596 | return false; | 36678 | return false; |
| 36597 | }, | 36679 | }, |
| 36598 | } | 36680 | } |
| ... | @@ -36673,40 +36755,41 @@ fn typeAbiSize(sema: *Sema, ty: Type) !u64 { | ... | @@ -36673,40 +36755,41 @@ fn typeAbiSize(sema: *Sema, ty: Type) !u64 { |
| 36673 | return ty.abiSize(sema.mod); | 36755 | return ty.abiSize(sema.mod); |
| 36674 | } | 36756 | } |
| 36675 | 36757 | ||
| 36676 | fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!u32 { | 36758 | fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!Alignment { |
| 36677 | return (try ty.abiAlignmentAdvanced(sema.mod, .{ .sema = sema })).scalar; | 36759 | return (try ty.abiAlignmentAdvanced(sema.mod, .{ .sema = sema })).scalar; |
| 36678 | } | 36760 | } |
| 36679 | 36761 | ||
| 36680 | /// Not valid to call for packed unions. | 36762 | /// Not valid to call for packed unions. |
| 36681 | /// Keep implementation in sync with `Module.unionFieldNormalAlignment`. | 36763 | /// Keep implementation in sync with `Module.unionFieldNormalAlignment`. |
| 36682 | /// TODO: this returns alignment in byte units should should be a u64 | 36764 | fn unionFieldAlignment(sema: *Sema, u: InternPool.UnionType, field_index: u32) !Alignment { |
| 36683 | fn unionFieldAlignment(sema: *Sema, u: InternPool.UnionType, field_index: u32) !u32 { | ||
| 36684 | const mod = sema.mod; | 36765 | const mod = sema.mod; |
| 36685 | const ip = &mod.intern_pool; | 36766 | const ip = &mod.intern_pool; |
| 36686 | if (u.fieldAlign(ip, field_index).toByteUnitsOptional()) |a| return @intCast(a); | 36767 | const field_align = u.fieldAlign(ip, field_index); |
| 36768 | if (field_align != .none) return field_align; | ||
| 36687 | const field_ty = u.field_types.get(ip)[field_index].toType(); | 36769 | const field_ty = u.field_types.get(ip)[field_index].toType(); |
| 36688 | if (field_ty.isNoReturn(sema.mod)) return 0; | 36770 | if (field_ty.isNoReturn(sema.mod)) return .none; |
| 36689 | return @intCast(try sema.typeAbiAlignment(field_ty)); | 36771 | return sema.typeAbiAlignment(field_ty); |
| 36690 | } | 36772 | } |
| 36691 | 36773 | ||
| 36692 | /// Keep implementation in sync with `Module.Struct.Field.alignment`. | 36774 | /// Keep implementation in sync with `Module.structFieldAlignment`. |
| 36693 | fn structFieldAlignment(sema: *Sema, field: Module.Struct.Field, layout: std.builtin.Type.ContainerLayout) !u32 { | 36775 | fn structFieldAlignment( |
| 36776 | sema: *Sema, | ||
| 36777 | explicit_alignment: InternPool.Alignment, | ||
| 36778 | field_ty: Type, | ||
| 36779 | layout: std.builtin.Type.ContainerLayout, | ||
| 36780 | ) !Alignment { | ||
| 36781 | if (explicit_alignment != .none) | ||
| 36782 | return explicit_alignment; | ||
| 36694 | const mod = sema.mod; | 36783 | const mod = sema.mod; |
| 36695 | if (field.abi_align.toByteUnitsOptional()) |a| { | ||
| 36696 | assert(layout != .Packed); | ||
| 36697 | return @intCast(a); | ||
| 36698 | } | ||
| 36699 | switch (layout) { | 36784 | switch (layout) { |
| 36700 | .Packed => return 0, | 36785 | .Packed => return .none, |
| 36701 | .Auto => if (mod.getTarget().ofmt != .c) { | 36786 | .Auto => if (mod.getTarget().ofmt != .c) return sema.typeAbiAlignment(field_ty), |
| 36702 | return sema.typeAbiAlignment(field.ty); | ||
| 36703 | }, | ||
| 36704 | .Extern => {}, | 36787 | .Extern => {}, |
| 36705 | } | 36788 | } |
| 36706 | // extern | 36789 | // extern |
| 36707 | const ty_abi_align = try sema.typeAbiAlignment(field.ty); | 36790 | const ty_abi_align = try sema.typeAbiAlignment(field_ty); |
| 36708 | if (field.ty.isAbiInt(mod) and field.ty.intInfo(mod).bits >= 128) { | 36791 | if (field_ty.isAbiInt(mod) and field_ty.intInfo(mod).bits >= 128) { |
| 36709 | return @max(ty_abi_align, 16); | 36792 | return ty_abi_align.max(.@"16"); |
| 36710 | } | 36793 | } |
| 36711 | return ty_abi_align; | 36794 | return ty_abi_align; |
| 36712 | } | 36795 | } |
| ... | @@ -36752,14 +36835,14 @@ fn structFieldIndex( | ... | @@ -36752,14 +36835,14 @@ fn structFieldIndex( |
| 36752 | field_src: LazySrcLoc, | 36835 | field_src: LazySrcLoc, |
| 36753 | ) !u32 { | 36836 | ) !u32 { |
| 36754 | const mod = sema.mod; | 36837 | const mod = sema.mod; |
| 36838 | const ip = &mod.intern_pool; | ||
| 36755 | try sema.resolveTypeFields(struct_ty); | 36839 | try sema.resolveTypeFields(struct_ty); |
| 36756 | if (struct_ty.isAnonStruct(mod)) { | 36840 | if (struct_ty.isAnonStruct(mod)) { |
| 36757 | return sema.anonStructFieldIndex(block, struct_ty, field_name, field_src); | 36841 | return sema.anonStructFieldIndex(block, struct_ty, field_name, field_src); |
| 36758 | } else { | 36842 | } else { |
| 36759 | const struct_obj = mod.typeToStruct(struct_ty).?; | 36843 | const struct_type = mod.typeToStruct(struct_ty).?; |
| 36760 | const field_index_usize = struct_obj.fields.getIndex(field_name) orelse | 36844 | return struct_type.nameIndex(ip, field_name) orelse |
| 36761 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name); | 36845 | return sema.failWithBadStructFieldAccess(block, struct_type, field_src, field_name); |
| 36762 | return @intCast(field_index_usize); | ||
| 36763 | } | 36846 | } |
| 36764 | } | 36847 | } |
| 36765 | 36848 | ||
| ... | @@ -36776,13 +36859,7 @@ fn anonStructFieldIndex( | ... | @@ -36776,13 +36859,7 @@ fn anonStructFieldIndex( |
| 36776 | .anon_struct_type => |anon_struct_type| for (anon_struct_type.names.get(ip), 0..) |name, i| { | 36859 | .anon_struct_type => |anon_struct_type| for (anon_struct_type.names.get(ip), 0..) |name, i| { |
| 36777 | if (name == field_name) return @intCast(i); | 36860 | if (name == field_name) return @intCast(i); |
| 36778 | }, | 36861 | }, |
| 36779 | .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| { | 36862 | .struct_type => |struct_type| if (struct_type.nameIndex(ip, field_name)) |i| return i, |
| 36780 | for (struct_obj.fields.keys(), 0..) |name, i| { | ||
| 36781 | if (name == field_name) { | ||
| 36782 | return @intCast(i); | ||
| 36783 | } | ||
| 36784 | } | ||
| 36785 | }, | ||
| 36786 | else => unreachable, | 36863 | else => unreachable, |
| 36787 | } | 36864 | } |
| 36788 | return sema.fail(block, field_src, "no field named '{}' in anonymous struct '{}'", .{ | 36865 | return sema.fail(block, field_src, "no field named '{}' in anonymous struct '{}'", .{ |
| ... | @@ -37167,8 +37244,8 @@ fn intFitsInType( | ... | @@ -37167,8 +37244,8 @@ fn intFitsInType( |
| 37167 | // If it is u16 or bigger we know the alignment fits without resolving it. | 37244 | // If it is u16 or bigger we know the alignment fits without resolving it. |
| 37168 | if (info.bits >= max_needed_bits) return true; | 37245 | if (info.bits >= max_needed_bits) return true; |
| 37169 | const x = try sema.typeAbiAlignment(lazy_ty.toType()); | 37246 | const x = try sema.typeAbiAlignment(lazy_ty.toType()); |
| 37170 | if (x == 0) return true; | 37247 | if (x == .none) return true; |
| 37171 | const actual_needed_bits = std.math.log2(x) + 1 + @intFromBool(info.signedness == .signed); | 37248 | const actual_needed_bits = @as(usize, x.toLog2Units()) + 1 + @intFromBool(info.signedness == .signed); |
| 37172 | return info.bits >= actual_needed_bits; | 37249 | return info.bits >= actual_needed_bits; |
| 37173 | }, | 37250 | }, |
| 37174 | .lazy_size => |lazy_ty| { | 37251 | .lazy_size => |lazy_ty| { |
| ... | @@ -37381,7 +37458,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { | ... | @@ -37381,7 +37458,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { |
| 37381 | 37458 | ||
| 37382 | const vector_info: struct { | 37459 | const vector_info: struct { |
| 37383 | host_size: u16 = 0, | 37460 | host_size: u16 = 0, |
| 37384 | alignment: u32 = 0, | 37461 | alignment: Alignment = .none, |
| 37385 | vector_index: VI = .none, | 37462 | vector_index: VI = .none, |
| 37386 | } = if (parent_ty.isVector(mod) and ptr_info.flags.size == .One) blk: { | 37463 | } = if (parent_ty.isVector(mod) and ptr_info.flags.size == .One) blk: { |
| 37387 | const elem_bits = elem_ty.bitSize(mod); | 37464 | const elem_bits = elem_ty.bitSize(mod); |
| ... | @@ -37391,7 +37468,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { | ... | @@ -37391,7 +37468,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { |
| 37391 | 37468 | ||
| 37392 | break :blk .{ | 37469 | break :blk .{ |
| 37393 | .host_size = @intCast(parent_ty.arrayLen(mod)), | 37470 | .host_size = @intCast(parent_ty.arrayLen(mod)), |
| 37394 | .alignment = @intCast(parent_ty.abiAlignment(mod)), | 37471 | .alignment = parent_ty.abiAlignment(mod), |
| 37395 | .vector_index = if (offset) |some| @enumFromInt(some) else .runtime, | 37472 | .vector_index = if (offset) |some| @enumFromInt(some) else .runtime, |
| 37396 | }; | 37473 | }; |
| 37397 | } else .{}; | 37474 | } else .{}; |
| ... | @@ -37399,9 +37476,9 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { | ... | @@ -37399,9 +37476,9 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { |
| 37399 | const alignment: Alignment = a: { | 37476 | const alignment: Alignment = a: { |
| 37400 | // Calculate the new pointer alignment. | 37477 | // Calculate the new pointer alignment. |
| 37401 | if (ptr_info.flags.alignment == .none) { | 37478 | if (ptr_info.flags.alignment == .none) { |
| 37402 | if (vector_info.alignment != 0) break :a Alignment.fromNonzeroByteUnits(vector_info.alignment); | 37479 | // In case of an ABI-aligned pointer, any pointer arithmetic |
| 37403 | // ABI-aligned pointer. Any pointer arithmetic maintains the same ABI-alignedness. | 37480 | // maintains the same ABI-alignedness. |
| 37404 | break :a .none; | 37481 | break :a vector_info.alignment; |
| 37405 | } | 37482 | } |
| 37406 | // If the addend is not a comptime-known value we can still count on | 37483 | // If the addend is not a comptime-known value we can still count on |
| 37407 | // it being a multiple of the type size. | 37484 | // it being a multiple of the type size. |
| ... | @@ -37413,7 +37490,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { | ... | @@ -37413,7 +37490,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { |
| 37413 | // non zero). | 37490 | // non zero). |
| 37414 | const new_align: Alignment = @enumFromInt(@min( | 37491 | const new_align: Alignment = @enumFromInt(@min( |
| 37415 | @ctz(addend), | 37492 | @ctz(addend), |
| 37416 | @intFromEnum(ptr_info.flags.alignment), | 37493 | ptr_info.flags.alignment.toLog2Units(), |
| 37417 | )); | 37494 | )); |
| 37418 | assert(new_align != .none); | 37495 | assert(new_align != .none); |
| 37419 | break :a new_align; | 37496 | break :a new_align; |
src/TypedValue.zig+1-1| ... | @@ -432,7 +432,7 @@ fn printAggregate( | ... | @@ -432,7 +432,7 @@ fn printAggregate( |
| 432 | if (i != 0) try writer.writeAll(", "); | 432 | if (i != 0) try writer.writeAll(", "); |
| 433 | 433 | ||
| 434 | const field_name = switch (ip.indexToKey(ty.toIntern())) { | 434 | const field_name = switch (ip.indexToKey(ty.toIntern())) { |
| 435 | .struct_type => |x| mod.structPtrUnwrap(x.index).?.fields.keys()[i].toOptional(), | 435 | .struct_type => |x| x.field_names.get(ip)[i].toOptional(), |
| 436 | .anon_struct_type => |x| if (x.isTuple()) .none else x.names.get(ip)[i].toOptional(), | 436 | .anon_struct_type => |x| if (x.isTuple()) .none else x.names.get(ip)[i].toOptional(), |
| 437 | else => unreachable, | 437 | else => unreachable, |
| 438 | }; | 438 | }; |
src/arch/aarch64/CodeGen.zig+20-27| ... | @@ -23,6 +23,7 @@ const DW = std.dwarf; | ... | @@ -23,6 +23,7 @@ const DW = std.dwarf; |
| 23 | const leb128 = std.leb; | 23 | const leb128 = std.leb; |
| 24 | const log = std.log.scoped(.codegen); | 24 | const log = std.log.scoped(.codegen); |
| 25 | const build_options = @import("build_options"); | 25 | const build_options = @import("build_options"); |
| 26 | const Alignment = InternPool.Alignment; | ||
| 26 | 27 | ||
| 27 | const CodeGenError = codegen.CodeGenError; | 28 | const CodeGenError = codegen.CodeGenError; |
| 28 | const Result = codegen.Result; | 29 | const Result = codegen.Result; |
| ... | @@ -506,11 +507,9 @@ fn gen(self: *Self) !void { | ... | @@ -506,11 +507,9 @@ fn gen(self: *Self) !void { |
| 506 | // (or w0 when pointer size is 32 bits). As this register | 507 | // (or w0 when pointer size is 32 bits). As this register |
| 507 | // might get overwritten along the way, save the address | 508 | // might get overwritten along the way, save the address |
| 508 | // to the stack. | 509 | // to the stack. |
| 509 | const ptr_bits = self.target.ptrBitWidth(); | ||
| 510 | const ptr_bytes = @divExact(ptr_bits, 8); | ||
| 511 | const ret_ptr_reg = self.registerAlias(.x0, Type.usize); | 510 | const ret_ptr_reg = self.registerAlias(.x0, Type.usize); |
| 512 | 511 | ||
| 513 | const stack_offset = try self.allocMem(ptr_bytes, ptr_bytes, null); | 512 | const stack_offset = try self.allocMem(8, .@"8", null); |
| 514 | 513 | ||
| 515 | try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = ret_ptr_reg }); | 514 | try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = ret_ptr_reg }); |
| 516 | self.ret_mcv = MCValue{ .stack_offset = stack_offset }; | 515 | self.ret_mcv = MCValue{ .stack_offset = stack_offset }; |
| ... | @@ -998,11 +997,11 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { | ... | @@ -998,11 +997,11 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { |
| 998 | fn allocMem( | 997 | fn allocMem( |
| 999 | self: *Self, | 998 | self: *Self, |
| 1000 | abi_size: u32, | 999 | abi_size: u32, |
| 1001 | abi_align: u32, | 1000 | abi_align: Alignment, |
| 1002 | maybe_inst: ?Air.Inst.Index, | 1001 | maybe_inst: ?Air.Inst.Index, |
| 1003 | ) !u32 { | 1002 | ) !u32 { |
| 1004 | assert(abi_size > 0); | 1003 | assert(abi_size > 0); |
| 1005 | assert(abi_align > 0); | 1004 | assert(abi_align != .none); |
| 1006 | 1005 | ||
| 1007 | // In order to efficiently load and store stack items that fit | 1006 | // In order to efficiently load and store stack items that fit |
| 1008 | // into registers, we bump up the alignment to the next power of | 1007 | // into registers, we bump up the alignment to the next power of |
| ... | @@ -1010,10 +1009,10 @@ fn allocMem( | ... | @@ -1010,10 +1009,10 @@ fn allocMem( |
| 1010 | const adjusted_align = if (abi_size > 8) | 1009 | const adjusted_align = if (abi_size > 8) |
| 1011 | abi_align | 1010 | abi_align |
| 1012 | else | 1011 | else |
| 1013 | std.math.ceilPowerOfTwoAssert(u32, abi_size); | 1012 | Alignment.fromNonzeroByteUnits(std.math.ceilPowerOfTwoAssert(u64, abi_size)); |
| 1014 | 1013 | ||
| 1015 | // TODO find a free slot instead of always appending | 1014 | // TODO find a free slot instead of always appending |
| 1016 | const offset = mem.alignForward(u32, self.next_stack_offset, adjusted_align) + abi_size; | 1015 | const offset: u32 = @intCast(adjusted_align.forward(self.next_stack_offset) + abi_size); |
| 1017 | self.next_stack_offset = offset; | 1016 | self.next_stack_offset = offset; |
| 1018 | self.max_end_stack = @max(self.max_end_stack, self.next_stack_offset); | 1017 | self.max_end_stack = @max(self.max_end_stack, self.next_stack_offset); |
| 1019 | 1018 | ||
| ... | @@ -1515,12 +1514,9 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1515,12 +1514,9 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1515 | const len = try self.resolveInst(bin_op.rhs); | 1514 | const len = try self.resolveInst(bin_op.rhs); |
| 1516 | const len_ty = self.typeOf(bin_op.rhs); | 1515 | const len_ty = self.typeOf(bin_op.rhs); |
| 1517 | 1516 | ||
| 1518 | const ptr_bits = self.target.ptrBitWidth(); | 1517 | const stack_offset = try self.allocMem(16, .@"8", inst); |
| 1519 | const ptr_bytes = @divExact(ptr_bits, 8); | ||
| 1520 | |||
| 1521 | const stack_offset = try self.allocMem(ptr_bytes * 2, ptr_bytes * 2, inst); | ||
| 1522 | try self.genSetStack(ptr_ty, stack_offset, ptr); | 1518 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 1523 | try self.genSetStack(len_ty, stack_offset - ptr_bytes, len); | 1519 | try self.genSetStack(len_ty, stack_offset - 8, len); |
| 1524 | break :result MCValue{ .stack_offset = stack_offset }; | 1520 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1525 | }; | 1521 | }; |
| 1526 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1522 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| ... | @@ -3285,9 +3281,9 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3285,9 +3281,9 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 3285 | break :result MCValue{ .register = reg }; | 3281 | break :result MCValue{ .register = reg }; |
| 3286 | } | 3282 | } |
| 3287 | 3283 | ||
| 3288 | const optional_abi_size = @as(u32, @intCast(optional_ty.abiSize(mod))); | 3284 | const optional_abi_size: u32 = @intCast(optional_ty.abiSize(mod)); |
| 3289 | const optional_abi_align = optional_ty.abiAlignment(mod); | 3285 | const optional_abi_align = optional_ty.abiAlignment(mod); |
| 3290 | const offset = @as(u32, @intCast(payload_ty.abiSize(mod))); | 3286 | const offset: u32 = @intCast(payload_ty.abiSize(mod)); |
| 3291 | 3287 | ||
| 3292 | const stack_offset = try self.allocMem(optional_abi_size, optional_abi_align, inst); | 3288 | const stack_offset = try self.allocMem(optional_abi_size, optional_abi_align, inst); |
| 3293 | try self.genSetStack(payload_ty, stack_offset, operand); | 3289 | try self.genSetStack(payload_ty, stack_offset, operand); |
| ... | @@ -3376,7 +3372,7 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3376,7 +3372,7 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3376 | fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { | 3372 | fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 3377 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3373 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3378 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 3374 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 3379 | const ptr_bits = self.target.ptrBitWidth(); | 3375 | const ptr_bits = 64; |
| 3380 | const ptr_bytes = @divExact(ptr_bits, 8); | 3376 | const ptr_bytes = @divExact(ptr_bits, 8); |
| 3381 | const mcv = try self.resolveInst(ty_op.operand); | 3377 | const mcv = try self.resolveInst(ty_op.operand); |
| 3382 | switch (mcv) { | 3378 | switch (mcv) { |
| ... | @@ -3400,7 +3396,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3400,7 +3396,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 3400 | fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { | 3396 | fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3401 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3397 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3402 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 3398 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 3403 | const ptr_bits = self.target.ptrBitWidth(); | 3399 | const ptr_bits = 64; |
| 3404 | const ptr_bytes = @divExact(ptr_bits, 8); | 3400 | const ptr_bytes = @divExact(ptr_bits, 8); |
| 3405 | const mcv = try self.resolveInst(ty_op.operand); | 3401 | const mcv = try self.resolveInst(ty_op.operand); |
| 3406 | switch (mcv) { | 3402 | switch (mcv) { |
| ... | @@ -4272,8 +4268,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -4272,8 +4268,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4272 | if (info.return_value == .stack_offset) { | 4268 | if (info.return_value == .stack_offset) { |
| 4273 | log.debug("airCall: return by reference", .{}); | 4269 | log.debug("airCall: return by reference", .{}); |
| 4274 | const ret_ty = fn_ty.fnReturnType(mod); | 4270 | const ret_ty = fn_ty.fnReturnType(mod); |
| 4275 | const ret_abi_size = @as(u32, @intCast(ret_ty.abiSize(mod))); | 4271 | const ret_abi_size: u32 = @intCast(ret_ty.abiSize(mod)); |
| 4276 | const ret_abi_align = @as(u32, @intCast(ret_ty.abiAlignment(mod))); | 4272 | const ret_abi_align = ret_ty.abiAlignment(mod); |
| 4277 | const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst); | 4273 | const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst); |
| 4278 | 4274 | ||
| 4279 | const ret_ptr_reg = self.registerAlias(.x0, Type.usize); | 4275 | const ret_ptr_reg = self.registerAlias(.x0, Type.usize); |
| ... | @@ -5939,11 +5935,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5939,11 +5935,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 5939 | const ptr = try self.resolveInst(ty_op.operand); | 5935 | const ptr = try self.resolveInst(ty_op.operand); |
| 5940 | const array_ty = ptr_ty.childType(mod); | 5936 | const array_ty = ptr_ty.childType(mod); |
| 5941 | const array_len = @as(u32, @intCast(array_ty.arrayLen(mod))); | 5937 | const array_len = @as(u32, @intCast(array_ty.arrayLen(mod))); |
| 5942 | 5938 | const ptr_bytes = 8; | |
| 5943 | const ptr_bits = self.target.ptrBitWidth(); | 5939 | const stack_offset = try self.allocMem(ptr_bytes * 2, .@"8", inst); |
| 5944 | const ptr_bytes = @divExact(ptr_bits, 8); | ||
| 5945 | |||
| 5946 | const stack_offset = try self.allocMem(ptr_bytes * 2, ptr_bytes * 2, inst); | ||
| 5947 | try self.genSetStack(ptr_ty, stack_offset, ptr); | 5940 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 5948 | try self.genSetStack(Type.usize, stack_offset - ptr_bytes, .{ .immediate = array_len }); | 5941 | try self.genSetStack(Type.usize, stack_offset - ptr_bytes, .{ .immediate = array_len }); |
| 5949 | break :result MCValue{ .stack_offset = stack_offset }; | 5942 | break :result MCValue{ .stack_offset = stack_offset }; |
| ... | @@ -6254,7 +6247,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6254,7 +6247,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6254 | 6247 | ||
| 6255 | // We round up NCRN only for non-Apple platforms which allow the 16-byte aligned | 6248 | // We round up NCRN only for non-Apple platforms which allow the 16-byte aligned |
| 6256 | // values to spread across odd-numbered registers. | 6249 | // values to spread across odd-numbered registers. |
| 6257 | if (ty.toType().abiAlignment(mod) == 16 and !self.target.isDarwin()) { | 6250 | if (ty.toType().abiAlignment(mod) == .@"16" and !self.target.isDarwin()) { |
| 6258 | // Round up NCRN to the next even number | 6251 | // Round up NCRN to the next even number |
| 6259 | ncrn += ncrn % 2; | 6252 | ncrn += ncrn % 2; |
| 6260 | } | 6253 | } |
| ... | @@ -6272,7 +6265,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6272,7 +6265,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6272 | ncrn = 8; | 6265 | ncrn = 8; |
| 6273 | // TODO Apple allows the arguments on the stack to be non-8-byte aligned provided | 6266 | // TODO Apple allows the arguments on the stack to be non-8-byte aligned provided |
| 6274 | // that the entire stack space consumed by the arguments is 8-byte aligned. | 6267 | // that the entire stack space consumed by the arguments is 8-byte aligned. |
| 6275 | if (ty.toType().abiAlignment(mod) == 8) { | 6268 | if (ty.toType().abiAlignment(mod) == .@"8") { |
| 6276 | if (nsaa % 8 != 0) { | 6269 | if (nsaa % 8 != 0) { |
| 6277 | nsaa += 8 - (nsaa % 8); | 6270 | nsaa += 8 - (nsaa % 8); |
| 6278 | } | 6271 | } |
| ... | @@ -6312,10 +6305,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6312,10 +6305,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6312 | 6305 | ||
| 6313 | for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| { | 6306 | for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| { |
| 6314 | if (ty.toType().abiSize(mod) > 0) { | 6307 | if (ty.toType().abiSize(mod) > 0) { |
| 6315 | const param_size = @as(u32, @intCast(ty.toType().abiSize(mod))); | 6308 | const param_size: u32 = @intCast(ty.toType().abiSize(mod)); |
| 6316 | const param_alignment = ty.toType().abiAlignment(mod); | 6309 | const param_alignment = ty.toType().abiAlignment(mod); |
| 6317 | 6310 | ||
| 6318 | stack_offset = std.mem.alignForward(u32, stack_offset, param_alignment); | 6311 | stack_offset = @intCast(param_alignment.forward(stack_offset)); |
| 6319 | result_arg.* = .{ .stack_argument_offset = stack_offset }; | 6312 | result_arg.* = .{ .stack_argument_offset = stack_offset }; |
| 6320 | stack_offset += param_size; | 6313 | stack_offset += param_size; |
| 6321 | } else { | 6314 | } else { |
src/arch/arm/CodeGen.zig+13-12| ... | @@ -23,6 +23,7 @@ const DW = std.dwarf; | ... | @@ -23,6 +23,7 @@ const DW = std.dwarf; |
| 23 | const leb128 = std.leb; | 23 | const leb128 = std.leb; |
| 24 | const log = std.log.scoped(.codegen); | 24 | const log = std.log.scoped(.codegen); |
| 25 | const build_options = @import("build_options"); | 25 | const build_options = @import("build_options"); |
| 26 | const Alignment = InternPool.Alignment; | ||
| 26 | 27 | ||
| 27 | const Result = codegen.Result; | 28 | const Result = codegen.Result; |
| 28 | const CodeGenError = codegen.CodeGenError; | 29 | const CodeGenError = codegen.CodeGenError; |
| ... | @@ -508,7 +509,7 @@ fn gen(self: *Self) !void { | ... | @@ -508,7 +509,7 @@ fn gen(self: *Self) !void { |
| 508 | // The address of where to store the return value is in | 509 | // The address of where to store the return value is in |
| 509 | // r0. As this register might get overwritten along the | 510 | // r0. As this register might get overwritten along the |
| 510 | // way, save the address to the stack. | 511 | // way, save the address to the stack. |
| 511 | const stack_offset = try self.allocMem(4, 4, null); | 512 | const stack_offset = try self.allocMem(4, .@"4", null); |
| 512 | 513 | ||
| 513 | try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = .r0 }); | 514 | try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = .r0 }); |
| 514 | self.ret_mcv = MCValue{ .stack_offset = stack_offset }; | 515 | self.ret_mcv = MCValue{ .stack_offset = stack_offset }; |
| ... | @@ -986,14 +987,14 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { | ... | @@ -986,14 +987,14 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { |
| 986 | fn allocMem( | 987 | fn allocMem( |
| 987 | self: *Self, | 988 | self: *Self, |
| 988 | abi_size: u32, | 989 | abi_size: u32, |
| 989 | abi_align: u32, | 990 | abi_align: Alignment, |
| 990 | maybe_inst: ?Air.Inst.Index, | 991 | maybe_inst: ?Air.Inst.Index, |
| 991 | ) !u32 { | 992 | ) !u32 { |
| 992 | assert(abi_size > 0); | 993 | assert(abi_size > 0); |
| 993 | assert(abi_align > 0); | 994 | assert(abi_align != .none); |
| 994 | 995 | ||
| 995 | // TODO find a free slot instead of always appending | 996 | // TODO find a free slot instead of always appending |
| 996 | const offset = mem.alignForward(u32, self.next_stack_offset, abi_align) + abi_size; | 997 | const offset: u32 = @intCast(abi_align.forward(self.next_stack_offset) + abi_size); |
| 997 | self.next_stack_offset = offset; | 998 | self.next_stack_offset = offset; |
| 998 | self.max_end_stack = @max(self.max_end_stack, self.next_stack_offset); | 999 | self.max_end_stack = @max(self.max_end_stack, self.next_stack_offset); |
| 999 | 1000 | ||
| ... | @@ -1490,7 +1491,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1490,7 +1491,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1490 | const len = try self.resolveInst(bin_op.rhs); | 1491 | const len = try self.resolveInst(bin_op.rhs); |
| 1491 | const len_ty = self.typeOf(bin_op.rhs); | 1492 | const len_ty = self.typeOf(bin_op.rhs); |
| 1492 | 1493 | ||
| 1493 | const stack_offset = try self.allocMem(8, 4, inst); | 1494 | const stack_offset = try self.allocMem(8, .@"4", inst); |
| 1494 | try self.genSetStack(ptr_ty, stack_offset, ptr); | 1495 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 1495 | try self.genSetStack(len_ty, stack_offset - 4, len); | 1496 | try self.genSetStack(len_ty, stack_offset - 4, len); |
| 1496 | break :result MCValue{ .stack_offset = stack_offset }; | 1497 | break :result MCValue{ .stack_offset = stack_offset }; |
| ... | @@ -4251,8 +4252,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -4251,8 +4252,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4251 | const r0_lock: ?RegisterLock = if (info.return_value == .stack_offset) blk: { | 4252 | const r0_lock: ?RegisterLock = if (info.return_value == .stack_offset) blk: { |
| 4252 | log.debug("airCall: return by reference", .{}); | 4253 | log.debug("airCall: return by reference", .{}); |
| 4253 | const ret_ty = fn_ty.fnReturnType(mod); | 4254 | const ret_ty = fn_ty.fnReturnType(mod); |
| 4254 | const ret_abi_size = @as(u32, @intCast(ret_ty.abiSize(mod))); | 4255 | const ret_abi_size: u32 = @intCast(ret_ty.abiSize(mod)); |
| 4255 | const ret_abi_align = @as(u32, @intCast(ret_ty.abiAlignment(mod))); | 4256 | const ret_abi_align = ret_ty.abiAlignment(mod); |
| 4256 | const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst); | 4257 | const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst); |
| 4257 | 4258 | ||
| 4258 | const ptr_ty = try mod.singleMutPtrType(ret_ty); | 4259 | const ptr_ty = try mod.singleMutPtrType(ret_ty); |
| ... | @@ -5896,7 +5897,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5896,7 +5897,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 5896 | const array_ty = ptr_ty.childType(mod); | 5897 | const array_ty = ptr_ty.childType(mod); |
| 5897 | const array_len = @as(u32, @intCast(array_ty.arrayLen(mod))); | 5898 | const array_len = @as(u32, @intCast(array_ty.arrayLen(mod))); |
| 5898 | 5899 | ||
| 5899 | const stack_offset = try self.allocMem(8, 8, inst); | 5900 | const stack_offset = try self.allocMem(8, .@"8", inst); |
| 5900 | try self.genSetStack(ptr_ty, stack_offset, ptr); | 5901 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 5901 | try self.genSetStack(Type.usize, stack_offset - 4, .{ .immediate = array_len }); | 5902 | try self.genSetStack(Type.usize, stack_offset - 4, .{ .immediate = array_len }); |
| 5902 | break :result MCValue{ .stack_offset = stack_offset }; | 5903 | break :result MCValue{ .stack_offset = stack_offset }; |
| ... | @@ -6201,7 +6202,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6201,7 +6202,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6201 | } | 6202 | } |
| 6202 | 6203 | ||
| 6203 | for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| { | 6204 | for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| { |
| 6204 | if (ty.toType().abiAlignment(mod) == 8) | 6205 | if (ty.toType().abiAlignment(mod) == .@"8") |
| 6205 | ncrn = std.mem.alignForward(usize, ncrn, 2); | 6206 | ncrn = std.mem.alignForward(usize, ncrn, 2); |
| 6206 | 6207 | ||
| 6207 | const param_size = @as(u32, @intCast(ty.toType().abiSize(mod))); | 6208 | const param_size = @as(u32, @intCast(ty.toType().abiSize(mod))); |
| ... | @@ -6216,7 +6217,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6216,7 +6217,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6216 | return self.fail("TODO MCValues split between registers and stack", .{}); | 6217 | return self.fail("TODO MCValues split between registers and stack", .{}); |
| 6217 | } else { | 6218 | } else { |
| 6218 | ncrn = 4; | 6219 | ncrn = 4; |
| 6219 | if (ty.toType().abiAlignment(mod) == 8) | 6220 | if (ty.toType().abiAlignment(mod) == .@"8") |
| 6220 | nsaa = std.mem.alignForward(u32, nsaa, 8); | 6221 | nsaa = std.mem.alignForward(u32, nsaa, 8); |
| 6221 | 6222 | ||
| 6222 | result_arg.* = .{ .stack_argument_offset = nsaa }; | 6223 | result_arg.* = .{ .stack_argument_offset = nsaa }; |
| ... | @@ -6252,10 +6253,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6252,10 +6253,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6252 | 6253 | ||
| 6253 | for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| { | 6254 | for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| { |
| 6254 | if (ty.toType().abiSize(mod) > 0) { | 6255 | if (ty.toType().abiSize(mod) > 0) { |
| 6255 | const param_size = @as(u32, @intCast(ty.toType().abiSize(mod))); | 6256 | const param_size: u32 = @intCast(ty.toType().abiSize(mod)); |
| 6256 | const param_alignment = ty.toType().abiAlignment(mod); | 6257 | const param_alignment = ty.toType().abiAlignment(mod); |
| 6257 | 6258 | ||
| 6258 | stack_offset = std.mem.alignForward(u32, stack_offset, param_alignment); | 6259 | stack_offset = @intCast(param_alignment.forward(stack_offset)); |
| 6259 | result_arg.* = .{ .stack_argument_offset = stack_offset }; | 6260 | result_arg.* = .{ .stack_argument_offset = stack_offset }; |
| 6260 | stack_offset += param_size; | 6261 | stack_offset += param_size; |
| 6261 | } else { | 6262 | } else { |
src/arch/arm/abi.zig+2-2| ... | @@ -47,7 +47,7 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class { | ... | @@ -47,7 +47,7 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class { |
| 47 | const field_ty = ty.structFieldType(i, mod); | 47 | const field_ty = ty.structFieldType(i, mod); |
| 48 | const field_alignment = ty.structFieldAlign(i, mod); | 48 | const field_alignment = ty.structFieldAlign(i, mod); |
| 49 | const field_size = field_ty.bitSize(mod); | 49 | const field_size = field_ty.bitSize(mod); |
| 50 | if (field_size > 32 or field_alignment > 32) { | 50 | if (field_size > 32 or field_alignment.compare(.gt, .@"32")) { |
| 51 | return Class.arrSize(bit_size, 64); | 51 | return Class.arrSize(bit_size, 64); |
| 52 | } | 52 | } |
| 53 | } | 53 | } |
| ... | @@ -66,7 +66,7 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class { | ... | @@ -66,7 +66,7 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class { |
| 66 | 66 | ||
| 67 | for (union_obj.field_types.get(ip), 0..) |field_ty, field_index| { | 67 | for (union_obj.field_types.get(ip), 0..) |field_ty, field_index| { |
| 68 | if (field_ty.toType().bitSize(mod) > 32 or | 68 | if (field_ty.toType().bitSize(mod) > 32 or |
| 69 | mod.unionFieldNormalAlignment(union_obj, @intCast(field_index)) > 32) | 69 | mod.unionFieldNormalAlignment(union_obj, @intCast(field_index)).compare(.gt, .@"32")) |
| 70 | { | 70 | { |
| 71 | return Class.arrSize(bit_size, 64); | 71 | return Class.arrSize(bit_size, 64); |
| 72 | } | 72 | } |
src/arch/riscv64/CodeGen.zig+9-10| ... | @@ -23,6 +23,7 @@ const leb128 = std.leb; | ... | @@ -23,6 +23,7 @@ const leb128 = std.leb; |
| 23 | const log = std.log.scoped(.codegen); | 23 | const log = std.log.scoped(.codegen); |
| 24 | const build_options = @import("build_options"); | 24 | const build_options = @import("build_options"); |
| 25 | const codegen = @import("../../codegen.zig"); | 25 | const codegen = @import("../../codegen.zig"); |
| 26 | const Alignment = InternPool.Alignment; | ||
| 26 | 27 | ||
| 27 | const CodeGenError = codegen.CodeGenError; | 28 | const CodeGenError = codegen.CodeGenError; |
| 28 | const Result = codegen.Result; | 29 | const Result = codegen.Result; |
| ... | @@ -53,7 +54,7 @@ ret_mcv: MCValue, | ... | @@ -53,7 +54,7 @@ ret_mcv: MCValue, |
| 53 | fn_type: Type, | 54 | fn_type: Type, |
| 54 | arg_index: usize, | 55 | arg_index: usize, |
| 55 | src_loc: Module.SrcLoc, | 56 | src_loc: Module.SrcLoc, |
| 56 | stack_align: u32, | 57 | stack_align: Alignment, |
| 57 | 58 | ||
| 58 | /// MIR Instructions | 59 | /// MIR Instructions |
| 59 | mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, | 60 | mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, |
| ... | @@ -788,11 +789,10 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { | ... | @@ -788,11 +789,10 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { |
| 788 | try table.ensureUnusedCapacity(self.gpa, additional_count); | 789 | try table.ensureUnusedCapacity(self.gpa, additional_count); |
| 789 | } | 790 | } |
| 790 | 791 | ||
| 791 | fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 { | 792 | fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: Alignment) !u32 { |
| 792 | if (abi_align > self.stack_align) | 793 | self.stack_align = self.stack_align.max(abi_align); |
| 793 | self.stack_align = abi_align; | ||
| 794 | // TODO find a free slot instead of always appending | 794 | // TODO find a free slot instead of always appending |
| 795 | const offset = mem.alignForward(u32, self.next_stack_offset, abi_align); | 795 | const offset: u32 = @intCast(abi_align.forward(self.next_stack_offset)); |
| 796 | self.next_stack_offset = offset + abi_size; | 796 | self.next_stack_offset = offset + abi_size; |
| 797 | if (self.next_stack_offset > self.max_end_stack) | 797 | if (self.next_stack_offset > self.max_end_stack) |
| 798 | self.max_end_stack = self.next_stack_offset; | 798 | self.max_end_stack = self.next_stack_offset; |
| ... | @@ -822,8 +822,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { | ... | @@ -822,8 +822,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 822 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); | 822 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); |
| 823 | }; | 823 | }; |
| 824 | const abi_align = elem_ty.abiAlignment(mod); | 824 | const abi_align = elem_ty.abiAlignment(mod); |
| 825 | if (abi_align > self.stack_align) | 825 | self.stack_align = self.stack_align.max(abi_align); |
| 826 | self.stack_align = abi_align; | ||
| 827 | 826 | ||
| 828 | if (reg_ok) { | 827 | if (reg_ok) { |
| 829 | // Make sure the type can fit in a register before we try to allocate one. | 828 | // Make sure the type can fit in a register before we try to allocate one. |
| ... | @@ -2602,7 +2601,7 @@ const CallMCValues = struct { | ... | @@ -2602,7 +2601,7 @@ const CallMCValues = struct { |
| 2602 | args: []MCValue, | 2601 | args: []MCValue, |
| 2603 | return_value: MCValue, | 2602 | return_value: MCValue, |
| 2604 | stack_byte_count: u32, | 2603 | stack_byte_count: u32, |
| 2605 | stack_align: u32, | 2604 | stack_align: Alignment, |
| 2606 | 2605 | ||
| 2607 | fn deinit(self: *CallMCValues, func: *Self) void { | 2606 | fn deinit(self: *CallMCValues, func: *Self) void { |
| 2608 | func.gpa.free(self.args); | 2607 | func.gpa.free(self.args); |
| ... | @@ -2632,7 +2631,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -2632,7 +2631,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 2632 | assert(result.args.len == 0); | 2631 | assert(result.args.len == 0); |
| 2633 | result.return_value = .{ .unreach = {} }; | 2632 | result.return_value = .{ .unreach = {} }; |
| 2634 | result.stack_byte_count = 0; | 2633 | result.stack_byte_count = 0; |
| 2635 | result.stack_align = 1; | 2634 | result.stack_align = .@"1"; |
| 2636 | return result; | 2635 | return result; |
| 2637 | }, | 2636 | }, |
| 2638 | .Unspecified, .C => { | 2637 | .Unspecified, .C => { |
| ... | @@ -2671,7 +2670,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -2671,7 +2670,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 2671 | } | 2670 | } |
| 2672 | 2671 | ||
| 2673 | result.stack_byte_count = next_stack_offset; | 2672 | result.stack_byte_count = next_stack_offset; |
| 2674 | result.stack_align = 16; | 2673 | result.stack_align = .@"16"; |
| 2675 | }, | 2674 | }, |
| 2676 | else => return self.fail("TODO implement function parameters for {} on riscv64", .{cc}), | 2675 | else => return self.fail("TODO implement function parameters for {} on riscv64", .{cc}), |
| 2677 | } | 2676 | } |
src/arch/sparc64/CodeGen.zig+14-21| ... | @@ -24,6 +24,7 @@ const CodeGenError = codegen.CodeGenError; | ... | @@ -24,6 +24,7 @@ const CodeGenError = codegen.CodeGenError; |
| 24 | const Result = @import("../../codegen.zig").Result; | 24 | const Result = @import("../../codegen.zig").Result; |
| 25 | const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; | 25 | const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; |
| 26 | const Endian = std.builtin.Endian; | 26 | const Endian = std.builtin.Endian; |
| 27 | const Alignment = InternPool.Alignment; | ||
| 27 | 28 | ||
| 28 | const build_options = @import("build_options"); | 29 | const build_options = @import("build_options"); |
| 29 | 30 | ||
| ... | @@ -62,7 +63,7 @@ ret_mcv: MCValue, | ... | @@ -62,7 +63,7 @@ ret_mcv: MCValue, |
| 62 | fn_type: Type, | 63 | fn_type: Type, |
| 63 | arg_index: usize, | 64 | arg_index: usize, |
| 64 | src_loc: Module.SrcLoc, | 65 | src_loc: Module.SrcLoc, |
| 65 | stack_align: u32, | 66 | stack_align: Alignment, |
| 66 | 67 | ||
| 67 | /// MIR Instructions | 68 | /// MIR Instructions |
| 68 | mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, | 69 | mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, |
| ... | @@ -227,7 +228,7 @@ const CallMCValues = struct { | ... | @@ -227,7 +228,7 @@ const CallMCValues = struct { |
| 227 | args: []MCValue, | 228 | args: []MCValue, |
| 228 | return_value: MCValue, | 229 | return_value: MCValue, |
| 229 | stack_byte_count: u32, | 230 | stack_byte_count: u32, |
| 230 | stack_align: u32, | 231 | stack_align: Alignment, |
| 231 | 232 | ||
| 232 | fn deinit(self: *CallMCValues, func: *Self) void { | 233 | fn deinit(self: *CallMCValues, func: *Self) void { |
| 233 | func.gpa.free(self.args); | 234 | func.gpa.free(self.args); |
| ... | @@ -424,7 +425,7 @@ fn gen(self: *Self) !void { | ... | @@ -424,7 +425,7 @@ fn gen(self: *Self) !void { |
| 424 | 425 | ||
| 425 | // Backpatch stack offset | 426 | // Backpatch stack offset |
| 426 | const total_stack_size = self.max_end_stack + abi.stack_reserved_area; | 427 | const total_stack_size = self.max_end_stack + abi.stack_reserved_area; |
| 427 | const stack_size = mem.alignForward(u32, total_stack_size, self.stack_align); | 428 | const stack_size = self.stack_align.forward(total_stack_size); |
| 428 | if (math.cast(i13, stack_size)) |size| { | 429 | if (math.cast(i13, stack_size)) |size| { |
| 429 | self.mir_instructions.set(save_inst, .{ | 430 | self.mir_instructions.set(save_inst, .{ |
| 430 | .tag = .save, | 431 | .tag = .save, |
| ... | @@ -880,11 +881,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -880,11 +881,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 880 | const ptr = try self.resolveInst(ty_op.operand); | 881 | const ptr = try self.resolveInst(ty_op.operand); |
| 881 | const array_ty = ptr_ty.childType(mod); | 882 | const array_ty = ptr_ty.childType(mod); |
| 882 | const array_len = @as(u32, @intCast(array_ty.arrayLen(mod))); | 883 | const array_len = @as(u32, @intCast(array_ty.arrayLen(mod))); |
| 883 | 884 | const ptr_bytes = 8; | |
| 884 | const ptr_bits = self.target.ptrBitWidth(); | 885 | const stack_offset = try self.allocMem(inst, ptr_bytes * 2, .@"8"); |
| 885 | const ptr_bytes = @divExact(ptr_bits, 8); | ||
| 886 | |||
| 887 | const stack_offset = try self.allocMem(inst, ptr_bytes * 2, ptr_bytes * 2); | ||
| 888 | try self.genSetStack(ptr_ty, stack_offset, ptr); | 886 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 889 | try self.genSetStack(Type.usize, stack_offset - ptr_bytes, .{ .immediate = array_len }); | 887 | try self.genSetStack(Type.usize, stack_offset - ptr_bytes, .{ .immediate = array_len }); |
| 890 | break :result MCValue{ .stack_offset = stack_offset }; | 888 | break :result MCValue{ .stack_offset = stack_offset }; |
| ... | @@ -2438,11 +2436,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2438,11 +2436,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 2438 | const ptr_ty = self.typeOf(bin_op.lhs); | 2436 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 2439 | const len = try self.resolveInst(bin_op.rhs); | 2437 | const len = try self.resolveInst(bin_op.rhs); |
| 2440 | const len_ty = self.typeOf(bin_op.rhs); | 2438 | const len_ty = self.typeOf(bin_op.rhs); |
| 2441 | 2439 | const ptr_bytes = 8; | |
| 2442 | const ptr_bits = self.target.ptrBitWidth(); | 2440 | const stack_offset = try self.allocMem(inst, ptr_bytes * 2, .@"8"); |
| 2443 | const ptr_bytes = @divExact(ptr_bits, 8); | ||
| 2444 | |||
| 2445 | const stack_offset = try self.allocMem(inst, ptr_bytes * 2, ptr_bytes * 2); | ||
| 2446 | try self.genSetStack(ptr_ty, stack_offset, ptr); | 2441 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 2447 | try self.genSetStack(len_ty, stack_offset - ptr_bytes, len); | 2442 | try self.genSetStack(len_ty, stack_offset - ptr_bytes, len); |
| 2448 | break :result MCValue{ .stack_offset = stack_offset }; | 2443 | break :result MCValue{ .stack_offset = stack_offset }; |
| ... | @@ -2782,11 +2777,10 @@ fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { | ... | @@ -2782,11 +2777,10 @@ fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { |
| 2782 | return result_index; | 2777 | return result_index; |
| 2783 | } | 2778 | } |
| 2784 | 2779 | ||
| 2785 | fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 { | 2780 | fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: Alignment) !u32 { |
| 2786 | if (abi_align > self.stack_align) | 2781 | self.stack_align = self.stack_align.max(abi_align); |
| 2787 | self.stack_align = abi_align; | ||
| 2788 | // TODO find a free slot instead of always appending | 2782 | // TODO find a free slot instead of always appending |
| 2789 | const offset = mem.alignForward(u32, self.next_stack_offset, abi_align) + abi_size; | 2783 | const offset: u32 = @intCast(abi_align.forward(self.next_stack_offset) + abi_size); |
| 2790 | self.next_stack_offset = offset; | 2784 | self.next_stack_offset = offset; |
| 2791 | if (self.next_stack_offset > self.max_end_stack) | 2785 | if (self.next_stack_offset > self.max_end_stack) |
| 2792 | self.max_end_stack = self.next_stack_offset; | 2786 | self.max_end_stack = self.next_stack_offset; |
| ... | @@ -2825,8 +2819,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { | ... | @@ -2825,8 +2819,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 2825 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); | 2819 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); |
| 2826 | }; | 2820 | }; |
| 2827 | const abi_align = elem_ty.abiAlignment(mod); | 2821 | const abi_align = elem_ty.abiAlignment(mod); |
| 2828 | if (abi_align > self.stack_align) | 2822 | self.stack_align = self.stack_align.max(abi_align); |
| 2829 | self.stack_align = abi_align; | ||
| 2830 | 2823 | ||
| 2831 | if (reg_ok) { | 2824 | if (reg_ok) { |
| 2832 | // Make sure the type can fit in a register before we try to allocate one. | 2825 | // Make sure the type can fit in a register before we try to allocate one. |
| ... | @@ -4479,7 +4472,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) | ... | @@ -4479,7 +4472,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) |
| 4479 | assert(result.args.len == 0); | 4472 | assert(result.args.len == 0); |
| 4480 | result.return_value = .{ .unreach = {} }; | 4473 | result.return_value = .{ .unreach = {} }; |
| 4481 | result.stack_byte_count = 0; | 4474 | result.stack_byte_count = 0; |
| 4482 | result.stack_align = 1; | 4475 | result.stack_align = .@"1"; |
| 4483 | return result; | 4476 | return result; |
| 4484 | }, | 4477 | }, |
| 4485 | .Unspecified, .C => { | 4478 | .Unspecified, .C => { |
| ... | @@ -4521,7 +4514,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) | ... | @@ -4521,7 +4514,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) |
| 4521 | } | 4514 | } |
| 4522 | 4515 | ||
| 4523 | result.stack_byte_count = next_stack_offset; | 4516 | result.stack_byte_count = next_stack_offset; |
| 4524 | result.stack_align = 16; | 4517 | result.stack_align = .@"16"; |
| 4525 | 4518 | ||
| 4526 | if (ret_ty.zigTypeTag(mod) == .NoReturn) { | 4519 | if (ret_ty.zigTypeTag(mod) == .NoReturn) { |
| 4527 | result.return_value = .{ .unreach = {} }; | 4520 | result.return_value = .{ .unreach = {} }; |
src/arch/wasm/CodeGen.zig+88-75| ... | @@ -25,6 +25,7 @@ const target_util = @import("../../target.zig"); | ... | @@ -25,6 +25,7 @@ const target_util = @import("../../target.zig"); |
| 25 | const Mir = @import("Mir.zig"); | 25 | const Mir = @import("Mir.zig"); |
| 26 | const Emit = @import("Emit.zig"); | 26 | const Emit = @import("Emit.zig"); |
| 27 | const abi = @import("abi.zig"); | 27 | const abi = @import("abi.zig"); |
| 28 | const Alignment = InternPool.Alignment; | ||
| 28 | const errUnionPayloadOffset = codegen.errUnionPayloadOffset; | 29 | const errUnionPayloadOffset = codegen.errUnionPayloadOffset; |
| 29 | const errUnionErrorOffset = codegen.errUnionErrorOffset; | 30 | const errUnionErrorOffset = codegen.errUnionErrorOffset; |
| 30 | 31 | ||
| ... | @@ -709,7 +710,7 @@ stack_size: u32 = 0, | ... | @@ -709,7 +710,7 @@ stack_size: u32 = 0, |
| 709 | /// tool-conventions: https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md | 710 | /// tool-conventions: https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md |
| 710 | /// and also what the llvm backend will emit. | 711 | /// and also what the llvm backend will emit. |
| 711 | /// However, local variables or the usage of `@setAlignStack` can overwrite this default. | 712 | /// However, local variables or the usage of `@setAlignStack` can overwrite this default. |
| 712 | stack_alignment: u32 = 16, | 713 | stack_alignment: Alignment = .@"16", |
| 713 | 714 | ||
| 714 | // For each individual Wasm valtype we store a seperate free list which | 715 | // For each individual Wasm valtype we store a seperate free list which |
| 715 | // allows us to re-use locals that are no longer used. e.g. a temporary local. | 716 | // allows us to re-use locals that are no longer used. e.g. a temporary local. |
| ... | @@ -991,6 +992,7 @@ fn addExtraAssumeCapacity(func: *CodeGen, extra: anytype) error{OutOfMemory}!u32 | ... | @@ -991,6 +992,7 @@ fn addExtraAssumeCapacity(func: *CodeGen, extra: anytype) error{OutOfMemory}!u32 |
| 991 | /// Using a given `Type`, returns the corresponding type | 992 | /// Using a given `Type`, returns the corresponding type |
| 992 | fn typeToValtype(ty: Type, mod: *Module) wasm.Valtype { | 993 | fn typeToValtype(ty: Type, mod: *Module) wasm.Valtype { |
| 993 | const target = mod.getTarget(); | 994 | const target = mod.getTarget(); |
| 995 | const ip = &mod.intern_pool; | ||
| 994 | return switch (ty.zigTypeTag(mod)) { | 996 | return switch (ty.zigTypeTag(mod)) { |
| 995 | .Float => switch (ty.floatBits(target)) { | 997 | .Float => switch (ty.floatBits(target)) { |
| 996 | 16 => wasm.Valtype.i32, // stored/loaded as u16 | 998 | 16 => wasm.Valtype.i32, // stored/loaded as u16 |
| ... | @@ -1005,12 +1007,12 @@ fn typeToValtype(ty: Type, mod: *Module) wasm.Valtype { | ... | @@ -1005,12 +1007,12 @@ fn typeToValtype(ty: Type, mod: *Module) wasm.Valtype { |
| 1005 | if (info.bits > 32 and info.bits <= 128) break :blk wasm.Valtype.i64; | 1007 | if (info.bits > 32 and info.bits <= 128) break :blk wasm.Valtype.i64; |
| 1006 | break :blk wasm.Valtype.i32; // represented as pointer to stack | 1008 | break :blk wasm.Valtype.i32; // represented as pointer to stack |
| 1007 | }, | 1009 | }, |
| 1008 | .Struct => switch (ty.containerLayout(mod)) { | 1010 | .Struct => { |
| 1009 | .Packed => { | 1011 | if (mod.typeToPackedStruct(ty)) |packed_struct| { |
| 1010 | const struct_obj = mod.typeToStruct(ty).?; | 1012 | return typeToValtype(packed_struct.backingIntType(ip).toType(), mod); |
| 1011 | return typeToValtype(struct_obj.backing_int_ty, mod); | 1013 | } else { |
| 1012 | }, | 1014 | return wasm.Valtype.i32; |
| 1013 | else => wasm.Valtype.i32, | 1015 | } |
| 1014 | }, | 1016 | }, |
| 1015 | .Vector => switch (determineSimdStoreStrategy(ty, mod)) { | 1017 | .Vector => switch (determineSimdStoreStrategy(ty, mod)) { |
| 1016 | .direct => wasm.Valtype.v128, | 1018 | .direct => wasm.Valtype.v128, |
| ... | @@ -1285,12 +1287,12 @@ fn genFunc(func: *CodeGen) InnerError!void { | ... | @@ -1285,12 +1287,12 @@ fn genFunc(func: *CodeGen) InnerError!void { |
| 1285 | // store stack pointer so we can restore it when we return from the function | 1287 | // store stack pointer so we can restore it when we return from the function |
| 1286 | try prologue.append(.{ .tag = .local_tee, .data = .{ .label = func.initial_stack_value.local.value } }); | 1288 | try prologue.append(.{ .tag = .local_tee, .data = .{ .label = func.initial_stack_value.local.value } }); |
| 1287 | // get the total stack size | 1289 | // get the total stack size |
| 1288 | const aligned_stack = std.mem.alignForward(u32, func.stack_size, func.stack_alignment); | 1290 | const aligned_stack = func.stack_alignment.forward(func.stack_size); |
| 1289 | try prologue.append(.{ .tag = .i32_const, .data = .{ .imm32 = @as(i32, @intCast(aligned_stack)) } }); | 1291 | try prologue.append(.{ .tag = .i32_const, .data = .{ .imm32 = @intCast(aligned_stack) } }); |
| 1290 | // substract it from the current stack pointer | 1292 | // subtract it from the current stack pointer |
| 1291 | try prologue.append(.{ .tag = .i32_sub, .data = .{ .tag = {} } }); | 1293 | try prologue.append(.{ .tag = .i32_sub, .data = .{ .tag = {} } }); |
| 1292 | // Get negative stack aligment | 1294 | // Get negative stack aligment |
| 1293 | try prologue.append(.{ .tag = .i32_const, .data = .{ .imm32 = @as(i32, @intCast(func.stack_alignment)) * -1 } }); | 1295 | try prologue.append(.{ .tag = .i32_const, .data = .{ .imm32 = @as(i32, @intCast(func.stack_alignment.toByteUnitsOptional().?)) * -1 } }); |
| 1294 | // Bitwise-and the value to get the new stack pointer to ensure the pointers are aligned with the abi alignment | 1296 | // Bitwise-and the value to get the new stack pointer to ensure the pointers are aligned with the abi alignment |
| 1295 | try prologue.append(.{ .tag = .i32_and, .data = .{ .tag = {} } }); | 1297 | try prologue.append(.{ .tag = .i32_and, .data = .{ .tag = {} } }); |
| 1296 | // store the current stack pointer as the bottom, which will be used to calculate all stack pointer offsets | 1298 | // store the current stack pointer as the bottom, which will be used to calculate all stack pointer offsets |
| ... | @@ -1438,7 +1440,7 @@ fn lowerArg(func: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value: | ... | @@ -1438,7 +1440,7 @@ fn lowerArg(func: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value: |
| 1438 | }); | 1440 | }); |
| 1439 | try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{ | 1441 | try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{ |
| 1440 | .offset = value.offset(), | 1442 | .offset = value.offset(), |
| 1441 | .alignment = scalar_type.abiAlignment(mod), | 1443 | .alignment = @intCast(scalar_type.abiAlignment(mod).toByteUnitsOptional().?), |
| 1442 | }); | 1444 | }); |
| 1443 | } | 1445 | } |
| 1444 | }, | 1446 | }, |
| ... | @@ -1527,11 +1529,9 @@ fn allocStack(func: *CodeGen, ty: Type) !WValue { | ... | @@ -1527,11 +1529,9 @@ fn allocStack(func: *CodeGen, ty: Type) !WValue { |
| 1527 | }; | 1529 | }; |
| 1528 | const abi_align = ty.abiAlignment(mod); | 1530 | const abi_align = ty.abiAlignment(mod); |
| 1529 | 1531 | ||
| 1530 | if (abi_align > func.stack_alignment) { | 1532 | func.stack_alignment = func.stack_alignment.max(abi_align); |
| 1531 | func.stack_alignment = abi_align; | ||
| 1532 | } | ||
| 1533 | 1533 | ||
| 1534 | const offset = std.mem.alignForward(u32, func.stack_size, abi_align); | 1534 | const offset: u32 = @intCast(abi_align.forward(func.stack_size)); |
| 1535 | defer func.stack_size = offset + abi_size; | 1535 | defer func.stack_size = offset + abi_size; |
| 1536 | 1536 | ||
| 1537 | return WValue{ .stack_offset = .{ .value = offset, .references = 1 } }; | 1537 | return WValue{ .stack_offset = .{ .value = offset, .references = 1 } }; |
| ... | @@ -1560,11 +1560,9 @@ fn allocStackPtr(func: *CodeGen, inst: Air.Inst.Index) !WValue { | ... | @@ -1560,11 +1560,9 @@ fn allocStackPtr(func: *CodeGen, inst: Air.Inst.Index) !WValue { |
| 1560 | pointee_ty.fmt(mod), pointee_ty.abiSize(mod), | 1560 | pointee_ty.fmt(mod), pointee_ty.abiSize(mod), |
| 1561 | }); | 1561 | }); |
| 1562 | }; | 1562 | }; |
| 1563 | if (abi_alignment > func.stack_alignment) { | 1563 | func.stack_alignment = func.stack_alignment.max(abi_alignment); |
| 1564 | func.stack_alignment = abi_alignment; | ||
| 1565 | } | ||
| 1566 | 1564 | ||
| 1567 | const offset = std.mem.alignForward(u32, func.stack_size, abi_alignment); | 1565 | const offset: u32 = @intCast(abi_alignment.forward(func.stack_size)); |
| 1568 | defer func.stack_size = offset + abi_size; | 1566 | defer func.stack_size = offset + abi_size; |
| 1569 | 1567 | ||
| 1570 | return WValue{ .stack_offset = .{ .value = offset, .references = 1 } }; | 1568 | return WValue{ .stack_offset = .{ .value = offset, .references = 1 } }; |
| ... | @@ -1749,10 +1747,8 @@ fn isByRef(ty: Type, mod: *Module) bool { | ... | @@ -1749,10 +1747,8 @@ fn isByRef(ty: Type, mod: *Module) bool { |
| 1749 | return ty.hasRuntimeBitsIgnoreComptime(mod); | 1747 | return ty.hasRuntimeBitsIgnoreComptime(mod); |
| 1750 | }, | 1748 | }, |
| 1751 | .Struct => { | 1749 | .Struct => { |
| 1752 | if (mod.typeToStruct(ty)) |struct_obj| { | 1750 | if (mod.typeToPackedStruct(ty)) |packed_struct| { |
| 1753 | if (struct_obj.layout == .Packed and struct_obj.haveFieldTypes()) { | 1751 | return isByRef(packed_struct.backingIntType(ip).toType(), mod); |
| 1754 | return isByRef(struct_obj.backing_int_ty, mod); | ||
| 1755 | } | ||
| 1756 | } | 1752 | } |
| 1757 | return ty.hasRuntimeBitsIgnoreComptime(mod); | 1753 | return ty.hasRuntimeBitsIgnoreComptime(mod); |
| 1758 | }, | 1754 | }, |
| ... | @@ -2120,7 +2116,7 @@ fn airRet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -2120,7 +2116,7 @@ fn airRet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2120 | }); | 2116 | }); |
| 2121 | try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{ | 2117 | try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{ |
| 2122 | .offset = operand.offset(), | 2118 | .offset = operand.offset(), |
| 2123 | .alignment = scalar_type.abiAlignment(mod), | 2119 | .alignment = @intCast(scalar_type.abiAlignment(mod).toByteUnitsOptional().?), |
| 2124 | }); | 2120 | }); |
| 2125 | }, | 2121 | }, |
| 2126 | else => try func.emitWValue(operand), | 2122 | else => try func.emitWValue(operand), |
| ... | @@ -2385,19 +2381,19 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE | ... | @@ -2385,19 +2381,19 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE |
| 2385 | }, | 2381 | }, |
| 2386 | .Vector => switch (determineSimdStoreStrategy(ty, mod)) { | 2382 | .Vector => switch (determineSimdStoreStrategy(ty, mod)) { |
| 2387 | .unrolled => { | 2383 | .unrolled => { |
| 2388 | const len = @as(u32, @intCast(abi_size)); | 2384 | const len: u32 = @intCast(abi_size); |
| 2389 | return func.memcpy(lhs, rhs, .{ .imm32 = len }); | 2385 | return func.memcpy(lhs, rhs, .{ .imm32 = len }); |
| 2390 | }, | 2386 | }, |
| 2391 | .direct => { | 2387 | .direct => { |
| 2392 | try func.emitWValue(lhs); | 2388 | try func.emitWValue(lhs); |
| 2393 | try func.lowerToStack(rhs); | 2389 | try func.lowerToStack(rhs); |
| 2394 | // TODO: Add helper functions for simd opcodes | 2390 | // TODO: Add helper functions for simd opcodes |
| 2395 | const extra_index = @as(u32, @intCast(func.mir_extra.items.len)); | 2391 | const extra_index: u32 = @intCast(func.mir_extra.items.len); |
| 2396 | // stores as := opcode, offset, alignment (opcode::memarg) | 2392 | // stores as := opcode, offset, alignment (opcode::memarg) |
| 2397 | try func.mir_extra.appendSlice(func.gpa, &[_]u32{ | 2393 | try func.mir_extra.appendSlice(func.gpa, &[_]u32{ |
| 2398 | std.wasm.simdOpcode(.v128_store), | 2394 | std.wasm.simdOpcode(.v128_store), |
| 2399 | offset + lhs.offset(), | 2395 | offset + lhs.offset(), |
| 2400 | ty.abiAlignment(mod), | 2396 | @intCast(ty.abiAlignment(mod).toByteUnits(0)), |
| 2401 | }); | 2397 | }); |
| 2402 | return func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); | 2398 | return func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); |
| 2403 | }, | 2399 | }, |
| ... | @@ -2451,7 +2447,10 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE | ... | @@ -2451,7 +2447,10 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE |
| 2451 | // store rhs value at stack pointer's location in memory | 2447 | // store rhs value at stack pointer's location in memory |
| 2452 | try func.addMemArg( | 2448 | try func.addMemArg( |
| 2453 | Mir.Inst.Tag.fromOpcode(opcode), | 2449 | Mir.Inst.Tag.fromOpcode(opcode), |
| 2454 | .{ .offset = offset + lhs.offset(), .alignment = ty.abiAlignment(mod) }, | 2450 | .{ |
| 2451 | .offset = offset + lhs.offset(), | ||
| 2452 | .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?), | ||
| 2453 | }, | ||
| 2455 | ); | 2454 | ); |
| 2456 | } | 2455 | } |
| 2457 | 2456 | ||
| ... | @@ -2510,7 +2509,7 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu | ... | @@ -2510,7 +2509,7 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu |
| 2510 | try func.mir_extra.appendSlice(func.gpa, &[_]u32{ | 2509 | try func.mir_extra.appendSlice(func.gpa, &[_]u32{ |
| 2511 | std.wasm.simdOpcode(.v128_load), | 2510 | std.wasm.simdOpcode(.v128_load), |
| 2512 | offset + operand.offset(), | 2511 | offset + operand.offset(), |
| 2513 | ty.abiAlignment(mod), | 2512 | @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?), |
| 2514 | }); | 2513 | }); |
| 2515 | try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); | 2514 | try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); |
| 2516 | return WValue{ .stack = {} }; | 2515 | return WValue{ .stack = {} }; |
| ... | @@ -2526,7 +2525,10 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu | ... | @@ -2526,7 +2525,10 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu |
| 2526 | 2525 | ||
| 2527 | try func.addMemArg( | 2526 | try func.addMemArg( |
| 2528 | Mir.Inst.Tag.fromOpcode(opcode), | 2527 | Mir.Inst.Tag.fromOpcode(opcode), |
| 2529 | .{ .offset = offset + operand.offset(), .alignment = ty.abiAlignment(mod) }, | 2528 | .{ |
| 2529 | .offset = offset + operand.offset(), | ||
| 2530 | .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?), | ||
| 2531 | }, | ||
| 2530 | ); | 2532 | ); |
| 2531 | 2533 | ||
| 2532 | return WValue{ .stack = {} }; | 2534 | return WValue{ .stack = {} }; |
| ... | @@ -3023,10 +3025,10 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue | ... | @@ -3023,10 +3025,10 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue |
| 3023 | else => blk: { | 3025 | else => blk: { |
| 3024 | const layout: Module.UnionLayout = parent_ty.unionGetLayout(mod); | 3026 | const layout: Module.UnionLayout = parent_ty.unionGetLayout(mod); |
| 3025 | if (layout.payload_size == 0) break :blk 0; | 3027 | if (layout.payload_size == 0) break :blk 0; |
| 3026 | if (layout.payload_align > layout.tag_align) break :blk 0; | 3028 | if (layout.payload_align.compare(.gt, layout.tag_align)) break :blk 0; |
| 3027 | 3029 | ||
| 3028 | // tag is stored first so calculate offset from where payload starts | 3030 | // tag is stored first so calculate offset from where payload starts |
| 3029 | break :blk @as(u32, @intCast(std.mem.alignForward(u64, layout.tag_size, layout.tag_align))); | 3031 | break :blk layout.tag_align.forward(layout.tag_size); |
| 3030 | }, | 3032 | }, |
| 3031 | }, | 3033 | }, |
| 3032 | .Pointer => switch (parent_ty.ptrSize(mod)) { | 3034 | .Pointer => switch (parent_ty.ptrSize(mod)) { |
| ... | @@ -3103,8 +3105,12 @@ fn toTwosComplement(value: anytype, bits: u7) std.meta.Int(.unsigned, @typeInfo( | ... | @@ -3103,8 +3105,12 @@ fn toTwosComplement(value: anytype, bits: u7) std.meta.Int(.unsigned, @typeInfo( |
| 3103 | return @as(WantedT, @intCast(result)); | 3105 | return @as(WantedT, @intCast(result)); |
| 3104 | } | 3106 | } |
| 3105 | 3107 | ||
| 3108 | /// This function is intended to assert that `isByRef` returns `false` for `ty`. | ||
| 3109 | /// However such an assertion fails on the behavior tests currently. | ||
| 3106 | fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { | 3110 | fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { |
| 3107 | const mod = func.bin_file.base.options.module.?; | 3111 | const mod = func.bin_file.base.options.module.?; |
| 3112 | // TODO: enable this assertion | ||
| 3113 | //assert(!isByRef(ty, mod)); | ||
| 3108 | const ip = &mod.intern_pool; | 3114 | const ip = &mod.intern_pool; |
| 3109 | var val = arg_val; | 3115 | var val = arg_val; |
| 3110 | switch (ip.indexToKey(val.ip_index)) { | 3116 | switch (ip.indexToKey(val.ip_index)) { |
| ... | @@ -3235,16 +3241,18 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { | ... | @@ -3235,16 +3241,18 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { |
| 3235 | val.writeToMemory(ty, mod, &buf) catch unreachable; | 3241 | val.writeToMemory(ty, mod, &buf) catch unreachable; |
| 3236 | return func.storeSimdImmd(buf); | 3242 | return func.storeSimdImmd(buf); |
| 3237 | }, | 3243 | }, |
| 3238 | .struct_type, .anon_struct_type => { | 3244 | .struct_type => |struct_type| { |
| 3239 | const struct_obj = mod.typeToStruct(ty).?; | 3245 | // non-packed structs are not handled in this function because they |
| 3240 | assert(struct_obj.layout == .Packed); | 3246 | // are by-ref types. |
| 3247 | assert(struct_type.layout == .Packed); | ||
| 3241 | var buf: [8]u8 = .{0} ** 8; // zero the buffer so we do not read 0xaa as integer | 3248 | var buf: [8]u8 = .{0} ** 8; // zero the buffer so we do not read 0xaa as integer |
| 3242 | val.writeToPackedMemory(ty, func.bin_file.base.options.module.?, &buf, 0) catch unreachable; | 3249 | val.writeToPackedMemory(ty, mod, &buf, 0) catch unreachable; |
| 3250 | const backing_int_ty = struct_type.backingIntType(ip).toType(); | ||
| 3243 | const int_val = try mod.intValue( | 3251 | const int_val = try mod.intValue( |
| 3244 | struct_obj.backing_int_ty, | 3252 | backing_int_ty, |
| 3245 | std.mem.readIntLittle(u64, &buf), | 3253 | mem.readIntLittle(u64, &buf), |
| 3246 | ); | 3254 | ); |
| 3247 | return func.lowerConstant(int_val, struct_obj.backing_int_ty); | 3255 | return func.lowerConstant(int_val, backing_int_ty); |
| 3248 | }, | 3256 | }, |
| 3249 | else => unreachable, | 3257 | else => unreachable, |
| 3250 | }, | 3258 | }, |
| ... | @@ -3269,6 +3277,7 @@ fn storeSimdImmd(func: *CodeGen, value: [16]u8) !WValue { | ... | @@ -3269,6 +3277,7 @@ fn storeSimdImmd(func: *CodeGen, value: [16]u8) !WValue { |
| 3269 | 3277 | ||
| 3270 | fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue { | 3278 | fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue { |
| 3271 | const mod = func.bin_file.base.options.module.?; | 3279 | const mod = func.bin_file.base.options.module.?; |
| 3280 | const ip = &mod.intern_pool; | ||
| 3272 | switch (ty.zigTypeTag(mod)) { | 3281 | switch (ty.zigTypeTag(mod)) { |
| 3273 | .Bool, .ErrorSet => return WValue{ .imm32 = 0xaaaaaaaa }, | 3282 | .Bool, .ErrorSet => return WValue{ .imm32 = 0xaaaaaaaa }, |
| 3274 | .Int, .Enum => switch (ty.intInfo(mod).bits) { | 3283 | .Int, .Enum => switch (ty.intInfo(mod).bits) { |
| ... | @@ -3298,9 +3307,8 @@ fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue { | ... | @@ -3298,9 +3307,8 @@ fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue { |
| 3298 | return WValue{ .imm32 = 0xaaaaaaaa }; | 3307 | return WValue{ .imm32 = 0xaaaaaaaa }; |
| 3299 | }, | 3308 | }, |
| 3300 | .Struct => { | 3309 | .Struct => { |
| 3301 | const struct_obj = mod.typeToStruct(ty).?; | 3310 | const packed_struct = mod.typeToPackedStruct(ty).?; |
| 3302 | assert(struct_obj.layout == .Packed); | 3311 | return func.emitUndefined(packed_struct.backingIntType(ip).toType()); |
| 3303 | return func.emitUndefined(struct_obj.backing_int_ty); | ||
| 3304 | }, | 3312 | }, |
| 3305 | else => return func.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty.zigTypeTag(mod)}), | 3313 | else => return func.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty.zigTypeTag(mod)}), |
| 3306 | } | 3314 | } |
| ... | @@ -3340,7 +3348,7 @@ fn intStorageAsI32(storage: InternPool.Key.Int.Storage, mod: *Module) i32 { | ... | @@ -3340,7 +3348,7 @@ fn intStorageAsI32(storage: InternPool.Key.Int.Storage, mod: *Module) i32 { |
| 3340 | .i64 => |x| @as(i32, @intCast(x)), | 3348 | .i64 => |x| @as(i32, @intCast(x)), |
| 3341 | .u64 => |x| @as(i32, @bitCast(@as(u32, @intCast(x)))), | 3349 | .u64 => |x| @as(i32, @bitCast(@as(u32, @intCast(x)))), |
| 3342 | .big_int => unreachable, | 3350 | .big_int => unreachable, |
| 3343 | .lazy_align => |ty| @as(i32, @bitCast(ty.toType().abiAlignment(mod))), | 3351 | .lazy_align => |ty| @as(i32, @bitCast(@as(u32, @intCast(ty.toType().abiAlignment(mod).toByteUnits(0))))), |
| 3344 | .lazy_size => |ty| @as(i32, @bitCast(@as(u32, @intCast(ty.toType().abiSize(mod))))), | 3352 | .lazy_size => |ty| @as(i32, @bitCast(@as(u32, @intCast(ty.toType().abiSize(mod))))), |
| 3345 | }; | 3353 | }; |
| 3346 | } | 3354 | } |
| ... | @@ -3757,6 +3765,7 @@ fn structFieldPtr( | ... | @@ -3757,6 +3765,7 @@ fn structFieldPtr( |
| 3757 | 3765 | ||
| 3758 | fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 3766 | fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3759 | const mod = func.bin_file.base.options.module.?; | 3767 | const mod = func.bin_file.base.options.module.?; |
| 3768 | const ip = &mod.intern_pool; | ||
| 3760 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; | 3769 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 3761 | const struct_field = func.air.extraData(Air.StructField, ty_pl.payload).data; | 3770 | const struct_field = func.air.extraData(Air.StructField, ty_pl.payload).data; |
| 3762 | 3771 | ||
| ... | @@ -3769,9 +3778,9 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3769,9 +3778,9 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3769 | const result = switch (struct_ty.containerLayout(mod)) { | 3778 | const result = switch (struct_ty.containerLayout(mod)) { |
| 3770 | .Packed => switch (struct_ty.zigTypeTag(mod)) { | 3779 | .Packed => switch (struct_ty.zigTypeTag(mod)) { |
| 3771 | .Struct => result: { | 3780 | .Struct => result: { |
| 3772 | const struct_obj = mod.typeToStruct(struct_ty).?; | 3781 | const packed_struct = mod.typeToPackedStruct(struct_ty).?; |
| 3773 | const offset = struct_obj.packedFieldBitOffset(mod, field_index); | 3782 | const offset = mod.structPackedFieldBitOffset(packed_struct, field_index); |
| 3774 | const backing_ty = struct_obj.backing_int_ty; | 3783 | const backing_ty = packed_struct.backingIntType(ip).toType(); |
| 3775 | const wasm_bits = toWasmBits(backing_ty.intInfo(mod).bits) orelse { | 3784 | const wasm_bits = toWasmBits(backing_ty.intInfo(mod).bits) orelse { |
| 3776 | return func.fail("TODO: airStructFieldVal for packed structs larger than 128 bits", .{}); | 3785 | return func.fail("TODO: airStructFieldVal for packed structs larger than 128 bits", .{}); |
| 3777 | }; | 3786 | }; |
| ... | @@ -3793,7 +3802,7 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3793,7 +3802,7 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3793 | const truncated = try func.trunc(shifted_value, int_type, backing_ty); | 3802 | const truncated = try func.trunc(shifted_value, int_type, backing_ty); |
| 3794 | const bitcasted = try func.bitcast(field_ty, int_type, truncated); | 3803 | const bitcasted = try func.bitcast(field_ty, int_type, truncated); |
| 3795 | break :result try bitcasted.toLocal(func, field_ty); | 3804 | break :result try bitcasted.toLocal(func, field_ty); |
| 3796 | } else if (field_ty.isPtrAtRuntime(mod) and struct_obj.fields.count() == 1) { | 3805 | } else if (field_ty.isPtrAtRuntime(mod) and packed_struct.field_types.len == 1) { |
| 3797 | // In this case we do not have to perform any transformations, | 3806 | // In this case we do not have to perform any transformations, |
| 3798 | // we can simply reuse the operand. | 3807 | // we can simply reuse the operand. |
| 3799 | break :result func.reuseOperand(struct_field.struct_operand, operand); | 3808 | break :result func.reuseOperand(struct_field.struct_operand, operand); |
| ... | @@ -4053,7 +4062,7 @@ fn airIsErr(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerErro | ... | @@ -4053,7 +4062,7 @@ fn airIsErr(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerErro |
| 4053 | if (pl_ty.hasRuntimeBitsIgnoreComptime(mod)) { | 4062 | if (pl_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 4054 | try func.addMemArg(.i32_load16_u, .{ | 4063 | try func.addMemArg(.i32_load16_u, .{ |
| 4055 | .offset = operand.offset() + @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod))), | 4064 | .offset = operand.offset() + @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod))), |
| 4056 | .alignment = Type.anyerror.abiAlignment(mod), | 4065 | .alignment = @intCast(Type.anyerror.abiAlignment(mod).toByteUnitsOptional().?), |
| 4057 | }); | 4066 | }); |
| 4058 | } | 4067 | } |
| 4059 | 4068 | ||
| ... | @@ -4141,7 +4150,10 @@ fn airWrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void | ... | @@ -4141,7 +4150,10 @@ fn airWrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void |
| 4141 | try func.emitWValue(err_union); | 4150 | try func.emitWValue(err_union); |
| 4142 | try func.addImm32(0); | 4151 | try func.addImm32(0); |
| 4143 | const err_val_offset = @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod))); | 4152 | const err_val_offset = @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod))); |
| 4144 | try func.addMemArg(.i32_store16, .{ .offset = err_union.offset() + err_val_offset, .alignment = 2 }); | 4153 | try func.addMemArg(.i32_store16, .{ |
| 4154 | .offset = err_union.offset() + err_val_offset, | ||
| 4155 | .alignment = 2, | ||
| 4156 | }); | ||
| 4145 | break :result err_union; | 4157 | break :result err_union; |
| 4146 | }; | 4158 | }; |
| 4147 | func.finishAir(inst, result, &.{ty_op.operand}); | 4159 | func.finishAir(inst, result, &.{ty_op.operand}); |
| ... | @@ -4977,7 +4989,7 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4977,7 +4989,7 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4977 | try func.mir_extra.appendSlice(func.gpa, &[_]u32{ | 4989 | try func.mir_extra.appendSlice(func.gpa, &[_]u32{ |
| 4978 | opcode, | 4990 | opcode, |
| 4979 | operand.offset(), | 4991 | operand.offset(), |
| 4980 | elem_ty.abiAlignment(mod), | 4992 | @intCast(elem_ty.abiAlignment(mod).toByteUnitsOptional().?), |
| 4981 | }); | 4993 | }); |
| 4982 | try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); | 4994 | try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); |
| 4983 | try func.addLabel(.local_set, result.local.value); | 4995 | try func.addLabel(.local_set, result.local.value); |
| ... | @@ -5065,7 +5077,7 @@ fn airShuffle(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5065,7 +5077,7 @@ fn airShuffle(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5065 | std.wasm.simdOpcode(.i8x16_shuffle), | 5077 | std.wasm.simdOpcode(.i8x16_shuffle), |
| 5066 | } ++ [1]u32{undefined} ** 4; | 5078 | } ++ [1]u32{undefined} ** 4; |
| 5067 | 5079 | ||
| 5068 | var lanes = std.mem.asBytes(operands[1..]); | 5080 | var lanes = mem.asBytes(operands[1..]); |
| 5069 | for (0..@as(usize, @intCast(mask_len))) |index| { | 5081 | for (0..@as(usize, @intCast(mask_len))) |index| { |
| 5070 | const mask_elem = (try mask.elemValue(mod, index)).toSignedInt(mod); | 5082 | const mask_elem = (try mask.elemValue(mod, index)).toSignedInt(mod); |
| 5071 | const base_index = if (mask_elem >= 0) | 5083 | const base_index = if (mask_elem >= 0) |
| ... | @@ -5099,6 +5111,7 @@ fn airReduce(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5099,6 +5111,7 @@ fn airReduce(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5099 | 5111 | ||
| 5100 | fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 5112 | fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5101 | const mod = func.bin_file.base.options.module.?; | 5113 | const mod = func.bin_file.base.options.module.?; |
| 5114 | const ip = &mod.intern_pool; | ||
| 5102 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; | 5115 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 5103 | const result_ty = func.typeOfIndex(inst); | 5116 | const result_ty = func.typeOfIndex(inst); |
| 5104 | const len = @as(usize, @intCast(result_ty.arrayLen(mod))); | 5117 | const len = @as(usize, @intCast(result_ty.arrayLen(mod))); |
| ... | @@ -5150,13 +5163,13 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5150,13 +5163,13 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5150 | if (isByRef(result_ty, mod)) { | 5163 | if (isByRef(result_ty, mod)) { |
| 5151 | return func.fail("TODO: airAggregateInit for packed structs larger than 64 bits", .{}); | 5164 | return func.fail("TODO: airAggregateInit for packed structs larger than 64 bits", .{}); |
| 5152 | } | 5165 | } |
| 5153 | const struct_obj = mod.typeToStruct(result_ty).?; | 5166 | const packed_struct = mod.typeToPackedStruct(result_ty).?; |
| 5154 | const fields = struct_obj.fields.values(); | 5167 | const field_types = packed_struct.field_types; |
| 5155 | const backing_type = struct_obj.backing_int_ty; | 5168 | const backing_type = packed_struct.backingIntType(ip).toType(); |
| 5156 | 5169 | ||
| 5157 | // ensure the result is zero'd | 5170 | // ensure the result is zero'd |
| 5158 | const result = try func.allocLocal(backing_type); | 5171 | const result = try func.allocLocal(backing_type); |
| 5159 | if (struct_obj.backing_int_ty.bitSize(mod) <= 32) | 5172 | if (backing_type.bitSize(mod) <= 32) |
| 5160 | try func.addImm32(0) | 5173 | try func.addImm32(0) |
| 5161 | else | 5174 | else |
| 5162 | try func.addImm64(0); | 5175 | try func.addImm64(0); |
| ... | @@ -5164,22 +5177,22 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5164,22 +5177,22 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5164 | 5177 | ||
| 5165 | var current_bit: u16 = 0; | 5178 | var current_bit: u16 = 0; |
| 5166 | for (elements, 0..) |elem, elem_index| { | 5179 | for (elements, 0..) |elem, elem_index| { |
| 5167 | const field = fields[elem_index]; | 5180 | const field_ty = field_types.get(ip)[elem_index].toType(); |
| 5168 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | 5181 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 5169 | 5182 | ||
| 5170 | const shift_val = if (struct_obj.backing_int_ty.bitSize(mod) <= 32) | 5183 | const shift_val = if (backing_type.bitSize(mod) <= 32) |
| 5171 | WValue{ .imm32 = current_bit } | 5184 | WValue{ .imm32 = current_bit } |
| 5172 | else | 5185 | else |
| 5173 | WValue{ .imm64 = current_bit }; | 5186 | WValue{ .imm64 = current_bit }; |
| 5174 | 5187 | ||
| 5175 | const value = try func.resolveInst(elem); | 5188 | const value = try func.resolveInst(elem); |
| 5176 | const value_bit_size = @as(u16, @intCast(field.ty.bitSize(mod))); | 5189 | const value_bit_size: u16 = @intCast(field_ty.bitSize(mod)); |
| 5177 | const int_ty = try mod.intType(.unsigned, value_bit_size); | 5190 | const int_ty = try mod.intType(.unsigned, value_bit_size); |
| 5178 | 5191 | ||
| 5179 | // load our current result on stack so we can perform all transformations | 5192 | // load our current result on stack so we can perform all transformations |
| 5180 | // using only stack values. Saving the cost of loads and stores. | 5193 | // using only stack values. Saving the cost of loads and stores. |
| 5181 | try func.emitWValue(result); | 5194 | try func.emitWValue(result); |
| 5182 | const bitcasted = try func.bitcast(int_ty, field.ty, value); | 5195 | const bitcasted = try func.bitcast(int_ty, field_ty, value); |
| 5183 | const extended_val = try func.intcast(bitcasted, int_ty, backing_type); | 5196 | const extended_val = try func.intcast(bitcasted, int_ty, backing_type); |
| 5184 | // no need to shift any values when the current offset is 0 | 5197 | // no need to shift any values when the current offset is 0 |
| 5185 | const shifted = if (current_bit != 0) shifted: { | 5198 | const shifted = if (current_bit != 0) shifted: { |
| ... | @@ -5199,7 +5212,7 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5199,7 +5212,7 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5199 | if ((try result_ty.structFieldValueComptime(mod, elem_index)) != null) continue; | 5212 | if ((try result_ty.structFieldValueComptime(mod, elem_index)) != null) continue; |
| 5200 | 5213 | ||
| 5201 | const elem_ty = result_ty.structFieldType(elem_index, mod); | 5214 | const elem_ty = result_ty.structFieldType(elem_index, mod); |
| 5202 | const elem_size = @as(u32, @intCast(elem_ty.abiSize(mod))); | 5215 | const elem_size: u32 = @intCast(elem_ty.abiSize(mod)); |
| 5203 | const value = try func.resolveInst(elem); | 5216 | const value = try func.resolveInst(elem); |
| 5204 | try func.store(offset, value, elem_ty, 0); | 5217 | try func.store(offset, value, elem_ty, 0); |
| 5205 | 5218 | ||
| ... | @@ -5256,7 +5269,7 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5256,7 +5269,7 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5256 | if (isByRef(union_ty, mod)) { | 5269 | if (isByRef(union_ty, mod)) { |
| 5257 | const result_ptr = try func.allocStack(union_ty); | 5270 | const result_ptr = try func.allocStack(union_ty); |
| 5258 | const payload = try func.resolveInst(extra.init); | 5271 | const payload = try func.resolveInst(extra.init); |
| 5259 | if (layout.tag_align >= layout.payload_align) { | 5272 | if (layout.tag_align.compare(.gte, layout.payload_align)) { |
| 5260 | if (isByRef(field_ty, mod)) { | 5273 | if (isByRef(field_ty, mod)) { |
| 5261 | const payload_ptr = try func.buildPointerOffset(result_ptr, layout.tag_size, .new); | 5274 | const payload_ptr = try func.buildPointerOffset(result_ptr, layout.tag_size, .new); |
| 5262 | try func.store(payload_ptr, payload, field_ty, 0); | 5275 | try func.store(payload_ptr, payload, field_ty, 0); |
| ... | @@ -5420,9 +5433,9 @@ fn airSetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5420,9 +5433,9 @@ fn airSetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5420 | 5433 | ||
| 5421 | // when the tag alignment is smaller than the payload, the field will be stored | 5434 | // when the tag alignment is smaller than the payload, the field will be stored |
| 5422 | // after the payload. | 5435 | // after the payload. |
| 5423 | const offset = if (layout.tag_align < layout.payload_align) blk: { | 5436 | const offset: u32 = if (layout.tag_align.compare(.lt, layout.payload_align)) blk: { |
| 5424 | break :blk @as(u32, @intCast(layout.payload_size)); | 5437 | break :blk @intCast(layout.payload_size); |
| 5425 | } else @as(u32, 0); | 5438 | } else 0; |
| 5426 | try func.store(union_ptr, new_tag, tag_ty, offset); | 5439 | try func.store(union_ptr, new_tag, tag_ty, offset); |
| 5427 | func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs }); | 5440 | func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs }); |
| 5428 | } | 5441 | } |
| ... | @@ -5439,9 +5452,9 @@ fn airGetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5439,9 +5452,9 @@ fn airGetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5439 | const operand = try func.resolveInst(ty_op.operand); | 5452 | const operand = try func.resolveInst(ty_op.operand); |
| 5440 | // when the tag alignment is smaller than the payload, the field will be stored | 5453 | // when the tag alignment is smaller than the payload, the field will be stored |
| 5441 | // after the payload. | 5454 | // after the payload. |
| 5442 | const offset = if (layout.tag_align < layout.payload_align) blk: { | 5455 | const offset: u32 = if (layout.tag_align.compare(.lt, layout.payload_align)) blk: { |
| 5443 | break :blk @as(u32, @intCast(layout.payload_size)); | 5456 | break :blk @intCast(layout.payload_size); |
| 5444 | } else @as(u32, 0); | 5457 | } else 0; |
| 5445 | const tag = try func.load(operand, tag_ty, offset); | 5458 | const tag = try func.load(operand, tag_ty, offset); |
| 5446 | const result = try tag.toLocal(func, tag_ty); | 5459 | const result = try tag.toLocal(func, tag_ty); |
| 5447 | func.finishAir(inst, result, &.{ty_op.operand}); | 5460 | func.finishAir(inst, result, &.{ty_op.operand}); |
| ... | @@ -6366,7 +6379,7 @@ fn lowerTry( | ... | @@ -6366,7 +6379,7 @@ fn lowerTry( |
| 6366 | const err_offset = @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod))); | 6379 | const err_offset = @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod))); |
| 6367 | try func.addMemArg(.i32_load16_u, .{ | 6380 | try func.addMemArg(.i32_load16_u, .{ |
| 6368 | .offset = err_union.offset() + err_offset, | 6381 | .offset = err_union.offset() + err_offset, |
| 6369 | .alignment = Type.anyerror.abiAlignment(mod), | 6382 | .alignment = @intCast(Type.anyerror.abiAlignment(mod).toByteUnitsOptional().?), |
| 6370 | }); | 6383 | }); |
| 6371 | } | 6384 | } |
| 6372 | try func.addTag(.i32_eqz); | 6385 | try func.addTag(.i32_eqz); |
| ... | @@ -7287,7 +7300,7 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7287,7 +7300,7 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7287 | else => |size| return func.fail("TODO: implement `@cmpxchg` for types with abi size '{d}'", .{size}), | 7300 | else => |size| return func.fail("TODO: implement `@cmpxchg` for types with abi size '{d}'", .{size}), |
| 7288 | }, .{ | 7301 | }, .{ |
| 7289 | .offset = ptr_operand.offset(), | 7302 | .offset = ptr_operand.offset(), |
| 7290 | .alignment = ty.abiAlignment(mod), | 7303 | .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?), |
| 7291 | }); | 7304 | }); |
| 7292 | try func.addLabel(.local_tee, val_local.local.value); | 7305 | try func.addLabel(.local_tee, val_local.local.value); |
| 7293 | _ = try func.cmp(.stack, expected_val, ty, .eq); | 7306 | _ = try func.cmp(.stack, expected_val, ty, .eq); |
| ... | @@ -7349,7 +7362,7 @@ fn airAtomicLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7349,7 +7362,7 @@ fn airAtomicLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7349 | try func.emitWValue(ptr); | 7362 | try func.emitWValue(ptr); |
| 7350 | try func.addAtomicMemArg(tag, .{ | 7363 | try func.addAtomicMemArg(tag, .{ |
| 7351 | .offset = ptr.offset(), | 7364 | .offset = ptr.offset(), |
| 7352 | .alignment = ty.abiAlignment(mod), | 7365 | .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?), |
| 7353 | }); | 7366 | }); |
| 7354 | } else { | 7367 | } else { |
| 7355 | _ = try func.load(ptr, ty, 0); | 7368 | _ = try func.load(ptr, ty, 0); |
| ... | @@ -7410,7 +7423,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7410,7 +7423,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7410 | }, | 7423 | }, |
| 7411 | .{ | 7424 | .{ |
| 7412 | .offset = ptr.offset(), | 7425 | .offset = ptr.offset(), |
| 7413 | .alignment = ty.abiAlignment(mod), | 7426 | .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?), |
| 7414 | }, | 7427 | }, |
| 7415 | ); | 7428 | ); |
| 7416 | const select_res = try func.allocLocal(ty); | 7429 | const select_res = try func.allocLocal(ty); |
| ... | @@ -7470,7 +7483,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7470,7 +7483,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7470 | }; | 7483 | }; |
| 7471 | try func.addAtomicMemArg(tag, .{ | 7484 | try func.addAtomicMemArg(tag, .{ |
| 7472 | .offset = ptr.offset(), | 7485 | .offset = ptr.offset(), |
| 7473 | .alignment = ty.abiAlignment(mod), | 7486 | .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?), |
| 7474 | }); | 7487 | }); |
| 7475 | const result = try WValue.toLocal(.stack, func, ty); | 7488 | const result = try WValue.toLocal(.stack, func, ty); |
| 7476 | return func.finishAir(inst, result, &.{ pl_op.operand, extra.operand }); | 7489 | return func.finishAir(inst, result, &.{ pl_op.operand, extra.operand }); |
| ... | @@ -7566,7 +7579,7 @@ fn airAtomicStore(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7566,7 +7579,7 @@ fn airAtomicStore(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7566 | try func.lowerToStack(operand); | 7579 | try func.lowerToStack(operand); |
| 7567 | try func.addAtomicMemArg(tag, .{ | 7580 | try func.addAtomicMemArg(tag, .{ |
| 7568 | .offset = ptr.offset(), | 7581 | .offset = ptr.offset(), |
| 7569 | .alignment = ty.abiAlignment(mod), | 7582 | .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?), |
| 7570 | }); | 7583 | }); |
| 7571 | } else { | 7584 | } else { |
| 7572 | try func.store(ptr, operand, ty, 0); | 7585 | try func.store(ptr, operand, ty, 0); |
src/arch/wasm/abi.zig+15-18| ... | @@ -32,16 +32,17 @@ pub fn classifyType(ty: Type, mod: *Module) [2]Class { | ... | @@ -32,16 +32,17 @@ pub fn classifyType(ty: Type, mod: *Module) [2]Class { |
| 32 | if (ty.bitSize(mod) <= 64) return direct; | 32 | if (ty.bitSize(mod) <= 64) return direct; |
| 33 | return .{ .direct, .direct }; | 33 | return .{ .direct, .direct }; |
| 34 | } | 34 | } |
| 35 | // When the struct type is non-scalar | 35 | if (ty.structFieldCount(mod) > 1) { |
| 36 | if (ty.structFieldCount(mod) > 1) return memory; | 36 | // The struct type is non-scalar. |
| 37 | // When the struct's alignment is non-natural | 37 | return memory; |
| 38 | const field = ty.structFields(mod).values()[0]; | 38 | } |
| 39 | if (field.abi_align != .none) { | 39 | const field_ty = ty.structFieldType(0, mod); |
| 40 | if (field.abi_align.toByteUnitsOptional().? > field.ty.abiAlignment(mod)) { | 40 | const resolved_align = ty.structFieldAlign(0, mod); |
| 41 | return memory; | 41 | if (resolved_align.compare(.gt, field_ty.abiAlignment(mod))) { |
| 42 | } | 42 | // The struct's alignment is greater than natural alignment. |
| 43 | return memory; | ||
| 43 | } | 44 | } |
| 44 | return classifyType(field.ty, mod); | 45 | return classifyType(field_ty, mod); |
| 45 | }, | 46 | }, |
| 46 | .Int, .Enum, .ErrorSet, .Vector => { | 47 | .Int, .Enum, .ErrorSet, .Vector => { |
| 47 | const int_bits = ty.intInfo(mod).bits; | 48 | const int_bits = ty.intInfo(mod).bits; |
| ... | @@ -101,15 +102,11 @@ pub fn scalarType(ty: Type, mod: *Module) Type { | ... | @@ -101,15 +102,11 @@ pub fn scalarType(ty: Type, mod: *Module) Type { |
| 101 | const ip = &mod.intern_pool; | 102 | const ip = &mod.intern_pool; |
| 102 | switch (ty.zigTypeTag(mod)) { | 103 | switch (ty.zigTypeTag(mod)) { |
| 103 | .Struct => { | 104 | .Struct => { |
| 104 | switch (ty.containerLayout(mod)) { | 105 | if (mod.typeToPackedStruct(ty)) |packed_struct| { |
| 105 | .Packed => { | 106 | return scalarType(packed_struct.backingIntType(ip).toType(), mod); |
| 106 | const struct_obj = mod.typeToStruct(ty).?; | 107 | } else { |
| 107 | return scalarType(struct_obj.backing_int_ty, mod); | 108 | assert(ty.structFieldCount(mod) == 1); |
| 108 | }, | 109 | return scalarType(ty.structFieldType(0, mod), mod); |
| 109 | else => { | ||
| 110 | assert(ty.structFieldCount(mod) == 1); | ||
| 111 | return scalarType(ty.structFieldType(0, mod), mod); | ||
| 112 | }, | ||
| 113 | } | 110 | } |
| 114 | }, | 111 | }, |
| 115 | .Union => { | 112 | .Union => { |
src/arch/x86_64/CodeGen.zig+59-57| ... | @@ -27,6 +27,7 @@ const Lower = @import("Lower.zig"); | ... | @@ -27,6 +27,7 @@ const Lower = @import("Lower.zig"); |
| 27 | const Mir = @import("Mir.zig"); | 27 | const Mir = @import("Mir.zig"); |
| 28 | const Module = @import("../../Module.zig"); | 28 | const Module = @import("../../Module.zig"); |
| 29 | const InternPool = @import("../../InternPool.zig"); | 29 | const InternPool = @import("../../InternPool.zig"); |
| 30 | const Alignment = InternPool.Alignment; | ||
| 30 | const Target = std.Target; | 31 | const Target = std.Target; |
| 31 | const Type = @import("../../type.zig").Type; | 32 | const Type = @import("../../type.zig").Type; |
| 32 | const TypedValue = @import("../../TypedValue.zig"); | 33 | const TypedValue = @import("../../TypedValue.zig"); |
| ... | @@ -607,19 +608,21 @@ const InstTracking = struct { | ... | @@ -607,19 +608,21 @@ const InstTracking = struct { |
| 607 | 608 | ||
| 608 | const FrameAlloc = struct { | 609 | const FrameAlloc = struct { |
| 609 | abi_size: u31, | 610 | abi_size: u31, |
| 610 | abi_align: u5, | 611 | abi_align: Alignment, |
| 611 | ref_count: u16, | 612 | ref_count: u16, |
| 612 | 613 | ||
| 613 | fn init(alloc_abi: struct { size: u64, alignment: u32 }) FrameAlloc { | 614 | fn init(alloc_abi: struct { size: u64, alignment: Alignment }) FrameAlloc { |
| 614 | assert(math.isPowerOfTwo(alloc_abi.alignment)); | ||
| 615 | return .{ | 615 | return .{ |
| 616 | .abi_size = @intCast(alloc_abi.size), | 616 | .abi_size = @intCast(alloc_abi.size), |
| 617 | .abi_align = math.log2_int(u32, alloc_abi.alignment), | 617 | .abi_align = alloc_abi.alignment, |
| 618 | .ref_count = 0, | 618 | .ref_count = 0, |
| 619 | }; | 619 | }; |
| 620 | } | 620 | } |
| 621 | fn initType(ty: Type, mod: *Module) FrameAlloc { | 621 | fn initType(ty: Type, mod: *Module) FrameAlloc { |
| 622 | return init(.{ .size = ty.abiSize(mod), .alignment = ty.abiAlignment(mod) }); | 622 | return init(.{ |
| 623 | .size = ty.abiSize(mod), | ||
| 624 | .alignment = ty.abiAlignment(mod), | ||
| 625 | }); | ||
| 623 | } | 626 | } |
| 624 | }; | 627 | }; |
| 625 | 628 | ||
| ... | @@ -702,12 +705,12 @@ pub fn generate( | ... | @@ -702,12 +705,12 @@ pub fn generate( |
| 702 | @intFromEnum(FrameIndex.stack_frame), | 705 | @intFromEnum(FrameIndex.stack_frame), |
| 703 | FrameAlloc.init(.{ | 706 | FrameAlloc.init(.{ |
| 704 | .size = 0, | 707 | .size = 0, |
| 705 | .alignment = @intCast(func.analysis(ip).stack_alignment.toByteUnitsOptional() orelse 1), | 708 | .alignment = func.analysis(ip).stack_alignment.max(.@"1"), |
| 706 | }), | 709 | }), |
| 707 | ); | 710 | ); |
| 708 | function.frame_allocs.set( | 711 | function.frame_allocs.set( |
| 709 | @intFromEnum(FrameIndex.call_frame), | 712 | @intFromEnum(FrameIndex.call_frame), |
| 710 | FrameAlloc.init(.{ .size = 0, .alignment = 1 }), | 713 | FrameAlloc.init(.{ .size = 0, .alignment = .@"1" }), |
| 711 | ); | 714 | ); |
| 712 | 715 | ||
| 713 | const fn_info = mod.typeToFunc(fn_type).?; | 716 | const fn_info = mod.typeToFunc(fn_type).?; |
| ... | @@ -729,15 +732,21 @@ pub fn generate( | ... | @@ -729,15 +732,21 @@ pub fn generate( |
| 729 | function.ret_mcv = call_info.return_value; | 732 | function.ret_mcv = call_info.return_value; |
| 730 | function.frame_allocs.set(@intFromEnum(FrameIndex.ret_addr), FrameAlloc.init(.{ | 733 | function.frame_allocs.set(@intFromEnum(FrameIndex.ret_addr), FrameAlloc.init(.{ |
| 731 | .size = Type.usize.abiSize(mod), | 734 | .size = Type.usize.abiSize(mod), |
| 732 | .alignment = @min(Type.usize.abiAlignment(mod), call_info.stack_align), | 735 | .alignment = Type.usize.abiAlignment(mod).min(call_info.stack_align), |
| 733 | })); | 736 | })); |
| 734 | function.frame_allocs.set(@intFromEnum(FrameIndex.base_ptr), FrameAlloc.init(.{ | 737 | function.frame_allocs.set(@intFromEnum(FrameIndex.base_ptr), FrameAlloc.init(.{ |
| 735 | .size = Type.usize.abiSize(mod), | 738 | .size = Type.usize.abiSize(mod), |
| 736 | .alignment = @min(Type.usize.abiAlignment(mod) * 2, call_info.stack_align), | 739 | .alignment = Alignment.min( |
| 740 | call_info.stack_align, | ||
| 741 | Alignment.fromNonzeroByteUnits(bin_file.options.target.stackAlignment()), | ||
| 742 | ), | ||
| 737 | })); | 743 | })); |
| 738 | function.frame_allocs.set( | 744 | function.frame_allocs.set( |
| 739 | @intFromEnum(FrameIndex.args_frame), | 745 | @intFromEnum(FrameIndex.args_frame), |
| 740 | FrameAlloc.init(.{ .size = call_info.stack_byte_count, .alignment = call_info.stack_align }), | 746 | FrameAlloc.init(.{ |
| 747 | .size = call_info.stack_byte_count, | ||
| 748 | .alignment = call_info.stack_align, | ||
| 749 | }), | ||
| 741 | ); | 750 | ); |
| 742 | 751 | ||
| 743 | function.gen() catch |err| switch (err) { | 752 | function.gen() catch |err| switch (err) { |
| ... | @@ -2156,8 +2165,8 @@ fn setFrameLoc( | ... | @@ -2156,8 +2165,8 @@ fn setFrameLoc( |
| 2156 | ) void { | 2165 | ) void { |
| 2157 | const frame_i = @intFromEnum(frame_index); | 2166 | const frame_i = @intFromEnum(frame_index); |
| 2158 | if (aligned) { | 2167 | if (aligned) { |
| 2159 | const alignment = @as(i32, 1) << self.frame_allocs.items(.abi_align)[frame_i]; | 2168 | const alignment = self.frame_allocs.items(.abi_align)[frame_i]; |
| 2160 | offset.* = mem.alignForward(i32, offset.*, alignment); | 2169 | offset.* = @intCast(alignment.forward(@intCast(offset.*))); |
| 2161 | } | 2170 | } |
| 2162 | self.frame_locs.set(frame_i, .{ .base = base, .disp = offset.* }); | 2171 | self.frame_locs.set(frame_i, .{ .base = base, .disp = offset.* }); |
| 2163 | offset.* += self.frame_allocs.items(.abi_size)[frame_i]; | 2172 | offset.* += self.frame_allocs.items(.abi_size)[frame_i]; |
| ... | @@ -2179,7 +2188,7 @@ fn computeFrameLayout(self: *Self) !FrameLayout { | ... | @@ -2179,7 +2188,7 @@ fn computeFrameLayout(self: *Self) !FrameLayout { |
| 2179 | const SortContext = struct { | 2188 | const SortContext = struct { |
| 2180 | frame_align: @TypeOf(frame_align), | 2189 | frame_align: @TypeOf(frame_align), |
| 2181 | pub fn lessThan(context: @This(), lhs: FrameIndex, rhs: FrameIndex) bool { | 2190 | pub fn lessThan(context: @This(), lhs: FrameIndex, rhs: FrameIndex) bool { |
| 2182 | return context.frame_align[@intFromEnum(lhs)] > context.frame_align[@intFromEnum(rhs)]; | 2191 | return context.frame_align[@intFromEnum(lhs)].compare(.gt, context.frame_align[@intFromEnum(rhs)]); |
| 2183 | } | 2192 | } |
| 2184 | }; | 2193 | }; |
| 2185 | const sort_context = SortContext{ .frame_align = frame_align }; | 2194 | const sort_context = SortContext{ .frame_align = frame_align }; |
| ... | @@ -2189,8 +2198,8 @@ fn computeFrameLayout(self: *Self) !FrameLayout { | ... | @@ -2189,8 +2198,8 @@ fn computeFrameLayout(self: *Self) !FrameLayout { |
| 2189 | const call_frame_align = frame_align[@intFromEnum(FrameIndex.call_frame)]; | 2198 | const call_frame_align = frame_align[@intFromEnum(FrameIndex.call_frame)]; |
| 2190 | const stack_frame_align = frame_align[@intFromEnum(FrameIndex.stack_frame)]; | 2199 | const stack_frame_align = frame_align[@intFromEnum(FrameIndex.stack_frame)]; |
| 2191 | const args_frame_align = frame_align[@intFromEnum(FrameIndex.args_frame)]; | 2200 | const args_frame_align = frame_align[@intFromEnum(FrameIndex.args_frame)]; |
| 2192 | const needed_align = @max(call_frame_align, stack_frame_align); | 2201 | const needed_align = call_frame_align.max(stack_frame_align); |
| 2193 | const need_align_stack = needed_align > args_frame_align; | 2202 | const need_align_stack = needed_align.compare(.gt, args_frame_align); |
| 2194 | 2203 | ||
| 2195 | // Create list of registers to save in the prologue. | 2204 | // Create list of registers to save in the prologue. |
| 2196 | // TODO handle register classes | 2205 | // TODO handle register classes |
| ... | @@ -2214,21 +2223,21 @@ fn computeFrameLayout(self: *Self) !FrameLayout { | ... | @@ -2214,21 +2223,21 @@ fn computeFrameLayout(self: *Self) !FrameLayout { |
| 2214 | self.setFrameLoc(.stack_frame, .rsp, &rsp_offset, true); | 2223 | self.setFrameLoc(.stack_frame, .rsp, &rsp_offset, true); |
| 2215 | for (stack_frame_order) |frame_index| self.setFrameLoc(frame_index, .rsp, &rsp_offset, true); | 2224 | for (stack_frame_order) |frame_index| self.setFrameLoc(frame_index, .rsp, &rsp_offset, true); |
| 2216 | rsp_offset += stack_frame_align_offset; | 2225 | rsp_offset += stack_frame_align_offset; |
| 2217 | rsp_offset = mem.alignForward(i32, rsp_offset, @as(i32, 1) << needed_align); | 2226 | rsp_offset = @intCast(needed_align.forward(@intCast(rsp_offset))); |
| 2218 | rsp_offset -= stack_frame_align_offset; | 2227 | rsp_offset -= stack_frame_align_offset; |
| 2219 | frame_size[@intFromEnum(FrameIndex.call_frame)] = | 2228 | frame_size[@intFromEnum(FrameIndex.call_frame)] = |
| 2220 | @intCast(rsp_offset - frame_offset[@intFromEnum(FrameIndex.stack_frame)]); | 2229 | @intCast(rsp_offset - frame_offset[@intFromEnum(FrameIndex.stack_frame)]); |
| 2221 | 2230 | ||
| 2222 | return .{ | 2231 | return .{ |
| 2223 | .stack_mask = @as(u32, math.maxInt(u32)) << (if (need_align_stack) needed_align else 0), | 2232 | .stack_mask = @as(u32, math.maxInt(u32)) << @intCast(if (need_align_stack) @intFromEnum(needed_align) else 0), |
| 2224 | .stack_adjust = @intCast(rsp_offset - frame_offset[@intFromEnum(FrameIndex.call_frame)]), | 2233 | .stack_adjust = @intCast(rsp_offset - frame_offset[@intFromEnum(FrameIndex.call_frame)]), |
| 2225 | .save_reg_list = save_reg_list, | 2234 | .save_reg_list = save_reg_list, |
| 2226 | }; | 2235 | }; |
| 2227 | } | 2236 | } |
| 2228 | 2237 | ||
| 2229 | fn getFrameAddrAlignment(self: *Self, frame_addr: FrameAddr) u32 { | 2238 | fn getFrameAddrAlignment(self: *Self, frame_addr: FrameAddr) Alignment { |
| 2230 | const alloc_align = @as(u32, 1) << self.frame_allocs.get(@intFromEnum(frame_addr.index)).abi_align; | 2239 | const alloc_align = self.frame_allocs.get(@intFromEnum(frame_addr.index)).abi_align; |
| 2231 | return @min(alloc_align, @as(u32, @bitCast(frame_addr.off)) & (alloc_align - 1)); | 2240 | return @enumFromInt(@min(@intFromEnum(alloc_align), @ctz(frame_addr.off))); |
| 2232 | } | 2241 | } |
| 2233 | 2242 | ||
| 2234 | fn getFrameAddrSize(self: *Self, frame_addr: FrameAddr) u32 { | 2243 | fn getFrameAddrSize(self: *Self, frame_addr: FrameAddr) u32 { |
| ... | @@ -2241,13 +2250,13 @@ fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex { | ... | @@ -2241,13 +2250,13 @@ fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex { |
| 2241 | const frame_align = frame_allocs_slice.items(.abi_align); | 2250 | const frame_align = frame_allocs_slice.items(.abi_align); |
| 2242 | 2251 | ||
| 2243 | const stack_frame_align = &frame_align[@intFromEnum(FrameIndex.stack_frame)]; | 2252 | const stack_frame_align = &frame_align[@intFromEnum(FrameIndex.stack_frame)]; |
| 2244 | stack_frame_align.* = @max(stack_frame_align.*, alloc.abi_align); | 2253 | stack_frame_align.* = stack_frame_align.max(alloc.abi_align); |
| 2245 | 2254 | ||
| 2246 | for (self.free_frame_indices.keys(), 0..) |frame_index, free_i| { | 2255 | for (self.free_frame_indices.keys(), 0..) |frame_index, free_i| { |
| 2247 | const abi_size = frame_size[@intFromEnum(frame_index)]; | 2256 | const abi_size = frame_size[@intFromEnum(frame_index)]; |
| 2248 | if (abi_size != alloc.abi_size) continue; | 2257 | if (abi_size != alloc.abi_size) continue; |
| 2249 | const abi_align = &frame_align[@intFromEnum(frame_index)]; | 2258 | const abi_align = &frame_align[@intFromEnum(frame_index)]; |
| 2250 | abi_align.* = @max(abi_align.*, alloc.abi_align); | 2259 | abi_align.* = abi_align.max(alloc.abi_align); |
| 2251 | 2260 | ||
| 2252 | _ = self.free_frame_indices.swapRemoveAt(free_i); | 2261 | _ = self.free_frame_indices.swapRemoveAt(free_i); |
| 2253 | return frame_index; | 2262 | return frame_index; |
| ... | @@ -2266,7 +2275,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !FrameIndex { | ... | @@ -2266,7 +2275,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !FrameIndex { |
| 2266 | .size = math.cast(u32, val_ty.abiSize(mod)) orelse { | 2275 | .size = math.cast(u32, val_ty.abiSize(mod)) orelse { |
| 2267 | return self.fail("type '{}' too big to fit into stack frame", .{val_ty.fmt(mod)}); | 2276 | return self.fail("type '{}' too big to fit into stack frame", .{val_ty.fmt(mod)}); |
| 2268 | }, | 2277 | }, |
| 2269 | .alignment = @max(ptr_ty.ptrAlignment(mod), 1), | 2278 | .alignment = ptr_ty.ptrAlignment(mod).max(.@"1"), |
| 2270 | })); | 2279 | })); |
| 2271 | } | 2280 | } |
| 2272 | 2281 | ||
| ... | @@ -4266,7 +4275,7 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4266,7 +4275,7 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 4266 | }; | 4275 | }; |
| 4267 | defer if (tag_lock) |lock| self.register_manager.unlockReg(lock); | 4276 | defer if (tag_lock) |lock| self.register_manager.unlockReg(lock); |
| 4268 | 4277 | ||
| 4269 | const adjusted_ptr: MCValue = if (layout.payload_size > 0 and layout.tag_align < layout.payload_align) blk: { | 4278 | const adjusted_ptr: MCValue = if (layout.payload_size > 0 and layout.tag_align.compare(.lt, layout.payload_align)) blk: { |
| 4270 | // TODO reusing the operand | 4279 | // TODO reusing the operand |
| 4271 | const reg = try self.copyToTmpRegister(ptr_union_ty, ptr); | 4280 | const reg = try self.copyToTmpRegister(ptr_union_ty, ptr); |
| 4272 | try self.genBinOpMir( | 4281 | try self.genBinOpMir( |
| ... | @@ -4309,7 +4318,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4309,7 +4318,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 4309 | switch (operand) { | 4318 | switch (operand) { |
| 4310 | .load_frame => |frame_addr| { | 4319 | .load_frame => |frame_addr| { |
| 4311 | if (tag_abi_size <= 8) { | 4320 | if (tag_abi_size <= 8) { |
| 4312 | const off: i32 = if (layout.tag_align < layout.payload_align) | 4321 | const off: i32 = if (layout.tag_align.compare(.lt, layout.payload_align)) |
| 4313 | @intCast(layout.payload_size) | 4322 | @intCast(layout.payload_size) |
| 4314 | else | 4323 | else |
| 4315 | 0; | 4324 | 0; |
| ... | @@ -4321,7 +4330,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4321,7 +4330,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 4321 | return self.fail("TODO implement get_union_tag for ABI larger than 8 bytes and operand {}", .{operand}); | 4330 | return self.fail("TODO implement get_union_tag for ABI larger than 8 bytes and operand {}", .{operand}); |
| 4322 | }, | 4331 | }, |
| 4323 | .register => { | 4332 | .register => { |
| 4324 | const shift: u6 = if (layout.tag_align < layout.payload_align) | 4333 | const shift: u6 = if (layout.tag_align.compare(.lt, layout.payload_align)) |
| 4325 | @intCast(layout.payload_size * 8) | 4334 | @intCast(layout.payload_size * 8) |
| 4326 | else | 4335 | else |
| 4327 | 0; | 4336 | 0; |
| ... | @@ -5600,8 +5609,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5600,8 +5609,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 5600 | const src_mcv = try self.resolveInst(operand); | 5609 | const src_mcv = try self.resolveInst(operand); |
| 5601 | const field_off: u32 = switch (container_ty.containerLayout(mod)) { | 5610 | const field_off: u32 = switch (container_ty.containerLayout(mod)) { |
| 5602 | .Auto, .Extern => @intCast(container_ty.structFieldOffset(index, mod) * 8), | 5611 | .Auto, .Extern => @intCast(container_ty.structFieldOffset(index, mod) * 8), |
| 5603 | .Packed => if (mod.typeToStruct(container_ty)) |struct_obj| | 5612 | .Packed => if (mod.typeToStruct(container_ty)) |struct_type| |
| 5604 | struct_obj.packedFieldBitOffset(mod, index) | 5613 | mod.structPackedFieldBitOffset(struct_type, index) |
| 5605 | else | 5614 | else |
| 5606 | 0, | 5615 | 0, |
| 5607 | }; | 5616 | }; |
| ... | @@ -8084,14 +8093,17 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -8084,14 +8093,17 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 8084 | // We need a properly aligned and sized call frame to be able to call this function. | 8093 | // We need a properly aligned and sized call frame to be able to call this function. |
| 8085 | { | 8094 | { |
| 8086 | const needed_call_frame = | 8095 | const needed_call_frame = |
| 8087 | FrameAlloc.init(.{ .size = info.stack_byte_count, .alignment = info.stack_align }); | 8096 | FrameAlloc.init(.{ |
| 8097 | .size = info.stack_byte_count, | ||
| 8098 | .alignment = info.stack_align, | ||
| 8099 | }); | ||
| 8088 | const frame_allocs_slice = self.frame_allocs.slice(); | 8100 | const frame_allocs_slice = self.frame_allocs.slice(); |
| 8089 | const stack_frame_size = | 8101 | const stack_frame_size = |
| 8090 | &frame_allocs_slice.items(.abi_size)[@intFromEnum(FrameIndex.call_frame)]; | 8102 | &frame_allocs_slice.items(.abi_size)[@intFromEnum(FrameIndex.call_frame)]; |
| 8091 | stack_frame_size.* = @max(stack_frame_size.*, needed_call_frame.abi_size); | 8103 | stack_frame_size.* = @max(stack_frame_size.*, needed_call_frame.abi_size); |
| 8092 | const stack_frame_align = | 8104 | const stack_frame_align = |
| 8093 | &frame_allocs_slice.items(.abi_align)[@intFromEnum(FrameIndex.call_frame)]; | 8105 | &frame_allocs_slice.items(.abi_align)[@intFromEnum(FrameIndex.call_frame)]; |
| 8094 | stack_frame_align.* = @max(stack_frame_align.*, needed_call_frame.abi_align); | 8106 | stack_frame_align.* = stack_frame_align.max(needed_call_frame.abi_align); |
| 8095 | } | 8107 | } |
| 8096 | 8108 | ||
| 8097 | try self.spillEflagsIfOccupied(); | 8109 | try self.spillEflagsIfOccupied(); |
| ... | @@ -9944,7 +9956,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -9944,7 +9956,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 9944 | .indirect => try self.moveStrategy(ty, false), | 9956 | .indirect => try self.moveStrategy(ty, false), |
| 9945 | .load_frame => |frame_addr| try self.moveStrategy( | 9957 | .load_frame => |frame_addr| try self.moveStrategy( |
| 9946 | ty, | 9958 | ty, |
| 9947 | self.getFrameAddrAlignment(frame_addr) >= ty.abiAlignment(mod), | 9959 | self.getFrameAddrAlignment(frame_addr).compare(.gte, ty.abiAlignment(mod)), |
| 9948 | ), | 9960 | ), |
| 9949 | .lea_frame => .{ .move = .{ ._, .lea } }, | 9961 | .lea_frame => .{ .move = .{ ._, .lea } }, |
| 9950 | else => unreachable, | 9962 | else => unreachable, |
| ... | @@ -9973,10 +9985,8 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -9973,10 +9985,8 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 9973 | .base = .{ .reg = .ds }, | 9985 | .base = .{ .reg = .ds }, |
| 9974 | .disp = small_addr, | 9986 | .disp = small_addr, |
| 9975 | }); | 9987 | }); |
| 9976 | switch (try self.moveStrategy(ty, mem.isAlignedGeneric( | 9988 | switch (try self.moveStrategy(ty, ty.abiAlignment(mod).check( |
| 9977 | u32, | ||
| 9978 | @as(u32, @bitCast(small_addr)), | 9989 | @as(u32, @bitCast(small_addr)), |
| 9979 | ty.abiAlignment(mod), | ||
| 9980 | ))) { | 9990 | ))) { |
| 9981 | .move => |tag| try self.asmRegisterMemory(tag, dst_alias, src_mem), | 9991 | .move => |tag| try self.asmRegisterMemory(tag, dst_alias, src_mem), |
| 9982 | .insert_extract => |ie| try self.asmRegisterMemoryImmediate( | 9992 | .insert_extract => |ie| try self.asmRegisterMemoryImmediate( |
| ... | @@ -10142,22 +10152,14 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal | ... | @@ -10142,22 +10152,14 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal |
| 10142 | ); | 10152 | ); |
| 10143 | const src_alias = registerAlias(src_reg, abi_size); | 10153 | const src_alias = registerAlias(src_reg, abi_size); |
| 10144 | switch (try self.moveStrategy(ty, switch (base) { | 10154 | switch (try self.moveStrategy(ty, switch (base) { |
| 10145 | .none => mem.isAlignedGeneric( | 10155 | .none => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))), |
| 10146 | u32, | ||
| 10147 | @as(u32, @bitCast(disp)), | ||
| 10148 | ty.abiAlignment(mod), | ||
| 10149 | ), | ||
| 10150 | .reg => |reg| switch (reg) { | 10156 | .reg => |reg| switch (reg) { |
| 10151 | .es, .cs, .ss, .ds => mem.isAlignedGeneric( | 10157 | .es, .cs, .ss, .ds => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))), |
| 10152 | u32, | ||
| 10153 | @as(u32, @bitCast(disp)), | ||
| 10154 | ty.abiAlignment(mod), | ||
| 10155 | ), | ||
| 10156 | else => false, | 10158 | else => false, |
| 10157 | }, | 10159 | }, |
| 10158 | .frame => |frame_index| self.getFrameAddrAlignment( | 10160 | .frame => |frame_index| self.getFrameAddrAlignment( |
| 10159 | .{ .index = frame_index, .off = disp }, | 10161 | .{ .index = frame_index, .off = disp }, |
| 10160 | ) >= ty.abiAlignment(mod), | 10162 | ).compare(.gte, ty.abiAlignment(mod)), |
| 10161 | })) { | 10163 | })) { |
| 10162 | .move => |tag| try self.asmMemoryRegister(tag, dst_mem, src_alias), | 10164 | .move => |tag| try self.asmMemoryRegister(tag, dst_mem, src_alias), |
| 10163 | .insert_extract, .vex_insert_extract => |ie| try self.asmMemoryRegisterImmediate( | 10165 | .insert_extract, .vex_insert_extract => |ie| try self.asmMemoryRegisterImmediate( |
| ... | @@ -11079,7 +11081,7 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -11079,7 +11081,7 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { |
| 11079 | stack_frame_size.* = @max(stack_frame_size.*, needed_call_frame.abi_size); | 11081 | stack_frame_size.* = @max(stack_frame_size.*, needed_call_frame.abi_size); |
| 11080 | const stack_frame_align = | 11082 | const stack_frame_align = |
| 11081 | &frame_allocs_slice.items(.abi_align)[@intFromEnum(FrameIndex.call_frame)]; | 11083 | &frame_allocs_slice.items(.abi_align)[@intFromEnum(FrameIndex.call_frame)]; |
| 11082 | stack_frame_align.* = @max(stack_frame_align.*, needed_call_frame.abi_align); | 11084 | stack_frame_align.* = stack_frame_align.max(needed_call_frame.abi_align); |
| 11083 | } | 11085 | } |
| 11084 | 11086 | ||
| 11085 | try self.spillEflagsIfOccupied(); | 11087 | try self.spillEflagsIfOccupied(); |
| ... | @@ -11418,7 +11420,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -11418,7 +11420,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 11418 | const frame_index = | 11420 | const frame_index = |
| 11419 | try self.allocFrameIndex(FrameAlloc.initType(result_ty, mod)); | 11421 | try self.allocFrameIndex(FrameAlloc.initType(result_ty, mod)); |
| 11420 | if (result_ty.containerLayout(mod) == .Packed) { | 11422 | if (result_ty.containerLayout(mod) == .Packed) { |
| 11421 | const struct_obj = mod.typeToStruct(result_ty).?; | 11423 | const struct_type = mod.typeToStruct(result_ty).?; |
| 11422 | try self.genInlineMemset( | 11424 | try self.genInlineMemset( |
| 11423 | .{ .lea_frame = .{ .index = frame_index } }, | 11425 | .{ .lea_frame = .{ .index = frame_index } }, |
| 11424 | .{ .immediate = 0 }, | 11426 | .{ .immediate = 0 }, |
| ... | @@ -11437,7 +11439,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -11437,7 +11439,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 11437 | } | 11439 | } |
| 11438 | const elem_abi_size: u32 = @intCast(elem_ty.abiSize(mod)); | 11440 | const elem_abi_size: u32 = @intCast(elem_ty.abiSize(mod)); |
| 11439 | const elem_abi_bits = elem_abi_size * 8; | 11441 | const elem_abi_bits = elem_abi_size * 8; |
| 11440 | const elem_off = struct_obj.packedFieldBitOffset(mod, elem_i); | 11442 | const elem_off = mod.structPackedFieldBitOffset(struct_type, elem_i); |
| 11441 | const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size); | 11443 | const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size); |
| 11442 | const elem_bit_off = elem_off % elem_abi_bits; | 11444 | const elem_bit_off = elem_off % elem_abi_bits; |
| 11443 | const elem_mcv = try self.resolveInst(elem); | 11445 | const elem_mcv = try self.resolveInst(elem); |
| ... | @@ -11576,13 +11578,13 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -11576,13 +11578,13 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void { |
| 11576 | const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index); | 11578 | const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index); |
| 11577 | const tag_int_val = try tag_val.intFromEnum(tag_ty, mod); | 11579 | const tag_int_val = try tag_val.intFromEnum(tag_ty, mod); |
| 11578 | const tag_int = tag_int_val.toUnsignedInt(mod); | 11580 | const tag_int = tag_int_val.toUnsignedInt(mod); |
| 11579 | const tag_off: i32 = if (layout.tag_align < layout.payload_align) | 11581 | const tag_off: i32 = if (layout.tag_align.compare(.lt, layout.payload_align)) |
| 11580 | @intCast(layout.payload_size) | 11582 | @intCast(layout.payload_size) |
| 11581 | else | 11583 | else |
| 11582 | 0; | 11584 | 0; |
| 11583 | try self.genCopy(tag_ty, dst_mcv.address().offset(tag_off).deref(), .{ .immediate = tag_int }); | 11585 | try self.genCopy(tag_ty, dst_mcv.address().offset(tag_off).deref(), .{ .immediate = tag_int }); |
| 11584 | 11586 | ||
| 11585 | const pl_off: i32 = if (layout.tag_align < layout.payload_align) | 11587 | const pl_off: i32 = if (layout.tag_align.compare(.lt, layout.payload_align)) |
| 11586 | 0 | 11588 | 0 |
| 11587 | else | 11589 | else |
| 11588 | @intCast(layout.tag_size); | 11590 | @intCast(layout.tag_size); |
| ... | @@ -11823,7 +11825,7 @@ const CallMCValues = struct { | ... | @@ -11823,7 +11825,7 @@ const CallMCValues = struct { |
| 11823 | args: []MCValue, | 11825 | args: []MCValue, |
| 11824 | return_value: InstTracking, | 11826 | return_value: InstTracking, |
| 11825 | stack_byte_count: u31, | 11827 | stack_byte_count: u31, |
| 11826 | stack_align: u31, | 11828 | stack_align: Alignment, |
| 11827 | 11829 | ||
| 11828 | fn deinit(self: *CallMCValues, func: *Self) void { | 11830 | fn deinit(self: *CallMCValues, func: *Self) void { |
| 11829 | func.gpa.free(self.args); | 11831 | func.gpa.free(self.args); |
| ... | @@ -11867,12 +11869,12 @@ fn resolveCallingConventionValues( | ... | @@ -11867,12 +11869,12 @@ fn resolveCallingConventionValues( |
| 11867 | .Naked => { | 11869 | .Naked => { |
| 11868 | assert(result.args.len == 0); | 11870 | assert(result.args.len == 0); |
| 11869 | result.return_value = InstTracking.init(.unreach); | 11871 | result.return_value = InstTracking.init(.unreach); |
| 11870 | result.stack_align = 8; | 11872 | result.stack_align = .@"8"; |
| 11871 | }, | 11873 | }, |
| 11872 | .C => { | 11874 | .C => { |
| 11873 | var param_reg_i: usize = 0; | 11875 | var param_reg_i: usize = 0; |
| 11874 | var param_sse_reg_i: usize = 0; | 11876 | var param_sse_reg_i: usize = 0; |
| 11875 | result.stack_align = 16; | 11877 | result.stack_align = .@"16"; |
| 11876 | 11878 | ||
| 11877 | switch (self.target.os.tag) { | 11879 | switch (self.target.os.tag) { |
| 11878 | .windows => { | 11880 | .windows => { |
| ... | @@ -11957,7 +11959,7 @@ fn resolveCallingConventionValues( | ... | @@ -11957,7 +11959,7 @@ fn resolveCallingConventionValues( |
| 11957 | } | 11959 | } |
| 11958 | 11960 | ||
| 11959 | const param_size: u31 = @intCast(ty.abiSize(mod)); | 11961 | const param_size: u31 = @intCast(ty.abiSize(mod)); |
| 11960 | const param_align: u31 = @intCast(ty.abiAlignment(mod)); | 11962 | const param_align: u31 = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?); |
| 11961 | result.stack_byte_count = | 11963 | result.stack_byte_count = |
| 11962 | mem.alignForward(u31, result.stack_byte_count, param_align); | 11964 | mem.alignForward(u31, result.stack_byte_count, param_align); |
| 11963 | arg.* = .{ .load_frame = .{ | 11965 | arg.* = .{ .load_frame = .{ |
| ... | @@ -11968,7 +11970,7 @@ fn resolveCallingConventionValues( | ... | @@ -11968,7 +11970,7 @@ fn resolveCallingConventionValues( |
| 11968 | } | 11970 | } |
| 11969 | }, | 11971 | }, |
| 11970 | .Unspecified => { | 11972 | .Unspecified => { |
| 11971 | result.stack_align = 16; | 11973 | result.stack_align = .@"16"; |
| 11972 | 11974 | ||
| 11973 | // Return values | 11975 | // Return values |
| 11974 | if (ret_ty.zigTypeTag(mod) == .NoReturn) { | 11976 | if (ret_ty.zigTypeTag(mod) == .NoReturn) { |
| ... | @@ -11997,7 +11999,7 @@ fn resolveCallingConventionValues( | ... | @@ -11997,7 +11999,7 @@ fn resolveCallingConventionValues( |
| 11997 | continue; | 11999 | continue; |
| 11998 | } | 12000 | } |
| 11999 | const param_size: u31 = @intCast(ty.abiSize(mod)); | 12001 | const param_size: u31 = @intCast(ty.abiSize(mod)); |
| 12000 | const param_align: u31 = @intCast(ty.abiAlignment(mod)); | 12002 | const param_align: u31 = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?); |
| 12001 | result.stack_byte_count = | 12003 | result.stack_byte_count = |
| 12002 | mem.alignForward(u31, result.stack_byte_count, param_align); | 12004 | mem.alignForward(u31, result.stack_byte_count, param_align); |
| 12003 | arg.* = .{ .load_frame = .{ | 12005 | arg.* = .{ .load_frame = .{ |
| ... | @@ -12010,7 +12012,7 @@ fn resolveCallingConventionValues( | ... | @@ -12010,7 +12012,7 @@ fn resolveCallingConventionValues( |
| 12010 | else => return self.fail("TODO implement function parameters and return values for {} on x86_64", .{cc}), | 12012 | else => return self.fail("TODO implement function parameters and return values for {} on x86_64", .{cc}), |
| 12011 | } | 12013 | } |
| 12012 | 12014 | ||
| 12013 | result.stack_byte_count = mem.alignForward(u31, result.stack_byte_count, result.stack_align); | 12015 | result.stack_byte_count = @intCast(result.stack_align.forward(result.stack_byte_count)); |
| 12014 | return result; | 12016 | return result; |
| 12015 | } | 12017 | } |
| 12016 | 12018 |
src/arch/x86_64/abi.zig+14-24| ... | @@ -210,8 +210,9 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class { | ... | @@ -210,8 +210,9 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class { |
| 210 | // it contains unaligned fields, it has class MEMORY" | 210 | // it contains unaligned fields, it has class MEMORY" |
| 211 | // "If the size of the aggregate exceeds a single eightbyte, each is classified | 211 | // "If the size of the aggregate exceeds a single eightbyte, each is classified |
| 212 | // separately.". | 212 | // separately.". |
| 213 | const struct_type = mod.typeToStruct(ty).?; | ||
| 213 | const ty_size = ty.abiSize(mod); | 214 | const ty_size = ty.abiSize(mod); |
| 214 | if (ty.containerLayout(mod) == .Packed) { | 215 | if (struct_type.layout == .Packed) { |
| 215 | assert(ty_size <= 128); | 216 | assert(ty_size <= 128); |
| 216 | result[0] = .integer; | 217 | result[0] = .integer; |
| 217 | if (ty_size > 64) result[1] = .integer; | 218 | if (ty_size > 64) result[1] = .integer; |
| ... | @@ -222,15 +223,13 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class { | ... | @@ -222,15 +223,13 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class { |
| 222 | 223 | ||
| 223 | var result_i: usize = 0; // out of 8 | 224 | var result_i: usize = 0; // out of 8 |
| 224 | var byte_i: usize = 0; // out of 8 | 225 | var byte_i: usize = 0; // out of 8 |
| 225 | const fields = ty.structFields(mod); | 226 | for (struct_type.field_types.get(ip), 0..) |field_ty_ip, i| { |
| 226 | for (fields.values()) |field| { | 227 | const field_ty = field_ty_ip.toType(); |
| 227 | if (field.abi_align != .none) { | 228 | const field_align = struct_type.fieldAlign(ip, i); |
| 228 | if (field.abi_align.toByteUnitsOptional().? < field.ty.abiAlignment(mod)) { | 229 | if (field_align != .none and field_align.compare(.lt, field_ty.abiAlignment(mod))) |
| 229 | return memory_class; | 230 | return memory_class; |
| 230 | } | 231 | const field_size = field_ty.abiSize(mod); |
| 231 | } | 232 | const field_class_array = classifySystemV(field_ty, mod, .other); |
| 232 | const field_size = field.ty.abiSize(mod); | ||
| 233 | const field_class_array = classifySystemV(field.ty, mod, .other); | ||
| 234 | const field_class = std.mem.sliceTo(&field_class_array, .none); | 233 | const field_class = std.mem.sliceTo(&field_class_array, .none); |
| 235 | if (byte_i + field_size <= 8) { | 234 | if (byte_i + field_size <= 8) { |
| 236 | // Combine this field with the previous one. | 235 | // Combine this field with the previous one. |
| ... | @@ -341,10 +340,11 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class { | ... | @@ -341,10 +340,11 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class { |
| 341 | return memory_class; | 340 | return memory_class; |
| 342 | 341 | ||
| 343 | for (union_obj.field_types.get(ip), 0..) |field_ty, field_index| { | 342 | for (union_obj.field_types.get(ip), 0..) |field_ty, field_index| { |
| 344 | if (union_obj.fieldAlign(ip, @intCast(field_index)).toByteUnitsOptional()) |a| { | 343 | const field_align = union_obj.fieldAlign(ip, @intCast(field_index)); |
| 345 | if (a < field_ty.toType().abiAlignment(mod)) { | 344 | if (field_align != .none and |
| 346 | return memory_class; | 345 | field_align.compare(.lt, field_ty.toType().abiAlignment(mod))) |
| 347 | } | 346 | { |
| 347 | return memory_class; | ||
| 348 | } | 348 | } |
| 349 | // Combine this field with the previous one. | 349 | // Combine this field with the previous one. |
| 350 | const field_class = classifySystemV(field_ty.toType(), mod, .other); | 350 | const field_class = classifySystemV(field_ty.toType(), mod, .other); |
| ... | @@ -533,13 +533,3 @@ const Register = @import("bits.zig").Register; | ... | @@ -533,13 +533,3 @@ const Register = @import("bits.zig").Register; |
| 533 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; | 533 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; |
| 534 | const Type = @import("../../type.zig").Type; | 534 | const Type = @import("../../type.zig").Type; |
| 535 | const Value = @import("../../value.zig").Value; | 535 | const Value = @import("../../value.zig").Value; |
| 536 | |||
| 537 | fn _field(comptime tag: Type.Tag, offset: u32) Module.Struct.Field { | ||
| 538 | return .{ | ||
| 539 | .ty = Type.initTag(tag), | ||
| 540 | .default_val = Value.initTag(.unreachable_value), | ||
| 541 | .abi_align = 0, | ||
| 542 | .offset = offset, | ||
| 543 | .is_comptime = false, | ||
| 544 | }; | ||
| 545 | } |
src/codegen.zig+55-48| ... | @@ -22,6 +22,7 @@ const Type = @import("type.zig").Type; | ... | @@ -22,6 +22,7 @@ const Type = @import("type.zig").Type; |
| 22 | const TypedValue = @import("TypedValue.zig"); | 22 | const TypedValue = @import("TypedValue.zig"); |
| 23 | const Value = @import("value.zig").Value; | 23 | const Value = @import("value.zig").Value; |
| 24 | const Zir = @import("Zir.zig"); | 24 | const Zir = @import("Zir.zig"); |
| 25 | const Alignment = InternPool.Alignment; | ||
| 25 | 26 | ||
| 26 | pub const Result = union(enum) { | 27 | pub const Result = union(enum) { |
| 27 | /// The `code` parameter passed to `generateSymbol` has the value ok. | 28 | /// The `code` parameter passed to `generateSymbol` has the value ok. |
| ... | @@ -116,7 +117,8 @@ pub fn generateLazySymbol( | ... | @@ -116,7 +117,8 @@ pub fn generateLazySymbol( |
| 116 | bin_file: *link.File, | 117 | bin_file: *link.File, |
| 117 | src_loc: Module.SrcLoc, | 118 | src_loc: Module.SrcLoc, |
| 118 | lazy_sym: link.File.LazySymbol, | 119 | lazy_sym: link.File.LazySymbol, |
| 119 | alignment: *u32, | 120 | // TODO don't use an "out" parameter like this; put it in the result instead |
| 121 | alignment: *Alignment, | ||
| 120 | code: *std.ArrayList(u8), | 122 | code: *std.ArrayList(u8), |
| 121 | debug_output: DebugInfoOutput, | 123 | debug_output: DebugInfoOutput, |
| 122 | reloc_info: RelocInfo, | 124 | reloc_info: RelocInfo, |
| ... | @@ -141,7 +143,7 @@ pub fn generateLazySymbol( | ... | @@ -141,7 +143,7 @@ pub fn generateLazySymbol( |
| 141 | } | 143 | } |
| 142 | 144 | ||
| 143 | if (lazy_sym.ty.isAnyError(mod)) { | 145 | if (lazy_sym.ty.isAnyError(mod)) { |
| 144 | alignment.* = 4; | 146 | alignment.* = .@"4"; |
| 145 | const err_names = mod.global_error_set.keys(); | 147 | const err_names = mod.global_error_set.keys(); |
| 146 | mem.writeInt(u32, try code.addManyAsArray(4), @as(u32, @intCast(err_names.len)), endian); | 148 | mem.writeInt(u32, try code.addManyAsArray(4), @as(u32, @intCast(err_names.len)), endian); |
| 147 | var offset = code.items.len; | 149 | var offset = code.items.len; |
| ... | @@ -157,7 +159,7 @@ pub fn generateLazySymbol( | ... | @@ -157,7 +159,7 @@ pub fn generateLazySymbol( |
| 157 | mem.writeInt(u32, code.items[offset..][0..4], @as(u32, @intCast(code.items.len)), endian); | 159 | mem.writeInt(u32, code.items[offset..][0..4], @as(u32, @intCast(code.items.len)), endian); |
| 158 | return Result.ok; | 160 | return Result.ok; |
| 159 | } else if (lazy_sym.ty.zigTypeTag(mod) == .Enum) { | 161 | } else if (lazy_sym.ty.zigTypeTag(mod) == .Enum) { |
| 160 | alignment.* = 1; | 162 | alignment.* = .@"1"; |
| 161 | for (lazy_sym.ty.enumFields(mod)) |tag_name_ip| { | 163 | for (lazy_sym.ty.enumFields(mod)) |tag_name_ip| { |
| 162 | const tag_name = mod.intern_pool.stringToSlice(tag_name_ip); | 164 | const tag_name = mod.intern_pool.stringToSlice(tag_name_ip); |
| 163 | try code.ensureUnusedCapacity(tag_name.len + 1); | 165 | try code.ensureUnusedCapacity(tag_name.len + 1); |
| ... | @@ -273,7 +275,7 @@ pub fn generateSymbol( | ... | @@ -273,7 +275,7 @@ pub fn generateSymbol( |
| 273 | const abi_align = typed_value.ty.abiAlignment(mod); | 275 | const abi_align = typed_value.ty.abiAlignment(mod); |
| 274 | 276 | ||
| 275 | // error value first when its type is larger than the error union's payload | 277 | // error value first when its type is larger than the error union's payload |
| 276 | if (error_align > payload_align) { | 278 | if (error_align.order(payload_align) == .gt) { |
| 277 | try code.writer().writeInt(u16, err_val, endian); | 279 | try code.writer().writeInt(u16, err_val, endian); |
| 278 | } | 280 | } |
| 279 | 281 | ||
| ... | @@ -291,7 +293,7 @@ pub fn generateSymbol( | ... | @@ -291,7 +293,7 @@ pub fn generateSymbol( |
| 291 | .fail => |em| return .{ .fail = em }, | 293 | .fail => |em| return .{ .fail = em }, |
| 292 | } | 294 | } |
| 293 | const unpadded_end = code.items.len - begin; | 295 | const unpadded_end = code.items.len - begin; |
| 294 | const padded_end = mem.alignForward(u64, unpadded_end, abi_align); | 296 | const padded_end = abi_align.forward(unpadded_end); |
| 295 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; | 297 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; |
| 296 | 298 | ||
| 297 | if (padding > 0) { | 299 | if (padding > 0) { |
| ... | @@ -300,11 +302,11 @@ pub fn generateSymbol( | ... | @@ -300,11 +302,11 @@ pub fn generateSymbol( |
| 300 | } | 302 | } |
| 301 | 303 | ||
| 302 | // Payload size is larger than error set, so emit our error set last | 304 | // Payload size is larger than error set, so emit our error set last |
| 303 | if (error_align <= payload_align) { | 305 | if (error_align.compare(.lte, payload_align)) { |
| 304 | const begin = code.items.len; | 306 | const begin = code.items.len; |
| 305 | try code.writer().writeInt(u16, err_val, endian); | 307 | try code.writer().writeInt(u16, err_val, endian); |
| 306 | const unpadded_end = code.items.len - begin; | 308 | const unpadded_end = code.items.len - begin; |
| 307 | const padded_end = mem.alignForward(u64, unpadded_end, abi_align); | 309 | const padded_end = abi_align.forward(unpadded_end); |
| 308 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; | 310 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; |
| 309 | 311 | ||
| 310 | if (padding > 0) { | 312 | if (padding > 0) { |
| ... | @@ -474,23 +476,18 @@ pub fn generateSymbol( | ... | @@ -474,23 +476,18 @@ pub fn generateSymbol( |
| 474 | } | 476 | } |
| 475 | } | 477 | } |
| 476 | }, | 478 | }, |
| 477 | .struct_type => |struct_type| { | 479 | .struct_type => |struct_type| switch (struct_type.layout) { |
| 478 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | 480 | .Packed => { |
| 479 | |||
| 480 | if (struct_obj.layout == .Packed) { | ||
| 481 | const fields = struct_obj.fields.values(); | ||
| 482 | const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse | 481 | const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse |
| 483 | return error.Overflow; | 482 | return error.Overflow; |
| 484 | const current_pos = code.items.len; | 483 | const current_pos = code.items.len; |
| 485 | try code.resize(current_pos + abi_size); | 484 | try code.resize(current_pos + abi_size); |
| 486 | var bits: u16 = 0; | 485 | var bits: u16 = 0; |
| 487 | 486 | ||
| 488 | for (fields, 0..) |field, index| { | 487 | for (struct_type.field_types.get(ip), 0..) |field_ty, index| { |
| 489 | const field_ty = field.ty; | ||
| 490 | |||
| 491 | const field_val = switch (aggregate.storage) { | 488 | const field_val = switch (aggregate.storage) { |
| 492 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ | 489 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ |
| 493 | .ty = field_ty.toIntern(), | 490 | .ty = field_ty, |
| 494 | .storage = .{ .u64 = bytes[index] }, | 491 | .storage = .{ .u64 = bytes[index] }, |
| 495 | } }), | 492 | } }), |
| 496 | .elems => |elems| elems[index], | 493 | .elems => |elems| elems[index], |
| ... | @@ -499,48 +496,51 @@ pub fn generateSymbol( | ... | @@ -499,48 +496,51 @@ pub fn generateSymbol( |
| 499 | 496 | ||
| 500 | // pointer may point to a decl which must be marked used | 497 | // pointer may point to a decl which must be marked used |
| 501 | // but can also result in a relocation. Therefore we handle those separately. | 498 | // but can also result in a relocation. Therefore we handle those separately. |
| 502 | if (field_ty.zigTypeTag(mod) == .Pointer) { | 499 | if (field_ty.toType().zigTypeTag(mod) == .Pointer) { |
| 503 | const field_size = math.cast(usize, field_ty.abiSize(mod)) orelse | 500 | const field_size = math.cast(usize, field_ty.toType().abiSize(mod)) orelse |
| 504 | return error.Overflow; | 501 | return error.Overflow; |
| 505 | var tmp_list = try std.ArrayList(u8).initCapacity(code.allocator, field_size); | 502 | var tmp_list = try std.ArrayList(u8).initCapacity(code.allocator, field_size); |
| 506 | defer tmp_list.deinit(); | 503 | defer tmp_list.deinit(); |
| 507 | switch (try generateSymbol(bin_file, src_loc, .{ | 504 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 508 | .ty = field_ty, | 505 | .ty = field_ty.toType(), |
| 509 | .val = field_val.toValue(), | 506 | .val = field_val.toValue(), |
| 510 | }, &tmp_list, debug_output, reloc_info)) { | 507 | }, &tmp_list, debug_output, reloc_info)) { |
| 511 | .ok => @memcpy(code.items[current_pos..][0..tmp_list.items.len], tmp_list.items), | 508 | .ok => @memcpy(code.items[current_pos..][0..tmp_list.items.len], tmp_list.items), |
| 512 | .fail => |em| return Result{ .fail = em }, | 509 | .fail => |em| return Result{ .fail = em }, |
| 513 | } | 510 | } |
| 514 | } else { | 511 | } else { |
| 515 | field_val.toValue().writeToPackedMemory(field_ty, mod, code.items[current_pos..], bits) catch unreachable; | 512 | field_val.toValue().writeToPackedMemory(field_ty.toType(), mod, code.items[current_pos..], bits) catch unreachable; |
| 516 | } | 513 | } |
| 517 | bits += @as(u16, @intCast(field_ty.bitSize(mod))); | 514 | bits += @as(u16, @intCast(field_ty.toType().bitSize(mod))); |
| 518 | } | 515 | } |
| 519 | } else { | 516 | }, |
| 517 | .Auto, .Extern => { | ||
| 520 | const struct_begin = code.items.len; | 518 | const struct_begin = code.items.len; |
| 521 | const fields = struct_obj.fields.values(); | 519 | const field_types = struct_type.field_types.get(ip); |
| 522 | 520 | const offsets = struct_type.offsets.get(ip); | |
| 523 | var it = typed_value.ty.iterateStructOffsets(mod); | ||
| 524 | 521 | ||
| 525 | while (it.next()) |field_offset| { | 522 | var it = struct_type.iterateRuntimeOrder(ip); |
| 526 | const field_ty = fields[field_offset.field].ty; | 523 | while (it.next()) |field_index| { |
| 527 | 524 | const field_ty = field_types[field_index]; | |
| 528 | if (!field_ty.hasRuntimeBits(mod)) continue; | 525 | if (!field_ty.toType().hasRuntimeBits(mod)) continue; |
| 529 | 526 | ||
| 530 | const field_val = switch (ip.indexToKey(typed_value.val.toIntern()).aggregate.storage) { | 527 | const field_val = switch (ip.indexToKey(typed_value.val.toIntern()).aggregate.storage) { |
| 531 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ | 528 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ |
| 532 | .ty = field_ty.toIntern(), | 529 | .ty = field_ty, |
| 533 | .storage = .{ .u64 = bytes[field_offset.field] }, | 530 | .storage = .{ .u64 = bytes[field_index] }, |
| 534 | } }), | 531 | } }), |
| 535 | .elems => |elems| elems[field_offset.field], | 532 | .elems => |elems| elems[field_index], |
| 536 | .repeated_elem => |elem| elem, | 533 | .repeated_elem => |elem| elem, |
| 537 | }; | 534 | }; |
| 538 | 535 | ||
| 539 | const padding = math.cast(usize, field_offset.offset - (code.items.len - struct_begin)) orelse return error.Overflow; | 536 | const padding = math.cast( |
| 537 | usize, | ||
| 538 | offsets[field_index] - (code.items.len - struct_begin), | ||
| 539 | ) orelse return error.Overflow; | ||
| 540 | if (padding > 0) try code.appendNTimes(0, padding); | 540 | if (padding > 0) try code.appendNTimes(0, padding); |
| 541 | 541 | ||
| 542 | switch (try generateSymbol(bin_file, src_loc, .{ | 542 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 543 | .ty = field_ty, | 543 | .ty = field_ty.toType(), |
| 544 | .val = field_val.toValue(), | 544 | .val = field_val.toValue(), |
| 545 | }, code, debug_output, reloc_info)) { | 545 | }, code, debug_output, reloc_info)) { |
| 546 | .ok => {}, | 546 | .ok => {}, |
| ... | @@ -548,9 +548,16 @@ pub fn generateSymbol( | ... | @@ -548,9 +548,16 @@ pub fn generateSymbol( |
| 548 | } | 548 | } |
| 549 | } | 549 | } |
| 550 | 550 | ||
| 551 | const padding = math.cast(usize, std.mem.alignForward(u64, it.offset, @max(it.big_align, 1)) - (code.items.len - struct_begin)) orelse return error.Overflow; | 551 | const size = struct_type.size(ip).*; |
| 552 | const alignment = struct_type.flagsPtr(ip).alignment.toByteUnitsOptional().?; | ||
| 553 | |||
| 554 | const padding = math.cast( | ||
| 555 | usize, | ||
| 556 | std.mem.alignForward(u64, size, @max(alignment, 1)) - | ||
| 557 | (code.items.len - struct_begin), | ||
| 558 | ) orelse return error.Overflow; | ||
| 552 | if (padding > 0) try code.appendNTimes(0, padding); | 559 | if (padding > 0) try code.appendNTimes(0, padding); |
| 553 | } | 560 | }, |
| 554 | }, | 561 | }, |
| 555 | else => unreachable, | 562 | else => unreachable, |
| 556 | }, | 563 | }, |
| ... | @@ -565,7 +572,7 @@ pub fn generateSymbol( | ... | @@ -565,7 +572,7 @@ pub fn generateSymbol( |
| 565 | } | 572 | } |
| 566 | 573 | ||
| 567 | // Check if we should store the tag first. | 574 | // Check if we should store the tag first. |
| 568 | if (layout.tag_size > 0 and layout.tag_align >= layout.payload_align) { | 575 | if (layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align)) { |
| 569 | switch (try generateSymbol(bin_file, src_loc, .{ | 576 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 570 | .ty = typed_value.ty.unionTagType(mod).?, | 577 | .ty = typed_value.ty.unionTagType(mod).?, |
| 571 | .val = un.tag.toValue(), | 578 | .val = un.tag.toValue(), |
| ... | @@ -595,7 +602,7 @@ pub fn generateSymbol( | ... | @@ -595,7 +602,7 @@ pub fn generateSymbol( |
| 595 | } | 602 | } |
| 596 | } | 603 | } |
| 597 | 604 | ||
| 598 | if (layout.tag_size > 0 and layout.tag_align < layout.payload_align) { | 605 | if (layout.tag_size > 0 and layout.tag_align.compare(.lt, layout.payload_align)) { |
| 599 | switch (try generateSymbol(bin_file, src_loc, .{ | 606 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 600 | .ty = union_obj.enum_tag_ty.toType(), | 607 | .ty = union_obj.enum_tag_ty.toType(), |
| 601 | .val = un.tag.toValue(), | 608 | .val = un.tag.toValue(), |
| ... | @@ -695,10 +702,10 @@ fn lowerParentPtr( | ... | @@ -695,10 +702,10 @@ fn lowerParentPtr( |
| 695 | @intCast(field.index), | 702 | @intCast(field.index), |
| 696 | mod, | 703 | mod, |
| 697 | )), | 704 | )), |
| 698 | .Packed => if (mod.typeToStruct(base_type.toType())) |struct_obj| | 705 | .Packed => if (mod.typeToStruct(base_type.toType())) |struct_type| |
| 699 | math.divExact(u16, struct_obj.packedFieldBitOffset( | 706 | math.divExact(u16, mod.structPackedFieldBitOffset( |
| 700 | mod, | 707 | struct_type, |
| 701 | @intCast(field.index), | 708 | field.index, |
| 702 | ), 8) catch |err| switch (err) { | 709 | ), 8) catch |err| switch (err) { |
| 703 | error.UnexpectedRemainder => 0, | 710 | error.UnexpectedRemainder => 0, |
| 704 | error.DivisionByZero => unreachable, | 711 | error.DivisionByZero => unreachable, |
| ... | @@ -844,12 +851,12 @@ fn genDeclRef( | ... | @@ -844,12 +851,12 @@ fn genDeclRef( |
| 844 | // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`? | 851 | // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`? |
| 845 | if (tv.ty.castPtrToFn(mod)) |fn_ty| { | 852 | if (tv.ty.castPtrToFn(mod)) |fn_ty| { |
| 846 | if (mod.typeToFunc(fn_ty).?.is_generic) { | 853 | if (mod.typeToFunc(fn_ty).?.is_generic) { |
| 847 | return GenResult.mcv(.{ .immediate = fn_ty.abiAlignment(mod) }); | 854 | return GenResult.mcv(.{ .immediate = fn_ty.abiAlignment(mod).toByteUnitsOptional().? }); |
| 848 | } | 855 | } |
| 849 | } else if (tv.ty.zigTypeTag(mod) == .Pointer) { | 856 | } else if (tv.ty.zigTypeTag(mod) == .Pointer) { |
| 850 | const elem_ty = tv.ty.elemType2(mod); | 857 | const elem_ty = tv.ty.elemType2(mod); |
| 851 | if (!elem_ty.hasRuntimeBits(mod)) { | 858 | if (!elem_ty.hasRuntimeBits(mod)) { |
| 852 | return GenResult.mcv(.{ .immediate = elem_ty.abiAlignment(mod) }); | 859 | return GenResult.mcv(.{ .immediate = elem_ty.abiAlignment(mod).toByteUnitsOptional().? }); |
| 853 | } | 860 | } |
| 854 | } | 861 | } |
| 855 | 862 | ||
| ... | @@ -1036,10 +1043,10 @@ pub fn errUnionPayloadOffset(payload_ty: Type, mod: *Module) u64 { | ... | @@ -1036,10 +1043,10 @@ pub fn errUnionPayloadOffset(payload_ty: Type, mod: *Module) u64 { |
| 1036 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return 0; | 1043 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return 0; |
| 1037 | const payload_align = payload_ty.abiAlignment(mod); | 1044 | const payload_align = payload_ty.abiAlignment(mod); |
| 1038 | const error_align = Type.anyerror.abiAlignment(mod); | 1045 | const error_align = Type.anyerror.abiAlignment(mod); |
| 1039 | if (payload_align >= error_align or !payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | 1046 | if (payload_align.compare(.gte, error_align) or !payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 1040 | return 0; | 1047 | return 0; |
| 1041 | } else { | 1048 | } else { |
| 1042 | return mem.alignForward(u64, Type.anyerror.abiSize(mod), payload_align); | 1049 | return payload_align.forward(Type.anyerror.abiSize(mod)); |
| 1043 | } | 1050 | } |
| 1044 | } | 1051 | } |
| 1045 | 1052 | ||
| ... | @@ -1047,8 +1054,8 @@ pub fn errUnionErrorOffset(payload_ty: Type, mod: *Module) u64 { | ... | @@ -1047,8 +1054,8 @@ pub fn errUnionErrorOffset(payload_ty: Type, mod: *Module) u64 { |
| 1047 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return 0; | 1054 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return 0; |
| 1048 | const payload_align = payload_ty.abiAlignment(mod); | 1055 | const payload_align = payload_ty.abiAlignment(mod); |
| 1049 | const error_align = Type.anyerror.abiAlignment(mod); | 1056 | const error_align = Type.anyerror.abiAlignment(mod); |
| 1050 | if (payload_align >= error_align and payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | 1057 | if (payload_align.compare(.gte, error_align) and payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 1051 | return mem.alignForward(u64, payload_ty.abiSize(mod), error_align); | 1058 | return error_align.forward(payload_ty.abiSize(mod)); |
| 1052 | } else { | 1059 | } else { |
| 1053 | return 0; | 1060 | return 0; |
| 1054 | } | 1061 | } |
src/codegen/c.zig+130-134| ... | @@ -17,6 +17,7 @@ const LazySrcLoc = Module.LazySrcLoc; | ... | @@ -17,6 +17,7 @@ const LazySrcLoc = Module.LazySrcLoc; |
| 17 | const Air = @import("../Air.zig"); | 17 | const Air = @import("../Air.zig"); |
| 18 | const Liveness = @import("../Liveness.zig"); | 18 | const Liveness = @import("../Liveness.zig"); |
| 19 | const InternPool = @import("../InternPool.zig"); | 19 | const InternPool = @import("../InternPool.zig"); |
| 20 | const Alignment = InternPool.Alignment; | ||
| 20 | 21 | ||
| 21 | const BigIntLimb = std.math.big.Limb; | 22 | const BigIntLimb = std.math.big.Limb; |
| 22 | const BigInt = std.math.big.int; | 23 | const BigInt = std.math.big.int; |
| ... | @@ -292,7 +293,7 @@ pub const Function = struct { | ... | @@ -292,7 +293,7 @@ pub const Function = struct { |
| 292 | 293 | ||
| 293 | const result: CValue = if (lowersToArray(ty, mod)) result: { | 294 | const result: CValue = if (lowersToArray(ty, mod)) result: { |
| 294 | const writer = f.object.code_header.writer(); | 295 | const writer = f.object.code_header.writer(); |
| 295 | const alignment = 0; | 296 | const alignment: Alignment = .none; |
| 296 | const decl_c_value = try f.allocLocalValue(ty, alignment); | 297 | const decl_c_value = try f.allocLocalValue(ty, alignment); |
| 297 | const gpa = f.object.dg.gpa; | 298 | const gpa = f.object.dg.gpa; |
| 298 | try f.allocs.put(gpa, decl_c_value.new_local, false); | 299 | try f.allocs.put(gpa, decl_c_value.new_local, false); |
| ... | @@ -318,25 +319,25 @@ pub const Function = struct { | ... | @@ -318,25 +319,25 @@ pub const Function = struct { |
| 318 | /// Skips the reuse logic. This function should be used for any persistent allocation, i.e. | 319 | /// Skips the reuse logic. This function should be used for any persistent allocation, i.e. |
| 319 | /// those which go into `allocs`. This function does not add the resulting local into `allocs`; | 320 | /// those which go into `allocs`. This function does not add the resulting local into `allocs`; |
| 320 | /// that responsibility lies with the caller. | 321 | /// that responsibility lies with the caller. |
| 321 | fn allocLocalValue(f: *Function, ty: Type, alignment: u32) !CValue { | 322 | fn allocLocalValue(f: *Function, ty: Type, alignment: Alignment) !CValue { |
| 322 | const mod = f.object.dg.module; | 323 | const mod = f.object.dg.module; |
| 323 | const gpa = f.object.dg.gpa; | 324 | const gpa = f.object.dg.gpa; |
| 324 | try f.locals.append(gpa, .{ | 325 | try f.locals.append(gpa, .{ |
| 325 | .cty_idx = try f.typeToIndex(ty, .complete), | 326 | .cty_idx = try f.typeToIndex(ty, .complete), |
| 326 | .alignas = CType.AlignAs.init(alignment, ty.abiAlignment(mod)), | 327 | .alignas = CType.AlignAs.init(alignment, ty.abiAlignment(mod)), |
| 327 | }); | 328 | }); |
| 328 | return .{ .new_local = @as(LocalIndex, @intCast(f.locals.items.len - 1)) }; | 329 | return .{ .new_local = @intCast(f.locals.items.len - 1) }; |
| 329 | } | 330 | } |
| 330 | 331 | ||
| 331 | fn allocLocal(f: *Function, inst: Air.Inst.Index, ty: Type) !CValue { | 332 | fn allocLocal(f: *Function, inst: Air.Inst.Index, ty: Type) !CValue { |
| 332 | const result = try f.allocAlignedLocal(ty, .{}, 0); | 333 | const result = try f.allocAlignedLocal(ty, .{}, .none); |
| 333 | log.debug("%{d}: allocating t{d}", .{ inst, result.new_local }); | 334 | log.debug("%{d}: allocating t{d}", .{ inst, result.new_local }); |
| 334 | return result; | 335 | return result; |
| 335 | } | 336 | } |
| 336 | 337 | ||
| 337 | /// Only allocates the local; does not print anything. Will attempt to re-use locals, so should | 338 | /// Only allocates the local; does not print anything. Will attempt to re-use locals, so should |
| 338 | /// not be used for persistent locals (i.e. those in `allocs`). | 339 | /// not be used for persistent locals (i.e. those in `allocs`). |
| 339 | fn allocAlignedLocal(f: *Function, ty: Type, _: CQualifiers, alignment: u32) !CValue { | 340 | fn allocAlignedLocal(f: *Function, ty: Type, _: CQualifiers, alignment: Alignment) !CValue { |
| 340 | const mod = f.object.dg.module; | 341 | const mod = f.object.dg.module; |
| 341 | if (f.free_locals_map.getPtr(.{ | 342 | if (f.free_locals_map.getPtr(.{ |
| 342 | .cty_idx = try f.typeToIndex(ty, .complete), | 343 | .cty_idx = try f.typeToIndex(ty, .complete), |
| ... | @@ -1299,139 +1300,134 @@ pub const DeclGen = struct { | ... | @@ -1299,139 +1300,134 @@ pub const DeclGen = struct { |
| 1299 | } | 1300 | } |
| 1300 | try writer.writeByte('}'); | 1301 | try writer.writeByte('}'); |
| 1301 | }, | 1302 | }, |
| 1302 | .struct_type => |struct_type| { | 1303 | .struct_type => |struct_type| switch (struct_type.layout) { |
| 1303 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | 1304 | .Auto, .Extern => { |
| 1304 | switch (struct_obj.layout) { | 1305 | if (!location.isInitializer()) { |
| 1305 | .Auto, .Extern => { | 1306 | try writer.writeByte('('); |
| 1306 | if (!location.isInitializer()) { | 1307 | try dg.renderType(writer, ty); |
| 1308 | try writer.writeByte(')'); | ||
| 1309 | } | ||
| 1310 | |||
| 1311 | try writer.writeByte('{'); | ||
| 1312 | var empty = true; | ||
| 1313 | const field_types = struct_type.field_types.get(ip); | ||
| 1314 | for (struct_type.runtime_order.get(ip)) |runtime_order| { | ||
| 1315 | const field_i = runtime_order.toInt() orelse break; | ||
| 1316 | const field_ty = field_types[field_i]; | ||
| 1317 | |||
| 1318 | if (!empty) try writer.writeByte(','); | ||
| 1319 | const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) { | ||
| 1320 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ | ||
| 1321 | .ty = field_ty, | ||
| 1322 | .storage = .{ .u64 = bytes[field_i] }, | ||
| 1323 | } }), | ||
| 1324 | .elems => |elems| elems[field_i], | ||
| 1325 | .repeated_elem => |elem| elem, | ||
| 1326 | }; | ||
| 1327 | try dg.renderValue(writer, field_ty.toType(), field_val.toValue(), initializer_type); | ||
| 1328 | |||
| 1329 | empty = false; | ||
| 1330 | } | ||
| 1331 | try writer.writeByte('}'); | ||
| 1332 | }, | ||
| 1333 | .Packed => { | ||
| 1334 | const int_info = ty.intInfo(mod); | ||
| 1335 | |||
| 1336 | const bits = Type.smallestUnsignedBits(int_info.bits - 1); | ||
| 1337 | const bit_offset_ty = try mod.intType(.unsigned, bits); | ||
| 1338 | const field_types = struct_type.field_types.get(ip); | ||
| 1339 | |||
| 1340 | var bit_offset: u64 = 0; | ||
| 1341 | var eff_num_fields: usize = 0; | ||
| 1342 | |||
| 1343 | for (field_types) |field_ty| { | ||
| 1344 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; | ||
| 1345 | eff_num_fields += 1; | ||
| 1346 | } | ||
| 1347 | |||
| 1348 | if (eff_num_fields == 0) { | ||
| 1349 | try writer.writeByte('('); | ||
| 1350 | try dg.renderValue(writer, ty, Value.undef, initializer_type); | ||
| 1351 | try writer.writeByte(')'); | ||
| 1352 | } else if (ty.bitSize(mod) > 64) { | ||
| 1353 | // zig_or_u128(zig_or_u128(zig_shl_u128(a, a_off), zig_shl_u128(b, b_off)), zig_shl_u128(c, c_off)) | ||
| 1354 | var num_or = eff_num_fields - 1; | ||
| 1355 | while (num_or > 0) : (num_or -= 1) { | ||
| 1356 | try writer.writeAll("zig_or_"); | ||
| 1357 | try dg.renderTypeForBuiltinFnName(writer, ty); | ||
| 1307 | try writer.writeByte('('); | 1358 | try writer.writeByte('('); |
| 1308 | try dg.renderType(writer, ty); | ||
| 1309 | try writer.writeByte(')'); | ||
| 1310 | } | 1359 | } |
| 1311 | 1360 | ||
| 1312 | try writer.writeByte('{'); | 1361 | var eff_index: usize = 0; |
| 1313 | var empty = true; | 1362 | var needs_closing_paren = false; |
| 1314 | for (struct_obj.fields.values(), 0..) |field, field_i| { | 1363 | for (field_types, 0..) |field_ty, field_i| { |
| 1315 | if (field.is_comptime) continue; | 1364 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 1316 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | ||
| 1317 | 1365 | ||
| 1318 | if (!empty) try writer.writeByte(','); | ||
| 1319 | const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) { | 1366 | const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) { |
| 1320 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ | 1367 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ |
| 1321 | .ty = field.ty.toIntern(), | 1368 | .ty = field_ty, |
| 1322 | .storage = .{ .u64 = bytes[field_i] }, | 1369 | .storage = .{ .u64 = bytes[field_i] }, |
| 1323 | } }), | 1370 | } }), |
| 1324 | .elems => |elems| elems[field_i], | 1371 | .elems => |elems| elems[field_i], |
| 1325 | .repeated_elem => |elem| elem, | 1372 | .repeated_elem => |elem| elem, |
| 1326 | }; | 1373 | }; |
| 1327 | try dg.renderValue(writer, field.ty, field_val.toValue(), initializer_type); | 1374 | const cast_context = IntCastContext{ .value = .{ .value = field_val.toValue() } }; |
| 1328 | 1375 | if (bit_offset != 0) { | |
| 1329 | empty = false; | 1376 | try writer.writeAll("zig_shl_"); |
| 1330 | } | 1377 | try dg.renderTypeForBuiltinFnName(writer, ty); |
| 1331 | try writer.writeByte('}'); | 1378 | try writer.writeByte('('); |
| 1332 | }, | 1379 | try dg.renderIntCast(writer, ty, cast_context, field_ty.toType(), .FunctionArgument); |
| 1333 | .Packed => { | 1380 | try writer.writeAll(", "); |
| 1334 | const int_info = ty.intInfo(mod); | 1381 | const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset); |
| 1335 | 1382 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | |
| 1336 | const bits = Type.smallestUnsignedBits(int_info.bits - 1); | 1383 | try writer.writeByte(')'); |
| 1337 | const bit_offset_ty = try mod.intType(.unsigned, bits); | 1384 | } else { |
| 1338 | 1385 | try dg.renderIntCast(writer, ty, cast_context, field_ty.toType(), .FunctionArgument); | |
| 1339 | var bit_offset: u64 = 0; | 1386 | } |
| 1340 | var eff_num_fields: usize = 0; | ||
| 1341 | 1387 | ||
| 1342 | for (struct_obj.fields.values()) |field| { | 1388 | if (needs_closing_paren) try writer.writeByte(')'); |
| 1343 | if (field.is_comptime) continue; | 1389 | if (eff_index != eff_num_fields - 1) try writer.writeAll(", "); |
| 1344 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | ||
| 1345 | 1390 | ||
| 1346 | eff_num_fields += 1; | 1391 | bit_offset += field_ty.toType().bitSize(mod); |
| 1392 | needs_closing_paren = true; | ||
| 1393 | eff_index += 1; | ||
| 1347 | } | 1394 | } |
| 1395 | } else { | ||
| 1396 | try writer.writeByte('('); | ||
| 1397 | // a << a_off | b << b_off | c << c_off | ||
| 1398 | var empty = true; | ||
| 1399 | for (field_types, 0..) |field_ty, field_i| { | ||
| 1400 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; | ||
| 1348 | 1401 | ||
| 1349 | if (eff_num_fields == 0) { | 1402 | if (!empty) try writer.writeAll(" | "); |
| 1350 | try writer.writeByte('('); | 1403 | try writer.writeByte('('); |
| 1351 | try dg.renderValue(writer, ty, Value.undef, initializer_type); | 1404 | try dg.renderType(writer, ty); |
| 1352 | try writer.writeByte(')'); | 1405 | try writer.writeByte(')'); |
| 1353 | } else if (ty.bitSize(mod) > 64) { | ||
| 1354 | // zig_or_u128(zig_or_u128(zig_shl_u128(a, a_off), zig_shl_u128(b, b_off)), zig_shl_u128(c, c_off)) | ||
| 1355 | var num_or = eff_num_fields - 1; | ||
| 1356 | while (num_or > 0) : (num_or -= 1) { | ||
| 1357 | try writer.writeAll("zig_or_"); | ||
| 1358 | try dg.renderTypeForBuiltinFnName(writer, ty); | ||
| 1359 | try writer.writeByte('('); | ||
| 1360 | } | ||
| 1361 | 1406 | ||
| 1362 | var eff_index: usize = 0; | 1407 | const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) { |
| 1363 | var needs_closing_paren = false; | 1408 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ |
| 1364 | for (struct_obj.fields.values(), 0..) |field, field_i| { | 1409 | .ty = field_ty, |
| 1365 | if (field.is_comptime) continue; | 1410 | .storage = .{ .u64 = bytes[field_i] }, |
| 1366 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | 1411 | } }), |
| 1367 | 1412 | .elems => |elems| elems[field_i], | |
| 1368 | const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) { | 1413 | .repeated_elem => |elem| elem, |
| 1369 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ | 1414 | }; |
| 1370 | .ty = field.ty.toIntern(), | ||
| 1371 | .storage = .{ .u64 = bytes[field_i] }, | ||
| 1372 | } }), | ||
| 1373 | .elems => |elems| elems[field_i], | ||
| 1374 | .repeated_elem => |elem| elem, | ||
| 1375 | }; | ||
| 1376 | const cast_context = IntCastContext{ .value = .{ .value = field_val.toValue() } }; | ||
| 1377 | if (bit_offset != 0) { | ||
| 1378 | try writer.writeAll("zig_shl_"); | ||
| 1379 | try dg.renderTypeForBuiltinFnName(writer, ty); | ||
| 1380 | try writer.writeByte('('); | ||
| 1381 | try dg.renderIntCast(writer, ty, cast_context, field.ty, .FunctionArgument); | ||
| 1382 | try writer.writeAll(", "); | ||
| 1383 | const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset); | ||
| 1384 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | ||
| 1385 | try writer.writeByte(')'); | ||
| 1386 | } else { | ||
| 1387 | try dg.renderIntCast(writer, ty, cast_context, field.ty, .FunctionArgument); | ||
| 1388 | } | ||
| 1389 | |||
| 1390 | if (needs_closing_paren) try writer.writeByte(')'); | ||
| 1391 | if (eff_index != eff_num_fields - 1) try writer.writeAll(", "); | ||
| 1392 | |||
| 1393 | bit_offset += field.ty.bitSize(mod); | ||
| 1394 | needs_closing_paren = true; | ||
| 1395 | eff_index += 1; | ||
| 1396 | } | ||
| 1397 | } else { | ||
| 1398 | try writer.writeByte('('); | ||
| 1399 | // a << a_off | b << b_off | c << c_off | ||
| 1400 | var empty = true; | ||
| 1401 | for (struct_obj.fields.values(), 0..) |field, field_i| { | ||
| 1402 | if (field.is_comptime) continue; | ||
| 1403 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | ||
| 1404 | |||
| 1405 | if (!empty) try writer.writeAll(" | "); | ||
| 1406 | try writer.writeByte('('); | ||
| 1407 | try dg.renderType(writer, ty); | ||
| 1408 | try writer.writeByte(')'); | ||
| 1409 | 1415 | ||
| 1410 | const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) { | 1416 | if (bit_offset != 0) { |
| 1411 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ | 1417 | try dg.renderValue(writer, field_ty.toType(), field_val.toValue(), .Other); |
| 1412 | .ty = field.ty.toIntern(), | 1418 | try writer.writeAll(" << "); |
| 1413 | .storage = .{ .u64 = bytes[field_i] }, | 1419 | const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset); |
| 1414 | } }), | 1420 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); |
| 1415 | .elems => |elems| elems[field_i], | 1421 | } else { |
| 1416 | .repeated_elem => |elem| elem, | 1422 | try dg.renderValue(writer, field_ty.toType(), field_val.toValue(), .Other); |
| 1417 | }; | ||
| 1418 | |||
| 1419 | if (bit_offset != 0) { | ||
| 1420 | try dg.renderValue(writer, field.ty, field_val.toValue(), .Other); | ||
| 1421 | try writer.writeAll(" << "); | ||
| 1422 | const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset); | ||
| 1423 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | ||
| 1424 | } else { | ||
| 1425 | try dg.renderValue(writer, field.ty, field_val.toValue(), .Other); | ||
| 1426 | } | ||
| 1427 | |||
| 1428 | bit_offset += field.ty.bitSize(mod); | ||
| 1429 | empty = false; | ||
| 1430 | } | 1423 | } |
| 1431 | try writer.writeByte(')'); | 1424 | |
| 1425 | bit_offset += field_ty.toType().bitSize(mod); | ||
| 1426 | empty = false; | ||
| 1432 | } | 1427 | } |
| 1433 | }, | 1428 | try writer.writeByte(')'); |
| 1434 | } | 1429 | } |
| 1430 | }, | ||
| 1435 | }, | 1431 | }, |
| 1436 | else => unreachable, | 1432 | else => unreachable, |
| 1437 | }, | 1433 | }, |
| ... | @@ -1723,7 +1719,7 @@ pub const DeclGen = struct { | ... | @@ -1723,7 +1719,7 @@ pub const DeclGen = struct { |
| 1723 | ty: Type, | 1719 | ty: Type, |
| 1724 | name: CValue, | 1720 | name: CValue, |
| 1725 | qualifiers: CQualifiers, | 1721 | qualifiers: CQualifiers, |
| 1726 | alignment: u64, | 1722 | alignment: Alignment, |
| 1727 | kind: CType.Kind, | 1723 | kind: CType.Kind, |
| 1728 | ) error{ OutOfMemory, AnalysisFail }!void { | 1724 | ) error{ OutOfMemory, AnalysisFail }!void { |
| 1729 | const mod = dg.module; | 1725 | const mod = dg.module; |
| ... | @@ -1854,7 +1850,7 @@ pub const DeclGen = struct { | ... | @@ -1854,7 +1850,7 @@ pub const DeclGen = struct { |
| 1854 | decl.ty, | 1850 | decl.ty, |
| 1855 | .{ .decl = decl_index }, | 1851 | .{ .decl = decl_index }, |
| 1856 | CQualifiers.init(.{ .@"const" = variable.is_const }), | 1852 | CQualifiers.init(.{ .@"const" = variable.is_const }), |
| 1857 | @as(u32, @intCast(decl.alignment.toByteUnits(0))), | 1853 | decl.alignment, |
| 1858 | .complete, | 1854 | .complete, |
| 1859 | ); | 1855 | ); |
| 1860 | try fwd_decl_writer.writeAll(";\n"); | 1856 | try fwd_decl_writer.writeAll(";\n"); |
| ... | @@ -2460,7 +2456,7 @@ pub fn genErrDecls(o: *Object) !void { | ... | @@ -2460,7 +2456,7 @@ pub fn genErrDecls(o: *Object) !void { |
| 2460 | } }); | 2456 | } }); |
| 2461 | 2457 | ||
| 2462 | try writer.writeAll("static "); | 2458 | try writer.writeAll("static "); |
| 2463 | try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, Const, 0, .complete); | 2459 | try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, Const, .none, .complete); |
| 2464 | try writer.writeAll(" = "); | 2460 | try writer.writeAll(" = "); |
| 2465 | try o.dg.renderValue(writer, name_ty, name_val.toValue(), .StaticInitializer); | 2461 | try o.dg.renderValue(writer, name_ty, name_val.toValue(), .StaticInitializer); |
| 2466 | try writer.writeAll(";\n"); | 2462 | try writer.writeAll(";\n"); |
| ... | @@ -2472,7 +2468,7 @@ pub fn genErrDecls(o: *Object) !void { | ... | @@ -2472,7 +2468,7 @@ pub fn genErrDecls(o: *Object) !void { |
| 2472 | }); | 2468 | }); |
| 2473 | 2469 | ||
| 2474 | try writer.writeAll("static "); | 2470 | try writer.writeAll("static "); |
| 2475 | try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = array_identifier }, Const, 0, .complete); | 2471 | try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = array_identifier }, Const, .none, .complete); |
| 2476 | try writer.writeAll(" = {"); | 2472 | try writer.writeAll(" = {"); |
| 2477 | for (mod.global_error_set.keys(), 0..) |name_nts, value| { | 2473 | for (mod.global_error_set.keys(), 0..) |name_nts, value| { |
| 2478 | const name = mod.intern_pool.stringToSlice(name_nts); | 2474 | const name = mod.intern_pool.stringToSlice(name_nts); |
| ... | @@ -2523,7 +2519,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { | ... | @@ -2523,7 +2519,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { |
| 2523 | try w.writeByte(' '); | 2519 | try w.writeByte(' '); |
| 2524 | try w.writeAll(fn_name); | 2520 | try w.writeAll(fn_name); |
| 2525 | try w.writeByte('('); | 2521 | try w.writeByte('('); |
| 2526 | try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, 0, .complete); | 2522 | try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, .none, .complete); |
| 2527 | try w.writeAll(") {\n switch (tag) {\n"); | 2523 | try w.writeAll(") {\n switch (tag) {\n"); |
| 2528 | for (enum_ty.enumFields(mod), 0..) |name_ip, index_usize| { | 2524 | for (enum_ty.enumFields(mod), 0..) |name_ip, index_usize| { |
| 2529 | const index = @as(u32, @intCast(index_usize)); | 2525 | const index = @as(u32, @intCast(index_usize)); |
| ... | @@ -2546,7 +2542,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { | ... | @@ -2546,7 +2542,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { |
| 2546 | try w.print(" case {}: {{\n static ", .{ | 2542 | try w.print(" case {}: {{\n static ", .{ |
| 2547 | try o.dg.fmtIntLiteral(enum_ty, int_val, .Other), | 2543 | try o.dg.fmtIntLiteral(enum_ty, int_val, .Other), |
| 2548 | }); | 2544 | }); |
| 2549 | try o.dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, Const, 0, .complete); | 2545 | try o.dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, Const, .none, .complete); |
| 2550 | try w.writeAll(" = "); | 2546 | try w.writeAll(" = "); |
| 2551 | try o.dg.renderValue(w, name_ty, name_val.toValue(), .Initializer); | 2547 | try o.dg.renderValue(w, name_ty, name_val.toValue(), .Initializer); |
| 2552 | try w.writeAll(";\n return ("); | 2548 | try w.writeAll(";\n return ("); |
| ... | @@ -2706,7 +2702,7 @@ pub fn genDecl(o: *Object) !void { | ... | @@ -2706,7 +2702,7 @@ pub fn genDecl(o: *Object) !void { |
| 2706 | if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage "); | 2702 | if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage "); |
| 2707 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| | 2703 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| |
| 2708 | try w.print("zig_linksection(\"{s}\", ", .{s}); | 2704 | try w.print("zig_linksection(\"{s}\", ", .{s}); |
| 2709 | try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .{}, decl.alignment.toByteUnits(0), .complete); | 2705 | try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .{}, decl.alignment, .complete); |
| 2710 | if (decl.@"linksection" != .none) try w.writeAll(", read, write)"); | 2706 | if (decl.@"linksection" != .none) try w.writeAll(", read, write)"); |
| 2711 | try w.writeAll(" = "); | 2707 | try w.writeAll(" = "); |
| 2712 | try o.dg.renderValue(w, tv.ty, variable.init.toValue(), .StaticInitializer); | 2708 | try o.dg.renderValue(w, tv.ty, variable.init.toValue(), .StaticInitializer); |
| ... | @@ -2717,14 +2713,14 @@ pub fn genDecl(o: *Object) !void { | ... | @@ -2717,14 +2713,14 @@ pub fn genDecl(o: *Object) !void { |
| 2717 | const fwd_decl_writer = o.dg.fwd_decl.writer(); | 2713 | const fwd_decl_writer = o.dg.fwd_decl.writer(); |
| 2718 | 2714 | ||
| 2719 | try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static "); | 2715 | try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static "); |
| 2720 | try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, Const, decl.alignment.toByteUnits(0), .complete); | 2716 | try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, Const, decl.alignment, .complete); |
| 2721 | try fwd_decl_writer.writeAll(";\n"); | 2717 | try fwd_decl_writer.writeAll(";\n"); |
| 2722 | 2718 | ||
| 2723 | const w = o.writer(); | 2719 | const w = o.writer(); |
| 2724 | if (!is_global) try w.writeAll("static "); | 2720 | if (!is_global) try w.writeAll("static "); |
| 2725 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| | 2721 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| |
| 2726 | try w.print("zig_linksection(\"{s}\", ", .{s}); | 2722 | try w.print("zig_linksection(\"{s}\", ", .{s}); |
| 2727 | try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, Const, decl.alignment.toByteUnits(0), .complete); | 2723 | try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, Const, decl.alignment, .complete); |
| 2728 | if (decl.@"linksection" != .none) try w.writeAll(", read)"); | 2724 | if (decl.@"linksection" != .none) try w.writeAll(", read)"); |
| 2729 | try w.writeAll(" = "); | 2725 | try w.writeAll(" = "); |
| 2730 | try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer); | 2726 | try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer); |
| ... | @@ -3353,8 +3349,8 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3353,8 +3349,8 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3353 | 3349 | ||
| 3354 | try reap(f, inst, &.{ty_op.operand}); | 3350 | try reap(f, inst, &.{ty_op.operand}); |
| 3355 | 3351 | ||
| 3356 | const is_aligned = if (ptr_info.flags.alignment.toByteUnitsOptional()) |alignment| | 3352 | const is_aligned = if (ptr_info.flags.alignment != .none) |
| 3357 | alignment >= src_ty.abiAlignment(mod) | 3353 | ptr_info.flags.alignment.compare(.gte, src_ty.abiAlignment(mod)) |
| 3358 | else | 3354 | else |
| 3359 | true; | 3355 | true; |
| 3360 | const is_array = lowersToArray(src_ty, mod); | 3356 | const is_array = lowersToArray(src_ty, mod); |
| ... | @@ -3625,8 +3621,8 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { | ... | @@ -3625,8 +3621,8 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 3625 | return .none; | 3621 | return .none; |
| 3626 | } | 3622 | } |
| 3627 | 3623 | ||
| 3628 | const is_aligned = if (ptr_info.flags.alignment.toByteUnitsOptional()) |alignment| | 3624 | const is_aligned = if (ptr_info.flags.alignment != .none) |
| 3629 | alignment >= src_ty.abiAlignment(mod) | 3625 | ptr_info.flags.alignment.compare(.gte, src_ty.abiAlignment(mod)) |
| 3630 | else | 3626 | else |
| 3631 | true; | 3627 | true; |
| 3632 | const is_array = lowersToArray(ptr_info.child.toType(), mod); | 3628 | const is_array = lowersToArray(ptr_info.child.toType(), mod); |
| ... | @@ -4847,7 +4843,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4847,7 +4843,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4847 | if (is_reg) { | 4843 | if (is_reg) { |
| 4848 | const output_ty = if (output == .none) inst_ty else f.typeOf(output).childType(mod); | 4844 | const output_ty = if (output == .none) inst_ty else f.typeOf(output).childType(mod); |
| 4849 | try writer.writeAll("register "); | 4845 | try writer.writeAll("register "); |
| 4850 | const alignment = 0; | 4846 | const alignment: Alignment = .none; |
| 4851 | const local_value = try f.allocLocalValue(output_ty, alignment); | 4847 | const local_value = try f.allocLocalValue(output_ty, alignment); |
| 4852 | try f.allocs.put(gpa, local_value.new_local, false); | 4848 | try f.allocs.put(gpa, local_value.new_local, false); |
| 4853 | try f.object.dg.renderTypeAndName(writer, output_ty, local_value, .{}, alignment, .complete); | 4849 | try f.object.dg.renderTypeAndName(writer, output_ty, local_value, .{}, alignment, .complete); |
| ... | @@ -4880,7 +4876,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4880,7 +4876,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4880 | if (asmInputNeedsLocal(f, constraint, input_val)) { | 4876 | if (asmInputNeedsLocal(f, constraint, input_val)) { |
| 4881 | const input_ty = f.typeOf(input); | 4877 | const input_ty = f.typeOf(input); |
| 4882 | if (is_reg) try writer.writeAll("register "); | 4878 | if (is_reg) try writer.writeAll("register "); |
| 4883 | const alignment = 0; | 4879 | const alignment: Alignment = .none; |
| 4884 | const local_value = try f.allocLocalValue(input_ty, alignment); | 4880 | const local_value = try f.allocLocalValue(input_ty, alignment); |
| 4885 | try f.allocs.put(gpa, local_value.new_local, false); | 4881 | try f.allocs.put(gpa, local_value.new_local, false); |
| 4886 | try f.object.dg.renderTypeAndName(writer, input_ty, local_value, Const, alignment, .complete); | 4882 | try f.object.dg.renderTypeAndName(writer, input_ty, local_value, Const, alignment, .complete); |
| ... | @@ -5427,12 +5423,12 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5427,12 +5423,12 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5427 | else | 5423 | else |
| 5428 | .{ .identifier = ip.stringToSlice(struct_ty.structFieldName(extra.field_index, mod)) }, | 5424 | .{ .identifier = ip.stringToSlice(struct_ty.structFieldName(extra.field_index, mod)) }, |
| 5429 | .Packed => { | 5425 | .Packed => { |
| 5430 | const struct_obj = mod.typeToStruct(struct_ty).?; | 5426 | const struct_type = mod.typeToStruct(struct_ty).?; |
| 5431 | const int_info = struct_ty.intInfo(mod); | 5427 | const int_info = struct_ty.intInfo(mod); |
| 5432 | 5428 | ||
| 5433 | const bit_offset_ty = try mod.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1)); | 5429 | const bit_offset_ty = try mod.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1)); |
| 5434 | 5430 | ||
| 5435 | const bit_offset = struct_obj.packedFieldBitOffset(mod, extra.field_index); | 5431 | const bit_offset = mod.structPackedFieldBitOffset(struct_type, extra.field_index); |
| 5436 | const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset); | 5432 | const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset); |
| 5437 | 5433 | ||
| 5438 | const field_int_signedness = if (inst_ty.isAbiInt(mod)) | 5434 | const field_int_signedness = if (inst_ty.isAbiInt(mod)) |
src/codegen/c/type.zig+15-9| ... | @@ -283,14 +283,20 @@ pub const CType = extern union { | ... | @@ -283,14 +283,20 @@ pub const CType = extern union { |
| 283 | @"align": Alignment, | 283 | @"align": Alignment, |
| 284 | abi: Alignment, | 284 | abi: Alignment, |
| 285 | 285 | ||
| 286 | pub fn init(alignment: u64, abi_alignment: u32) AlignAs { | 286 | pub fn init(@"align": Alignment, abi_align: Alignment) AlignAs { |
| 287 | const @"align" = Alignment.fromByteUnits(alignment); | 287 | assert(abi_align != .none); |
| 288 | const abi_align = Alignment.fromNonzeroByteUnits(abi_alignment); | ||
| 289 | return .{ | 288 | return .{ |
| 290 | .@"align" = if (@"align" != .none) @"align" else abi_align, | 289 | .@"align" = if (@"align" != .none) @"align" else abi_align, |
| 291 | .abi = abi_align, | 290 | .abi = abi_align, |
| 292 | }; | 291 | }; |
| 293 | } | 292 | } |
| 293 | |||
| 294 | pub fn initByteUnits(alignment: u64, abi_alignment: u32) AlignAs { | ||
| 295 | return init( | ||
| 296 | Alignment.fromByteUnits(alignment), | ||
| 297 | Alignment.fromNonzeroByteUnits(abi_alignment), | ||
| 298 | ); | ||
| 299 | } | ||
| 294 | pub fn abiAlign(ty: Type, mod: *Module) AlignAs { | 300 | pub fn abiAlign(ty: Type, mod: *Module) AlignAs { |
| 295 | const abi_align = ty.abiAlignment(mod); | 301 | const abi_align = ty.abiAlignment(mod); |
| 296 | return init(abi_align, abi_align); | 302 | return init(abi_align, abi_align); |
| ... | @@ -1360,6 +1366,7 @@ pub const CType = extern union { | ... | @@ -1360,6 +1366,7 @@ pub const CType = extern union { |
| 1360 | 1366 | ||
| 1361 | pub fn initType(self: *@This(), ty: Type, kind: Kind, lookup: Lookup) !void { | 1367 | pub fn initType(self: *@This(), ty: Type, kind: Kind, lookup: Lookup) !void { |
| 1362 | const mod = lookup.getModule(); | 1368 | const mod = lookup.getModule(); |
| 1369 | const ip = &mod.intern_pool; | ||
| 1363 | 1370 | ||
| 1364 | self.* = undefined; | 1371 | self.* = undefined; |
| 1365 | if (!ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) | 1372 | if (!ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) |
| ... | @@ -1382,12 +1389,12 @@ pub const CType = extern union { | ... | @@ -1382,12 +1389,12 @@ pub const CType = extern union { |
| 1382 | .array => switch (kind) { | 1389 | .array => switch (kind) { |
| 1383 | .forward, .complete, .global => { | 1390 | .forward, .complete, .global => { |
| 1384 | const abi_size = ty.abiSize(mod); | 1391 | const abi_size = ty.abiSize(mod); |
| 1385 | const abi_align = ty.abiAlignment(mod); | 1392 | const abi_align = ty.abiAlignment(mod).toByteUnits(0); |
| 1386 | self.storage = .{ .seq = .{ .base = .{ .tag = .array }, .data = .{ | 1393 | self.storage = .{ .seq = .{ .base = .{ .tag = .array }, .data = .{ |
| 1387 | .len = @divExact(abi_size, abi_align), | 1394 | .len = @divExact(abi_size, abi_align), |
| 1388 | .elem_type = tagFromIntInfo(.{ | 1395 | .elem_type = tagFromIntInfo(.{ |
| 1389 | .signedness = .unsigned, | 1396 | .signedness = .unsigned, |
| 1390 | .bits = @as(u16, @intCast(abi_align * 8)), | 1397 | .bits = @intCast(abi_align * 8), |
| 1391 | }).toIndex(), | 1398 | }).toIndex(), |
| 1392 | } } }; | 1399 | } } }; |
| 1393 | self.value = .{ .cty = initPayload(&self.storage.seq) }; | 1400 | self.value = .{ .cty = initPayload(&self.storage.seq) }; |
| ... | @@ -1488,10 +1495,10 @@ pub const CType = extern union { | ... | @@ -1488,10 +1495,10 @@ pub const CType = extern union { |
| 1488 | }, | 1495 | }, |
| 1489 | 1496 | ||
| 1490 | .Struct, .Union => |zig_ty_tag| if (ty.containerLayout(mod) == .Packed) { | 1497 | .Struct, .Union => |zig_ty_tag| if (ty.containerLayout(mod) == .Packed) { |
| 1491 | if (mod.typeToStruct(ty)) |struct_obj| { | 1498 | if (mod.typeToPackedStruct(ty)) |packed_struct| { |
| 1492 | try self.initType(struct_obj.backing_int_ty, kind, lookup); | 1499 | try self.initType(packed_struct.backingIntType(ip).toType(), kind, lookup); |
| 1493 | } else { | 1500 | } else { |
| 1494 | const bits = @as(u16, @intCast(ty.bitSize(mod))); | 1501 | const bits: u16 = @intCast(ty.bitSize(mod)); |
| 1495 | const int_ty = try mod.intType(.unsigned, bits); | 1502 | const int_ty = try mod.intType(.unsigned, bits); |
| 1496 | try self.initType(int_ty, kind, lookup); | 1503 | try self.initType(int_ty, kind, lookup); |
| 1497 | } | 1504 | } |
| ... | @@ -1722,7 +1729,6 @@ pub const CType = extern union { | ... | @@ -1722,7 +1729,6 @@ pub const CType = extern union { |
| 1722 | 1729 | ||
| 1723 | .Fn => { | 1730 | .Fn => { |
| 1724 | const info = mod.typeToFunc(ty).?; | 1731 | const info = mod.typeToFunc(ty).?; |
| 1725 | const ip = &mod.intern_pool; | ||
| 1726 | if (!info.is_generic) { | 1732 | if (!info.is_generic) { |
| 1727 | if (lookup.isMutable()) { | 1733 | if (lookup.isMutable()) { |
| 1728 | const param_kind: Kind = switch (kind) { | 1734 | const param_kind: Kind = switch (kind) { |
src/codegen/llvm.zig+300-289| ... | @@ -1076,7 +1076,7 @@ pub const Object = struct { | ... | @@ -1076,7 +1076,7 @@ pub const Object = struct { |
| 1076 | table_variable_index.setMutability(.constant, &o.builder); | 1076 | table_variable_index.setMutability(.constant, &o.builder); |
| 1077 | table_variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); | 1077 | table_variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); |
| 1078 | table_variable_index.setAlignment( | 1078 | table_variable_index.setAlignment( |
| 1079 | Builder.Alignment.fromByteUnits(slice_ty.abiAlignment(mod)), | 1079 | slice_ty.abiAlignment(mod).toLlvm(), |
| 1080 | &o.builder, | 1080 | &o.builder, |
| 1081 | ); | 1081 | ); |
| 1082 | 1082 | ||
| ... | @@ -1318,8 +1318,9 @@ pub const Object = struct { | ... | @@ -1318,8 +1318,9 @@ pub const Object = struct { |
| 1318 | _ = try attributes.removeFnAttr(.@"noinline"); | 1318 | _ = try attributes.removeFnAttr(.@"noinline"); |
| 1319 | } | 1319 | } |
| 1320 | 1320 | ||
| 1321 | if (func.analysis(ip).stack_alignment.toByteUnitsOptional()) |alignment| { | 1321 | const stack_alignment = func.analysis(ip).stack_alignment; |
| 1322 | try attributes.addFnAttr(.{ .alignstack = Builder.Alignment.fromByteUnits(alignment) }, &o.builder); | 1322 | if (stack_alignment != .none) { |
| 1323 | try attributes.addFnAttr(.{ .alignstack = stack_alignment.toLlvm() }, &o.builder); | ||
| 1323 | try attributes.addFnAttr(.@"noinline", &o.builder); | 1324 | try attributes.addFnAttr(.@"noinline", &o.builder); |
| 1324 | } else { | 1325 | } else { |
| 1325 | _ = try attributes.removeFnAttr(.alignstack); | 1326 | _ = try attributes.removeFnAttr(.alignstack); |
| ... | @@ -1407,7 +1408,7 @@ pub const Object = struct { | ... | @@ -1407,7 +1408,7 @@ pub const Object = struct { |
| 1407 | const param = wip.arg(llvm_arg_i); | 1408 | const param = wip.arg(llvm_arg_i); |
| 1408 | 1409 | ||
| 1409 | if (isByRef(param_ty, mod)) { | 1410 | if (isByRef(param_ty, mod)) { |
| 1410 | const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod)); | 1411 | const alignment = param_ty.abiAlignment(mod).toLlvm(); |
| 1411 | const param_llvm_ty = param.typeOfWip(&wip); | 1412 | const param_llvm_ty = param.typeOfWip(&wip); |
| 1412 | const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target); | 1413 | const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target); |
| 1413 | _ = try wip.store(.normal, param, arg_ptr, alignment); | 1414 | _ = try wip.store(.normal, param, arg_ptr, alignment); |
| ... | @@ -1423,7 +1424,7 @@ pub const Object = struct { | ... | @@ -1423,7 +1424,7 @@ pub const Object = struct { |
| 1423 | const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType(); | 1424 | const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType(); |
| 1424 | const param_llvm_ty = try o.lowerType(param_ty); | 1425 | const param_llvm_ty = try o.lowerType(param_ty); |
| 1425 | const param = wip.arg(llvm_arg_i); | 1426 | const param = wip.arg(llvm_arg_i); |
| 1426 | const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod)); | 1427 | const alignment = param_ty.abiAlignment(mod).toLlvm(); |
| 1427 | 1428 | ||
| 1428 | try o.addByRefParamAttrs(&attributes, llvm_arg_i, alignment, it.byval_attr, param_llvm_ty); | 1429 | try o.addByRefParamAttrs(&attributes, llvm_arg_i, alignment, it.byval_attr, param_llvm_ty); |
| 1429 | llvm_arg_i += 1; | 1430 | llvm_arg_i += 1; |
| ... | @@ -1438,7 +1439,7 @@ pub const Object = struct { | ... | @@ -1438,7 +1439,7 @@ pub const Object = struct { |
| 1438 | const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType(); | 1439 | const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType(); |
| 1439 | const param_llvm_ty = try o.lowerType(param_ty); | 1440 | const param_llvm_ty = try o.lowerType(param_ty); |
| 1440 | const param = wip.arg(llvm_arg_i); | 1441 | const param = wip.arg(llvm_arg_i); |
| 1441 | const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod)); | 1442 | const alignment = param_ty.abiAlignment(mod).toLlvm(); |
| 1442 | 1443 | ||
| 1443 | try attributes.addParamAttr(llvm_arg_i, .noundef, &o.builder); | 1444 | try attributes.addParamAttr(llvm_arg_i, .noundef, &o.builder); |
| 1444 | llvm_arg_i += 1; | 1445 | llvm_arg_i += 1; |
| ... | @@ -1456,7 +1457,7 @@ pub const Object = struct { | ... | @@ -1456,7 +1457,7 @@ pub const Object = struct { |
| 1456 | llvm_arg_i += 1; | 1457 | llvm_arg_i += 1; |
| 1457 | 1458 | ||
| 1458 | const param_llvm_ty = try o.lowerType(param_ty); | 1459 | const param_llvm_ty = try o.lowerType(param_ty); |
| 1459 | const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod)); | 1460 | const alignment = param_ty.abiAlignment(mod).toLlvm(); |
| 1460 | const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target); | 1461 | const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target); |
| 1461 | _ = try wip.store(.normal, param, arg_ptr, alignment); | 1462 | _ = try wip.store(.normal, param, arg_ptr, alignment); |
| 1462 | 1463 | ||
| ... | @@ -1481,10 +1482,10 @@ pub const Object = struct { | ... | @@ -1481,10 +1482,10 @@ pub const Object = struct { |
| 1481 | if (ptr_info.flags.is_const) { | 1482 | if (ptr_info.flags.is_const) { |
| 1482 | try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder); | 1483 | try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder); |
| 1483 | } | 1484 | } |
| 1484 | const elem_align = Builder.Alignment.fromByteUnits( | 1485 | const elem_align = (if (ptr_info.flags.alignment != .none) |
| 1485 | ptr_info.flags.alignment.toByteUnitsOptional() orelse | 1486 | @as(InternPool.Alignment, ptr_info.flags.alignment) |
| 1486 | @max(ptr_info.child.toType().abiAlignment(mod), 1), | 1487 | else |
| 1487 | ); | 1488 | ptr_info.child.toType().abiAlignment(mod).max(.@"1")).toLlvm(); |
| 1488 | try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder); | 1489 | try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder); |
| 1489 | const ptr_param = wip.arg(llvm_arg_i); | 1490 | const ptr_param = wip.arg(llvm_arg_i); |
| 1490 | llvm_arg_i += 1; | 1491 | llvm_arg_i += 1; |
| ... | @@ -1501,7 +1502,7 @@ pub const Object = struct { | ... | @@ -1501,7 +1502,7 @@ pub const Object = struct { |
| 1501 | const field_types = it.types_buffer[0..it.types_len]; | 1502 | const field_types = it.types_buffer[0..it.types_len]; |
| 1502 | const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType(); | 1503 | const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType(); |
| 1503 | const param_llvm_ty = try o.lowerType(param_ty); | 1504 | const param_llvm_ty = try o.lowerType(param_ty); |
| 1504 | const param_alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod)); | 1505 | const param_alignment = param_ty.abiAlignment(mod).toLlvm(); |
| 1505 | const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, param_alignment, target); | 1506 | const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, param_alignment, target); |
| 1506 | const llvm_ty = try o.builder.structType(.normal, field_types); | 1507 | const llvm_ty = try o.builder.structType(.normal, field_types); |
| 1507 | for (0..field_types.len) |field_i| { | 1508 | for (0..field_types.len) |field_i| { |
| ... | @@ -1531,7 +1532,7 @@ pub const Object = struct { | ... | @@ -1531,7 +1532,7 @@ pub const Object = struct { |
| 1531 | const param = wip.arg(llvm_arg_i); | 1532 | const param = wip.arg(llvm_arg_i); |
| 1532 | llvm_arg_i += 1; | 1533 | llvm_arg_i += 1; |
| 1533 | 1534 | ||
| 1534 | const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod)); | 1535 | const alignment = param_ty.abiAlignment(mod).toLlvm(); |
| 1535 | const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target); | 1536 | const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target); |
| 1536 | _ = try wip.store(.normal, param, arg_ptr, alignment); | 1537 | _ = try wip.store(.normal, param, arg_ptr, alignment); |
| 1537 | 1538 | ||
| ... | @@ -1546,7 +1547,7 @@ pub const Object = struct { | ... | @@ -1546,7 +1547,7 @@ pub const Object = struct { |
| 1546 | const param = wip.arg(llvm_arg_i); | 1547 | const param = wip.arg(llvm_arg_i); |
| 1547 | llvm_arg_i += 1; | 1548 | llvm_arg_i += 1; |
| 1548 | 1549 | ||
| 1549 | const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod)); | 1550 | const alignment = param_ty.abiAlignment(mod).toLlvm(); |
| 1550 | const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target); | 1551 | const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target); |
| 1551 | _ = try wip.store(.normal, param, arg_ptr, alignment); | 1552 | _ = try wip.store(.normal, param, arg_ptr, alignment); |
| 1552 | 1553 | ||
| ... | @@ -1967,7 +1968,7 @@ pub const Object = struct { | ... | @@ -1967,7 +1968,7 @@ pub const Object = struct { |
| 1967 | di_file, | 1968 | di_file, |
| 1968 | owner_decl.src_node + 1, | 1969 | owner_decl.src_node + 1, |
| 1969 | ty.abiSize(mod) * 8, | 1970 | ty.abiSize(mod) * 8, |
| 1970 | ty.abiAlignment(mod) * 8, | 1971 | ty.abiAlignment(mod).toByteUnits(0) * 8, |
| 1971 | enumerators.ptr, | 1972 | enumerators.ptr, |
| 1972 | @intCast(enumerators.len), | 1973 | @intCast(enumerators.len), |
| 1973 | try o.lowerDebugType(int_ty, .full), | 1974 | try o.lowerDebugType(int_ty, .full), |
| ... | @@ -2055,7 +2056,7 @@ pub const Object = struct { | ... | @@ -2055,7 +2056,7 @@ pub const Object = struct { |
| 2055 | 2056 | ||
| 2056 | var offset: u64 = 0; | 2057 | var offset: u64 = 0; |
| 2057 | offset += ptr_size; | 2058 | offset += ptr_size; |
| 2058 | offset = std.mem.alignForward(u64, offset, len_align); | 2059 | offset = len_align.forward(offset); |
| 2059 | const len_offset = offset; | 2060 | const len_offset = offset; |
| 2060 | 2061 | ||
| 2061 | const fields: [2]*llvm.DIType = .{ | 2062 | const fields: [2]*llvm.DIType = .{ |
| ... | @@ -2065,7 +2066,7 @@ pub const Object = struct { | ... | @@ -2065,7 +2066,7 @@ pub const Object = struct { |
| 2065 | di_file, | 2066 | di_file, |
| 2066 | line, | 2067 | line, |
| 2067 | ptr_size * 8, // size in bits | 2068 | ptr_size * 8, // size in bits |
| 2068 | ptr_align * 8, // align in bits | 2069 | ptr_align.toByteUnits(0) * 8, // align in bits |
| 2069 | 0, // offset in bits | 2070 | 0, // offset in bits |
| 2070 | 0, // flags | 2071 | 0, // flags |
| 2071 | try o.lowerDebugType(ptr_ty, .full), | 2072 | try o.lowerDebugType(ptr_ty, .full), |
| ... | @@ -2076,7 +2077,7 @@ pub const Object = struct { | ... | @@ -2076,7 +2077,7 @@ pub const Object = struct { |
| 2076 | di_file, | 2077 | di_file, |
| 2077 | line, | 2078 | line, |
| 2078 | len_size * 8, // size in bits | 2079 | len_size * 8, // size in bits |
| 2079 | len_align * 8, // align in bits | 2080 | len_align.toByteUnits(0) * 8, // align in bits |
| 2080 | len_offset * 8, // offset in bits | 2081 | len_offset * 8, // offset in bits |
| 2081 | 0, // flags | 2082 | 0, // flags |
| 2082 | try o.lowerDebugType(len_ty, .full), | 2083 | try o.lowerDebugType(len_ty, .full), |
| ... | @@ -2089,7 +2090,7 @@ pub const Object = struct { | ... | @@ -2089,7 +2090,7 @@ pub const Object = struct { |
| 2089 | di_file, | 2090 | di_file, |
| 2090 | line, | 2091 | line, |
| 2091 | ty.abiSize(mod) * 8, // size in bits | 2092 | ty.abiSize(mod) * 8, // size in bits |
| 2092 | ty.abiAlignment(mod) * 8, // align in bits | 2093 | ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits |
| 2093 | 0, // flags | 2094 | 0, // flags |
| 2094 | null, // derived from | 2095 | null, // derived from |
| 2095 | &fields, | 2096 | &fields, |
| ... | @@ -2110,7 +2111,7 @@ pub const Object = struct { | ... | @@ -2110,7 +2111,7 @@ pub const Object = struct { |
| 2110 | const ptr_di_ty = dib.createPointerType( | 2111 | const ptr_di_ty = dib.createPointerType( |
| 2111 | elem_di_ty, | 2112 | elem_di_ty, |
| 2112 | target.ptrBitWidth(), | 2113 | target.ptrBitWidth(), |
| 2113 | ty.ptrAlignment(mod) * 8, | 2114 | ty.ptrAlignment(mod).toByteUnits(0) * 8, |
| 2114 | name, | 2115 | name, |
| 2115 | ); | 2116 | ); |
| 2116 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | 2117 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| ... | @@ -2142,7 +2143,7 @@ pub const Object = struct { | ... | @@ -2142,7 +2143,7 @@ pub const Object = struct { |
| 2142 | .Array => { | 2143 | .Array => { |
| 2143 | const array_di_ty = dib.createArrayType( | 2144 | const array_di_ty = dib.createArrayType( |
| 2144 | ty.abiSize(mod) * 8, | 2145 | ty.abiSize(mod) * 8, |
| 2145 | ty.abiAlignment(mod) * 8, | 2146 | ty.abiAlignment(mod).toByteUnits(0) * 8, |
| 2146 | try o.lowerDebugType(ty.childType(mod), .full), | 2147 | try o.lowerDebugType(ty.childType(mod), .full), |
| 2147 | @intCast(ty.arrayLen(mod)), | 2148 | @intCast(ty.arrayLen(mod)), |
| 2148 | ); | 2149 | ); |
| ... | @@ -2174,7 +2175,7 @@ pub const Object = struct { | ... | @@ -2174,7 +2175,7 @@ pub const Object = struct { |
| 2174 | 2175 | ||
| 2175 | const vector_di_ty = dib.createVectorType( | 2176 | const vector_di_ty = dib.createVectorType( |
| 2176 | ty.abiSize(mod) * 8, | 2177 | ty.abiSize(mod) * 8, |
| 2177 | ty.abiAlignment(mod) * 8, | 2178 | @intCast(ty.abiAlignment(mod).toByteUnits(0) * 8), |
| 2178 | elem_di_type, | 2179 | elem_di_type, |
| 2179 | ty.vectorLen(mod), | 2180 | ty.vectorLen(mod), |
| 2180 | ); | 2181 | ); |
| ... | @@ -2223,7 +2224,7 @@ pub const Object = struct { | ... | @@ -2223,7 +2224,7 @@ pub const Object = struct { |
| 2223 | 2224 | ||
| 2224 | var offset: u64 = 0; | 2225 | var offset: u64 = 0; |
| 2225 | offset += payload_size; | 2226 | offset += payload_size; |
| 2226 | offset = std.mem.alignForward(u64, offset, non_null_align); | 2227 | offset = non_null_align.forward(offset); |
| 2227 | const non_null_offset = offset; | 2228 | const non_null_offset = offset; |
| 2228 | 2229 | ||
| 2229 | const fields: [2]*llvm.DIType = .{ | 2230 | const fields: [2]*llvm.DIType = .{ |
| ... | @@ -2233,7 +2234,7 @@ pub const Object = struct { | ... | @@ -2233,7 +2234,7 @@ pub const Object = struct { |
| 2233 | di_file, | 2234 | di_file, |
| 2234 | line, | 2235 | line, |
| 2235 | payload_size * 8, // size in bits | 2236 | payload_size * 8, // size in bits |
| 2236 | payload_align * 8, // align in bits | 2237 | payload_align.toByteUnits(0) * 8, // align in bits |
| 2237 | 0, // offset in bits | 2238 | 0, // offset in bits |
| 2238 | 0, // flags | 2239 | 0, // flags |
| 2239 | try o.lowerDebugType(child_ty, .full), | 2240 | try o.lowerDebugType(child_ty, .full), |
| ... | @@ -2244,7 +2245,7 @@ pub const Object = struct { | ... | @@ -2244,7 +2245,7 @@ pub const Object = struct { |
| 2244 | di_file, | 2245 | di_file, |
| 2245 | line, | 2246 | line, |
| 2246 | non_null_size * 8, // size in bits | 2247 | non_null_size * 8, // size in bits |
| 2247 | non_null_align * 8, // align in bits | 2248 | non_null_align.toByteUnits(0) * 8, // align in bits |
| 2248 | non_null_offset * 8, // offset in bits | 2249 | non_null_offset * 8, // offset in bits |
| 2249 | 0, // flags | 2250 | 0, // flags |
| 2250 | try o.lowerDebugType(non_null_ty, .full), | 2251 | try o.lowerDebugType(non_null_ty, .full), |
| ... | @@ -2257,7 +2258,7 @@ pub const Object = struct { | ... | @@ -2257,7 +2258,7 @@ pub const Object = struct { |
| 2257 | di_file, | 2258 | di_file, |
| 2258 | line, | 2259 | line, |
| 2259 | ty.abiSize(mod) * 8, // size in bits | 2260 | ty.abiSize(mod) * 8, // size in bits |
| 2260 | ty.abiAlignment(mod) * 8, // align in bits | 2261 | ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits |
| 2261 | 0, // flags | 2262 | 0, // flags |
| 2262 | null, // derived from | 2263 | null, // derived from |
| 2263 | &fields, | 2264 | &fields, |
| ... | @@ -2306,16 +2307,16 @@ pub const Object = struct { | ... | @@ -2306,16 +2307,16 @@ pub const Object = struct { |
| 2306 | var payload_index: u32 = undefined; | 2307 | var payload_index: u32 = undefined; |
| 2307 | var error_offset: u64 = undefined; | 2308 | var error_offset: u64 = undefined; |
| 2308 | var payload_offset: u64 = undefined; | 2309 | var payload_offset: u64 = undefined; |
| 2309 | if (error_align > payload_align) { | 2310 | if (error_align.compare(.gt, payload_align)) { |
| 2310 | error_index = 0; | 2311 | error_index = 0; |
| 2311 | payload_index = 1; | 2312 | payload_index = 1; |
| 2312 | error_offset = 0; | 2313 | error_offset = 0; |
| 2313 | payload_offset = std.mem.alignForward(u64, error_size, payload_align); | 2314 | payload_offset = payload_align.forward(error_size); |
| 2314 | } else { | 2315 | } else { |
| 2315 | payload_index = 0; | 2316 | payload_index = 0; |
| 2316 | error_index = 1; | 2317 | error_index = 1; |
| 2317 | payload_offset = 0; | 2318 | payload_offset = 0; |
| 2318 | error_offset = std.mem.alignForward(u64, payload_size, error_align); | 2319 | error_offset = error_align.forward(payload_size); |
| 2319 | } | 2320 | } |
| 2320 | 2321 | ||
| 2321 | var fields: [2]*llvm.DIType = undefined; | 2322 | var fields: [2]*llvm.DIType = undefined; |
| ... | @@ -2325,7 +2326,7 @@ pub const Object = struct { | ... | @@ -2325,7 +2326,7 @@ pub const Object = struct { |
| 2325 | di_file, | 2326 | di_file, |
| 2326 | line, | 2327 | line, |
| 2327 | error_size * 8, // size in bits | 2328 | error_size * 8, // size in bits |
| 2328 | error_align * 8, // align in bits | 2329 | error_align.toByteUnits(0) * 8, // align in bits |
| 2329 | error_offset * 8, // offset in bits | 2330 | error_offset * 8, // offset in bits |
| 2330 | 0, // flags | 2331 | 0, // flags |
| 2331 | try o.lowerDebugType(Type.anyerror, .full), | 2332 | try o.lowerDebugType(Type.anyerror, .full), |
| ... | @@ -2336,7 +2337,7 @@ pub const Object = struct { | ... | @@ -2336,7 +2337,7 @@ pub const Object = struct { |
| 2336 | di_file, | 2337 | di_file, |
| 2337 | line, | 2338 | line, |
| 2338 | payload_size * 8, // size in bits | 2339 | payload_size * 8, // size in bits |
| 2339 | payload_align * 8, // align in bits | 2340 | payload_align.toByteUnits(0) * 8, // align in bits |
| 2340 | payload_offset * 8, // offset in bits | 2341 | payload_offset * 8, // offset in bits |
| 2341 | 0, // flags | 2342 | 0, // flags |
| 2342 | try o.lowerDebugType(payload_ty, .full), | 2343 | try o.lowerDebugType(payload_ty, .full), |
| ... | @@ -2348,7 +2349,7 @@ pub const Object = struct { | ... | @@ -2348,7 +2349,7 @@ pub const Object = struct { |
| 2348 | di_file, | 2349 | di_file, |
| 2349 | line, | 2350 | line, |
| 2350 | ty.abiSize(mod) * 8, // size in bits | 2351 | ty.abiSize(mod) * 8, // size in bits |
| 2351 | ty.abiAlignment(mod) * 8, // align in bits | 2352 | ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits |
| 2352 | 0, // flags | 2353 | 0, // flags |
| 2353 | null, // derived from | 2354 | null, // derived from |
| 2354 | &fields, | 2355 | &fields, |
| ... | @@ -2374,10 +2375,10 @@ pub const Object = struct { | ... | @@ -2374,10 +2375,10 @@ pub const Object = struct { |
| 2374 | const name = try o.allocTypeName(ty); | 2375 | const name = try o.allocTypeName(ty); |
| 2375 | defer gpa.free(name); | 2376 | defer gpa.free(name); |
| 2376 | 2377 | ||
| 2377 | if (mod.typeToStruct(ty)) |struct_obj| { | 2378 | if (mod.typeToPackedStruct(ty)) |struct_type| { |
| 2378 | if (struct_obj.layout == .Packed and struct_obj.haveFieldTypes()) { | 2379 | const backing_int_ty = struct_type.backingIntType(ip).*; |
| 2379 | assert(struct_obj.haveLayout()); | 2380 | if (backing_int_ty != .none) { |
| 2380 | const info = struct_obj.backing_int_ty.intInfo(mod); | 2381 | const info = backing_int_ty.toType().intInfo(mod); |
| 2381 | const dwarf_encoding: c_uint = switch (info.signedness) { | 2382 | const dwarf_encoding: c_uint = switch (info.signedness) { |
| 2382 | .signed => DW.ATE.signed, | 2383 | .signed => DW.ATE.signed, |
| 2383 | .unsigned => DW.ATE.unsigned, | 2384 | .unsigned => DW.ATE.unsigned, |
| ... | @@ -2417,7 +2418,7 @@ pub const Object = struct { | ... | @@ -2417,7 +2418,7 @@ pub const Object = struct { |
| 2417 | 2418 | ||
| 2418 | const field_size = field_ty.toType().abiSize(mod); | 2419 | const field_size = field_ty.toType().abiSize(mod); |
| 2419 | const field_align = field_ty.toType().abiAlignment(mod); | 2420 | const field_align = field_ty.toType().abiAlignment(mod); |
| 2420 | const field_offset = std.mem.alignForward(u64, offset, field_align); | 2421 | const field_offset = field_align.forward(offset); |
| 2421 | offset = field_offset + field_size; | 2422 | offset = field_offset + field_size; |
| 2422 | 2423 | ||
| 2423 | const field_name = if (tuple.names.len != 0) | 2424 | const field_name = if (tuple.names.len != 0) |
| ... | @@ -2432,7 +2433,7 @@ pub const Object = struct { | ... | @@ -2432,7 +2433,7 @@ pub const Object = struct { |
| 2432 | null, // file | 2433 | null, // file |
| 2433 | 0, // line | 2434 | 0, // line |
| 2434 | field_size * 8, // size in bits | 2435 | field_size * 8, // size in bits |
| 2435 | field_align * 8, // align in bits | 2436 | field_align.toByteUnits(0) * 8, // align in bits |
| 2436 | field_offset * 8, // offset in bits | 2437 | field_offset * 8, // offset in bits |
| 2437 | 0, // flags | 2438 | 0, // flags |
| 2438 | try o.lowerDebugType(field_ty.toType(), .full), | 2439 | try o.lowerDebugType(field_ty.toType(), .full), |
| ... | @@ -2445,7 +2446,7 @@ pub const Object = struct { | ... | @@ -2445,7 +2446,7 @@ pub const Object = struct { |
| 2445 | null, // file | 2446 | null, // file |
| 2446 | 0, // line | 2447 | 0, // line |
| 2447 | ty.abiSize(mod) * 8, // size in bits | 2448 | ty.abiSize(mod) * 8, // size in bits |
| 2448 | ty.abiAlignment(mod) * 8, // align in bits | 2449 | ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits |
| 2449 | 0, // flags | 2450 | 0, // flags |
| 2450 | null, // derived from | 2451 | null, // derived from |
| 2451 | di_fields.items.ptr, | 2452 | di_fields.items.ptr, |
| ... | @@ -2459,10 +2460,8 @@ pub const Object = struct { | ... | @@ -2459,10 +2460,8 @@ pub const Object = struct { |
| 2459 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(full_di_ty)); | 2460 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(full_di_ty)); |
| 2460 | return full_di_ty; | 2461 | return full_di_ty; |
| 2461 | }, | 2462 | }, |
| 2462 | .struct_type => |struct_type| s: { | 2463 | .struct_type => |struct_type| { |
| 2463 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :s; | 2464 | if (!struct_type.haveFieldTypes(ip)) { |
| 2464 | |||
| 2465 | if (!struct_obj.haveFieldTypes()) { | ||
| 2466 | // This can happen if a struct type makes it all the way to | 2465 | // This can happen if a struct type makes it all the way to |
| 2467 | // flush() without ever being instantiated or referenced (even | 2466 | // flush() without ever being instantiated or referenced (even |
| 2468 | // via pointer). The only reason we are hearing about it now is | 2467 | // via pointer). The only reason we are hearing about it now is |
| ... | @@ -2492,26 +2491,30 @@ pub const Object = struct { | ... | @@ -2492,26 +2491,30 @@ pub const Object = struct { |
| 2492 | return struct_di_ty; | 2491 | return struct_di_ty; |
| 2493 | } | 2492 | } |
| 2494 | 2493 | ||
| 2495 | const fields = ty.structFields(mod); | 2494 | const struct_type = mod.typeToStruct(ty).?; |
| 2496 | const layout = ty.containerLayout(mod); | 2495 | const field_types = struct_type.field_types.get(ip); |
| 2496 | const field_names = struct_type.field_names.get(ip); | ||
| 2497 | 2497 | ||
| 2498 | var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{}; | 2498 | var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{}; |
| 2499 | defer di_fields.deinit(gpa); | 2499 | defer di_fields.deinit(gpa); |
| 2500 | 2500 | ||
| 2501 | try di_fields.ensureUnusedCapacity(gpa, fields.count()); | 2501 | try di_fields.ensureUnusedCapacity(gpa, field_types.len); |
| 2502 | 2502 | ||
| 2503 | comptime assert(struct_layout_version == 2); | 2503 | comptime assert(struct_layout_version == 2); |
| 2504 | var offset: u64 = 0; | 2504 | var offset: u64 = 0; |
| 2505 | 2505 | var it = struct_type.iterateRuntimeOrder(ip); | |
| 2506 | var it = mod.typeToStruct(ty).?.runtimeFieldIterator(mod); | 2506 | while (it.next()) |field_index| { |
| 2507 | while (it.next()) |field_and_index| { | 2507 | const field_ty = field_types[field_index].toType(); |
| 2508 | const field = field_and_index.field; | 2508 | const field_size = field_ty.abiSize(mod); |
| 2509 | const field_size = field.ty.abiSize(mod); | 2509 | const field_align = mod.structFieldAlignment( |
| 2510 | const field_align = field.alignment(mod, layout); | 2510 | struct_type.fieldAlign(ip, field_index), |
| 2511 | const field_offset = std.mem.alignForward(u64, offset, field_align); | 2511 | field_ty, |
| 2512 | struct_type.layout, | ||
| 2513 | ); | ||
| 2514 | const field_offset = field_align.forward(offset); | ||
| 2512 | offset = field_offset + field_size; | 2515 | offset = field_offset + field_size; |
| 2513 | 2516 | ||
| 2514 | const field_name = ip.stringToSlice(fields.keys()[field_and_index.index]); | 2517 | const field_name = ip.stringToSlice(field_names[field_index]); |
| 2515 | 2518 | ||
| 2516 | try di_fields.append(gpa, dib.createMemberType( | 2519 | try di_fields.append(gpa, dib.createMemberType( |
| 2517 | fwd_decl.toScope(), | 2520 | fwd_decl.toScope(), |
| ... | @@ -2519,10 +2522,10 @@ pub const Object = struct { | ... | @@ -2519,10 +2522,10 @@ pub const Object = struct { |
| 2519 | null, // file | 2522 | null, // file |
| 2520 | 0, // line | 2523 | 0, // line |
| 2521 | field_size * 8, // size in bits | 2524 | field_size * 8, // size in bits |
| 2522 | field_align * 8, // align in bits | 2525 | field_align.toByteUnits(0) * 8, // align in bits |
| 2523 | field_offset * 8, // offset in bits | 2526 | field_offset * 8, // offset in bits |
| 2524 | 0, // flags | 2527 | 0, // flags |
| 2525 | try o.lowerDebugType(field.ty, .full), | 2528 | try o.lowerDebugType(field_ty, .full), |
| 2526 | )); | 2529 | )); |
| 2527 | } | 2530 | } |
| 2528 | 2531 | ||
| ... | @@ -2532,7 +2535,7 @@ pub const Object = struct { | ... | @@ -2532,7 +2535,7 @@ pub const Object = struct { |
| 2532 | null, // file | 2535 | null, // file |
| 2533 | 0, // line | 2536 | 0, // line |
| 2534 | ty.abiSize(mod) * 8, // size in bits | 2537 | ty.abiSize(mod) * 8, // size in bits |
| 2535 | ty.abiAlignment(mod) * 8, // align in bits | 2538 | ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits |
| 2536 | 0, // flags | 2539 | 0, // flags |
| 2537 | null, // derived from | 2540 | null, // derived from |
| 2538 | di_fields.items.ptr, | 2541 | di_fields.items.ptr, |
| ... | @@ -2588,7 +2591,7 @@ pub const Object = struct { | ... | @@ -2588,7 +2591,7 @@ pub const Object = struct { |
| 2588 | null, // file | 2591 | null, // file |
| 2589 | 0, // line | 2592 | 0, // line |
| 2590 | ty.abiSize(mod) * 8, // size in bits | 2593 | ty.abiSize(mod) * 8, // size in bits |
| 2591 | ty.abiAlignment(mod) * 8, // align in bits | 2594 | ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits |
| 2592 | 0, // flags | 2595 | 0, // flags |
| 2593 | null, // derived from | 2596 | null, // derived from |
| 2594 | &di_fields, | 2597 | &di_fields, |
| ... | @@ -2624,7 +2627,7 @@ pub const Object = struct { | ... | @@ -2624,7 +2627,7 @@ pub const Object = struct { |
| 2624 | null, // file | 2627 | null, // file |
| 2625 | 0, // line | 2628 | 0, // line |
| 2626 | field_size * 8, // size in bits | 2629 | field_size * 8, // size in bits |
| 2627 | field_align * 8, // align in bits | 2630 | field_align.toByteUnits(0) * 8, // align in bits |
| 2628 | 0, // offset in bits | 2631 | 0, // offset in bits |
| 2629 | 0, // flags | 2632 | 0, // flags |
| 2630 | field_di_ty, | 2633 | field_di_ty, |
| ... | @@ -2644,7 +2647,7 @@ pub const Object = struct { | ... | @@ -2644,7 +2647,7 @@ pub const Object = struct { |
| 2644 | null, // file | 2647 | null, // file |
| 2645 | 0, // line | 2648 | 0, // line |
| 2646 | ty.abiSize(mod) * 8, // size in bits | 2649 | ty.abiSize(mod) * 8, // size in bits |
| 2647 | ty.abiAlignment(mod) * 8, // align in bits | 2650 | ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits |
| 2648 | 0, // flags | 2651 | 0, // flags |
| 2649 | di_fields.items.ptr, | 2652 | di_fields.items.ptr, |
| 2650 | @intCast(di_fields.items.len), | 2653 | @intCast(di_fields.items.len), |
| ... | @@ -2661,12 +2664,12 @@ pub const Object = struct { | ... | @@ -2661,12 +2664,12 @@ pub const Object = struct { |
| 2661 | 2664 | ||
| 2662 | var tag_offset: u64 = undefined; | 2665 | var tag_offset: u64 = undefined; |
| 2663 | var payload_offset: u64 = undefined; | 2666 | var payload_offset: u64 = undefined; |
| 2664 | if (layout.tag_align >= layout.payload_align) { | 2667 | if (layout.tag_align.compare(.gte, layout.payload_align)) { |
| 2665 | tag_offset = 0; | 2668 | tag_offset = 0; |
| 2666 | payload_offset = std.mem.alignForward(u64, layout.tag_size, layout.payload_align); | 2669 | payload_offset = layout.payload_align.forward(layout.tag_size); |
| 2667 | } else { | 2670 | } else { |
| 2668 | payload_offset = 0; | 2671 | payload_offset = 0; |
| 2669 | tag_offset = std.mem.alignForward(u64, layout.payload_size, layout.tag_align); | 2672 | tag_offset = layout.tag_align.forward(layout.payload_size); |
| 2670 | } | 2673 | } |
| 2671 | 2674 | ||
| 2672 | const tag_di = dib.createMemberType( | 2675 | const tag_di = dib.createMemberType( |
| ... | @@ -2675,7 +2678,7 @@ pub const Object = struct { | ... | @@ -2675,7 +2678,7 @@ pub const Object = struct { |
| 2675 | null, // file | 2678 | null, // file |
| 2676 | 0, // line | 2679 | 0, // line |
| 2677 | layout.tag_size * 8, | 2680 | layout.tag_size * 8, |
| 2678 | layout.tag_align * 8, // align in bits | 2681 | layout.tag_align.toByteUnits(0) * 8, |
| 2679 | tag_offset * 8, // offset in bits | 2682 | tag_offset * 8, // offset in bits |
| 2680 | 0, // flags | 2683 | 0, // flags |
| 2681 | try o.lowerDebugType(union_obj.enum_tag_ty.toType(), .full), | 2684 | try o.lowerDebugType(union_obj.enum_tag_ty.toType(), .full), |
| ... | @@ -2687,14 +2690,14 @@ pub const Object = struct { | ... | @@ -2687,14 +2690,14 @@ pub const Object = struct { |
| 2687 | null, // file | 2690 | null, // file |
| 2688 | 0, // line | 2691 | 0, // line |
| 2689 | layout.payload_size * 8, // size in bits | 2692 | layout.payload_size * 8, // size in bits |
| 2690 | layout.payload_align * 8, // align in bits | 2693 | layout.payload_align.toByteUnits(0) * 8, |
| 2691 | payload_offset * 8, // offset in bits | 2694 | payload_offset * 8, // offset in bits |
| 2692 | 0, // flags | 2695 | 0, // flags |
| 2693 | union_di_ty, | 2696 | union_di_ty, |
| 2694 | ); | 2697 | ); |
| 2695 | 2698 | ||
| 2696 | const full_di_fields: [2]*llvm.DIType = | 2699 | const full_di_fields: [2]*llvm.DIType = |
| 2697 | if (layout.tag_align >= layout.payload_align) | 2700 | if (layout.tag_align.compare(.gte, layout.payload_align)) |
| 2698 | .{ tag_di, payload_di } | 2701 | .{ tag_di, payload_di } |
| 2699 | else | 2702 | else |
| 2700 | .{ payload_di, tag_di }; | 2703 | .{ payload_di, tag_di }; |
| ... | @@ -2705,7 +2708,7 @@ pub const Object = struct { | ... | @@ -2705,7 +2708,7 @@ pub const Object = struct { |
| 2705 | null, // file | 2708 | null, // file |
| 2706 | 0, // line | 2709 | 0, // line |
| 2707 | ty.abiSize(mod) * 8, // size in bits | 2710 | ty.abiSize(mod) * 8, // size in bits |
| 2708 | ty.abiAlignment(mod) * 8, // align in bits | 2711 | ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits |
| 2709 | 0, // flags | 2712 | 0, // flags |
| 2710 | null, // derived from | 2713 | null, // derived from |
| 2711 | &full_di_fields, | 2714 | &full_di_fields, |
| ... | @@ -2925,8 +2928,8 @@ pub const Object = struct { | ... | @@ -2925,8 +2928,8 @@ pub const Object = struct { |
| 2925 | else => function_index.setCallConv(toLlvmCallConv(fn_info.cc, target), &o.builder), | 2928 | else => function_index.setCallConv(toLlvmCallConv(fn_info.cc, target), &o.builder), |
| 2926 | } | 2929 | } |
| 2927 | 2930 | ||
| 2928 | if (fn_info.alignment.toByteUnitsOptional()) |alignment| | 2931 | if (fn_info.alignment != .none) |
| 2929 | function_index.setAlignment(Builder.Alignment.fromByteUnits(alignment), &o.builder); | 2932 | function_index.setAlignment(fn_info.alignment.toLlvm(), &o.builder); |
| 2930 | 2933 | ||
| 2931 | // Function attributes that are independent of analysis results of the function body. | 2934 | // Function attributes that are independent of analysis results of the function body. |
| 2932 | try o.addCommonFnAttributes(&attributes); | 2935 | try o.addCommonFnAttributes(&attributes); |
| ... | @@ -2949,9 +2952,8 @@ pub const Object = struct { | ... | @@ -2949,9 +2952,8 @@ pub const Object = struct { |
| 2949 | .byref => { | 2952 | .byref => { |
| 2950 | const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1]; | 2953 | const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1]; |
| 2951 | const param_llvm_ty = try o.lowerType(param_ty.toType()); | 2954 | const param_llvm_ty = try o.lowerType(param_ty.toType()); |
| 2952 | const alignment = | 2955 | const alignment = param_ty.toType().abiAlignment(mod); |
| 2953 | Builder.Alignment.fromByteUnits(param_ty.toType().abiAlignment(mod)); | 2956 | try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment.toLlvm(), it.byval_attr, param_llvm_ty); |
| 2954 | try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty); | ||
| 2955 | }, | 2957 | }, |
| 2956 | .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder), | 2958 | .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder), |
| 2957 | // No attributes needed for these. | 2959 | // No attributes needed for these. |
| ... | @@ -3248,21 +3250,21 @@ pub const Object = struct { | ... | @@ -3248,21 +3250,21 @@ pub const Object = struct { |
| 3248 | 3250 | ||
| 3249 | var fields: [3]Builder.Type = undefined; | 3251 | var fields: [3]Builder.Type = undefined; |
| 3250 | var fields_len: usize = 2; | 3252 | var fields_len: usize = 2; |
| 3251 | const padding_len = if (error_align > payload_align) pad: { | 3253 | const padding_len = if (error_align.compare(.gt, payload_align)) pad: { |
| 3252 | fields[0] = error_type; | 3254 | fields[0] = error_type; |
| 3253 | fields[1] = payload_type; | 3255 | fields[1] = payload_type; |
| 3254 | const payload_end = | 3256 | const payload_end = |
| 3255 | std.mem.alignForward(u64, error_size, payload_align) + | 3257 | payload_align.forward(error_size) + |
| 3256 | payload_size; | 3258 | payload_size; |
| 3257 | const abi_size = std.mem.alignForward(u64, payload_end, error_align); | 3259 | const abi_size = error_align.forward(payload_end); |
| 3258 | break :pad abi_size - payload_end; | 3260 | break :pad abi_size - payload_end; |
| 3259 | } else pad: { | 3261 | } else pad: { |
| 3260 | fields[0] = payload_type; | 3262 | fields[0] = payload_type; |
| 3261 | fields[1] = error_type; | 3263 | fields[1] = error_type; |
| 3262 | const error_end = | 3264 | const error_end = |
| 3263 | std.mem.alignForward(u64, payload_size, error_align) + | 3265 | error_align.forward(payload_size) + |
| 3264 | error_size; | 3266 | error_size; |
| 3265 | const abi_size = std.mem.alignForward(u64, error_end, payload_align); | 3267 | const abi_size = payload_align.forward(error_end); |
| 3266 | break :pad abi_size - error_end; | 3268 | break :pad abi_size - error_end; |
| 3267 | }; | 3269 | }; |
| 3268 | if (padding_len > 0) { | 3270 | if (padding_len > 0) { |
| ... | @@ -3276,43 +3278,44 @@ pub const Object = struct { | ... | @@ -3276,43 +3278,44 @@ pub const Object = struct { |
| 3276 | const gop = try o.type_map.getOrPut(o.gpa, t.toIntern()); | 3278 | const gop = try o.type_map.getOrPut(o.gpa, t.toIntern()); |
| 3277 | if (gop.found_existing) return gop.value_ptr.*; | 3279 | if (gop.found_existing) return gop.value_ptr.*; |
| 3278 | 3280 | ||
| 3279 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | 3281 | if (struct_type.layout == .Packed) { |
| 3280 | if (struct_obj.layout == .Packed) { | 3282 | const int_ty = try o.lowerType(struct_type.backingIntType(ip).toType()); |
| 3281 | assert(struct_obj.haveLayout()); | ||
| 3282 | const int_ty = try o.lowerType(struct_obj.backing_int_ty); | ||
| 3283 | gop.value_ptr.* = int_ty; | 3283 | gop.value_ptr.* = int_ty; |
| 3284 | return int_ty; | 3284 | return int_ty; |
| 3285 | } | 3285 | } |
| 3286 | 3286 | ||
| 3287 | const name = try o.builder.string(ip.stringToSlice( | 3287 | const name = try o.builder.string(ip.stringToSlice( |
| 3288 | try struct_obj.getFullyQualifiedName(mod), | 3288 | try mod.declPtr(struct_type.decl.unwrap().?).getFullyQualifiedName(mod), |
| 3289 | )); | 3289 | )); |
| 3290 | const ty = try o.builder.opaqueType(name); | 3290 | const ty = try o.builder.opaqueType(name); |
| 3291 | gop.value_ptr.* = ty; // must be done before any recursive calls | 3291 | gop.value_ptr.* = ty; // must be done before any recursive calls |
| 3292 | 3292 | ||
| 3293 | assert(struct_obj.haveFieldTypes()); | ||
| 3294 | |||
| 3295 | var llvm_field_types = std.ArrayListUnmanaged(Builder.Type){}; | 3293 | var llvm_field_types = std.ArrayListUnmanaged(Builder.Type){}; |
| 3296 | defer llvm_field_types.deinit(o.gpa); | 3294 | defer llvm_field_types.deinit(o.gpa); |
| 3297 | // Although we can estimate how much capacity to add, these cannot be | 3295 | // Although we can estimate how much capacity to add, these cannot be |
| 3298 | // relied upon because of the recursive calls to lowerType below. | 3296 | // relied upon because of the recursive calls to lowerType below. |
| 3299 | try llvm_field_types.ensureUnusedCapacity(o.gpa, struct_obj.fields.count()); | 3297 | try llvm_field_types.ensureUnusedCapacity(o.gpa, struct_type.field_types.len); |
| 3300 | try o.struct_field_map.ensureUnusedCapacity(o.gpa, @intCast(struct_obj.fields.count())); | 3298 | try o.struct_field_map.ensureUnusedCapacity(o.gpa, struct_type.field_types.len); |
| 3301 | 3299 | ||
| 3302 | comptime assert(struct_layout_version == 2); | 3300 | comptime assert(struct_layout_version == 2); |
| 3303 | var offset: u64 = 0; | 3301 | var offset: u64 = 0; |
| 3304 | var big_align: u32 = 1; | 3302 | var big_align: InternPool.Alignment = .@"1"; |
| 3305 | var struct_kind: Builder.Type.Structure.Kind = .normal; | 3303 | var struct_kind: Builder.Type.Structure.Kind = .normal; |
| 3306 | 3304 | ||
| 3307 | var it = struct_obj.runtimeFieldIterator(mod); | 3305 | for (struct_type.runtime_order.get(ip)) |runtime_index| { |
| 3308 | while (it.next()) |field_and_index| { | 3306 | const field_index = runtime_index.toInt() orelse break; |
| 3309 | const field = field_and_index.field; | 3307 | const field_ty = struct_type.field_types.get(ip)[field_index].toType(); |
| 3310 | const field_align = field.alignment(mod, struct_obj.layout); | 3308 | const field_aligns = struct_type.field_aligns.get(ip); |
| 3311 | const field_ty_align = field.ty.abiAlignment(mod); | 3309 | const field_align = mod.structFieldAlignment( |
| 3312 | if (field_align < field_ty_align) struct_kind = .@"packed"; | 3310 | if (field_aligns.len == 0) .none else field_aligns[field_index], |
| 3313 | big_align = @max(big_align, field_align); | 3311 | field_ty, |
| 3312 | struct_type.layout, | ||
| 3313 | ); | ||
| 3314 | const field_ty_align = field_ty.abiAlignment(mod); | ||
| 3315 | if (field_align.compare(.lt, field_ty_align)) struct_kind = .@"packed"; | ||
| 3316 | big_align = big_align.max(field_align); | ||
| 3314 | const prev_offset = offset; | 3317 | const prev_offset = offset; |
| 3315 | offset = std.mem.alignForward(u64, offset, field_align); | 3318 | offset = field_align.forward(offset); |
| 3316 | 3319 | ||
| 3317 | const padding_len = offset - prev_offset; | 3320 | const padding_len = offset - prev_offset; |
| 3318 | if (padding_len > 0) try llvm_field_types.append( | 3321 | if (padding_len > 0) try llvm_field_types.append( |
| ... | @@ -3321,15 +3324,15 @@ pub const Object = struct { | ... | @@ -3321,15 +3324,15 @@ pub const Object = struct { |
| 3321 | ); | 3324 | ); |
| 3322 | try o.struct_field_map.put(o.gpa, .{ | 3325 | try o.struct_field_map.put(o.gpa, .{ |
| 3323 | .struct_ty = t.toIntern(), | 3326 | .struct_ty = t.toIntern(), |
| 3324 | .field_index = field_and_index.index, | 3327 | .field_index = field_index, |
| 3325 | }, @intCast(llvm_field_types.items.len)); | 3328 | }, @intCast(llvm_field_types.items.len)); |
| 3326 | try llvm_field_types.append(o.gpa, try o.lowerType(field.ty)); | 3329 | try llvm_field_types.append(o.gpa, try o.lowerType(field_ty)); |
| 3327 | 3330 | ||
| 3328 | offset += field.ty.abiSize(mod); | 3331 | offset += field_ty.abiSize(mod); |
| 3329 | } | 3332 | } |
| 3330 | { | 3333 | { |
| 3331 | const prev_offset = offset; | 3334 | const prev_offset = offset; |
| 3332 | offset = std.mem.alignForward(u64, offset, big_align); | 3335 | offset = big_align.forward(offset); |
| 3333 | const padding_len = offset - prev_offset; | 3336 | const padding_len = offset - prev_offset; |
| 3334 | if (padding_len > 0) try llvm_field_types.append( | 3337 | if (padding_len > 0) try llvm_field_types.append( |
| 3335 | o.gpa, | 3338 | o.gpa, |
| ... | @@ -3353,7 +3356,7 @@ pub const Object = struct { | ... | @@ -3353,7 +3356,7 @@ pub const Object = struct { |
| 3353 | 3356 | ||
| 3354 | comptime assert(struct_layout_version == 2); | 3357 | comptime assert(struct_layout_version == 2); |
| 3355 | var offset: u64 = 0; | 3358 | var offset: u64 = 0; |
| 3356 | var big_align: u32 = 0; | 3359 | var big_align: InternPool.Alignment = .none; |
| 3357 | 3360 | ||
| 3358 | for ( | 3361 | for ( |
| 3359 | anon_struct_type.types.get(ip), | 3362 | anon_struct_type.types.get(ip), |
| ... | @@ -3363,9 +3366,9 @@ pub const Object = struct { | ... | @@ -3363,9 +3366,9 @@ pub const Object = struct { |
| 3363 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue; | 3366 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue; |
| 3364 | 3367 | ||
| 3365 | const field_align = field_ty.toType().abiAlignment(mod); | 3368 | const field_align = field_ty.toType().abiAlignment(mod); |
| 3366 | big_align = @max(big_align, field_align); | 3369 | big_align = big_align.max(field_align); |
| 3367 | const prev_offset = offset; | 3370 | const prev_offset = offset; |
| 3368 | offset = std.mem.alignForward(u64, offset, field_align); | 3371 | offset = field_align.forward(offset); |
| 3369 | 3372 | ||
| 3370 | const padding_len = offset - prev_offset; | 3373 | const padding_len = offset - prev_offset; |
| 3371 | if (padding_len > 0) try llvm_field_types.append( | 3374 | if (padding_len > 0) try llvm_field_types.append( |
| ... | @@ -3382,7 +3385,7 @@ pub const Object = struct { | ... | @@ -3382,7 +3385,7 @@ pub const Object = struct { |
| 3382 | } | 3385 | } |
| 3383 | { | 3386 | { |
| 3384 | const prev_offset = offset; | 3387 | const prev_offset = offset; |
| 3385 | offset = std.mem.alignForward(u64, offset, big_align); | 3388 | offset = big_align.forward(offset); |
| 3386 | const padding_len = offset - prev_offset; | 3389 | const padding_len = offset - prev_offset; |
| 3387 | if (padding_len > 0) try llvm_field_types.append( | 3390 | if (padding_len > 0) try llvm_field_types.append( |
| 3388 | o.gpa, | 3391 | o.gpa, |
| ... | @@ -3447,7 +3450,7 @@ pub const Object = struct { | ... | @@ -3447,7 +3450,7 @@ pub const Object = struct { |
| 3447 | var llvm_fields: [3]Builder.Type = undefined; | 3450 | var llvm_fields: [3]Builder.Type = undefined; |
| 3448 | var llvm_fields_len: usize = 2; | 3451 | var llvm_fields_len: usize = 2; |
| 3449 | 3452 | ||
| 3450 | if (layout.tag_align >= layout.payload_align) { | 3453 | if (layout.tag_align.compare(.gte, layout.payload_align)) { |
| 3451 | llvm_fields = .{ enum_tag_ty, payload_ty, .none }; | 3454 | llvm_fields = .{ enum_tag_ty, payload_ty, .none }; |
| 3452 | } else { | 3455 | } else { |
| 3453 | llvm_fields = .{ payload_ty, enum_tag_ty, .none }; | 3456 | llvm_fields = .{ payload_ty, enum_tag_ty, .none }; |
| ... | @@ -3687,7 +3690,7 @@ pub const Object = struct { | ... | @@ -3687,7 +3690,7 @@ pub const Object = struct { |
| 3687 | 3690 | ||
| 3688 | var fields: [3]Builder.Type = undefined; | 3691 | var fields: [3]Builder.Type = undefined; |
| 3689 | var vals: [3]Builder.Constant = undefined; | 3692 | var vals: [3]Builder.Constant = undefined; |
| 3690 | if (error_align > payload_align) { | 3693 | if (error_align.compare(.gt, payload_align)) { |
| 3691 | vals[0] = llvm_error_value; | 3694 | vals[0] = llvm_error_value; |
| 3692 | vals[1] = llvm_payload_value; | 3695 | vals[1] = llvm_payload_value; |
| 3693 | } else { | 3696 | } else { |
| ... | @@ -3910,7 +3913,7 @@ pub const Object = struct { | ... | @@ -3910,7 +3913,7 @@ pub const Object = struct { |
| 3910 | comptime assert(struct_layout_version == 2); | 3913 | comptime assert(struct_layout_version == 2); |
| 3911 | var llvm_index: usize = 0; | 3914 | var llvm_index: usize = 0; |
| 3912 | var offset: u64 = 0; | 3915 | var offset: u64 = 0; |
| 3913 | var big_align: u32 = 0; | 3916 | var big_align: InternPool.Alignment = .none; |
| 3914 | var need_unnamed = false; | 3917 | var need_unnamed = false; |
| 3915 | for ( | 3918 | for ( |
| 3916 | tuple.types.get(ip), | 3919 | tuple.types.get(ip), |
| ... | @@ -3921,9 +3924,9 @@ pub const Object = struct { | ... | @@ -3921,9 +3924,9 @@ pub const Object = struct { |
| 3921 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; | 3924 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 3922 | 3925 | ||
| 3923 | const field_align = field_ty.toType().abiAlignment(mod); | 3926 | const field_align = field_ty.toType().abiAlignment(mod); |
| 3924 | big_align = @max(big_align, field_align); | 3927 | big_align = big_align.max(field_align); |
| 3925 | const prev_offset = offset; | 3928 | const prev_offset = offset; |
| 3926 | offset = std.mem.alignForward(u64, offset, field_align); | 3929 | offset = field_align.forward(offset); |
| 3927 | 3930 | ||
| 3928 | const padding_len = offset - prev_offset; | 3931 | const padding_len = offset - prev_offset; |
| 3929 | if (padding_len > 0) { | 3932 | if (padding_len > 0) { |
| ... | @@ -3946,7 +3949,7 @@ pub const Object = struct { | ... | @@ -3946,7 +3949,7 @@ pub const Object = struct { |
| 3946 | } | 3949 | } |
| 3947 | { | 3950 | { |
| 3948 | const prev_offset = offset; | 3951 | const prev_offset = offset; |
| 3949 | offset = std.mem.alignForward(u64, offset, big_align); | 3952 | offset = big_align.forward(offset); |
| 3950 | const padding_len = offset - prev_offset; | 3953 | const padding_len = offset - prev_offset; |
| 3951 | if (padding_len > 0) { | 3954 | if (padding_len > 0) { |
| 3952 | fields[llvm_index] = try o.builder.arrayType(padding_len, .i8); | 3955 | fields[llvm_index] = try o.builder.arrayType(padding_len, .i8); |
| ... | @@ -3963,22 +3966,21 @@ pub const Object = struct { | ... | @@ -3963,22 +3966,21 @@ pub const Object = struct { |
| 3963 | struct_ty, vals); | 3966 | struct_ty, vals); |
| 3964 | }, | 3967 | }, |
| 3965 | .struct_type => |struct_type| { | 3968 | .struct_type => |struct_type| { |
| 3966 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | 3969 | assert(struct_type.haveLayout(ip)); |
| 3967 | assert(struct_obj.haveLayout()); | ||
| 3968 | const struct_ty = try o.lowerType(ty); | 3970 | const struct_ty = try o.lowerType(ty); |
| 3969 | if (struct_obj.layout == .Packed) { | 3971 | if (struct_type.layout == .Packed) { |
| 3970 | comptime assert(Type.packed_struct_layout_version == 2); | 3972 | comptime assert(Type.packed_struct_layout_version == 2); |
| 3971 | var running_int = try o.builder.intConst(struct_ty, 0); | 3973 | var running_int = try o.builder.intConst(struct_ty, 0); |
| 3972 | var running_bits: u16 = 0; | 3974 | var running_bits: u16 = 0; |
| 3973 | for (struct_obj.fields.values(), 0..) |field, field_index| { | 3975 | for (struct_type.field_types.get(ip), 0..) |field_ty, field_index| { |
| 3974 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | 3976 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 3975 | 3977 | ||
| 3976 | const non_int_val = | 3978 | const non_int_val = |
| 3977 | try o.lowerValue((try val.fieldValue(mod, field_index)).toIntern()); | 3979 | try o.lowerValue((try val.fieldValue(mod, field_index)).toIntern()); |
| 3978 | const ty_bit_size: u16 = @intCast(field.ty.bitSize(mod)); | 3980 | const ty_bit_size: u16 = @intCast(field_ty.toType().bitSize(mod)); |
| 3979 | const small_int_ty = try o.builder.intType(ty_bit_size); | 3981 | const small_int_ty = try o.builder.intType(ty_bit_size); |
| 3980 | const small_int_val = try o.builder.castConst( | 3982 | const small_int_val = try o.builder.castConst( |
| 3981 | if (field.ty.isPtrAtRuntime(mod)) .ptrtoint else .bitcast, | 3983 | if (field_ty.toType().isPtrAtRuntime(mod)) .ptrtoint else .bitcast, |
| 3982 | non_int_val, | 3984 | non_int_val, |
| 3983 | small_int_ty, | 3985 | small_int_ty, |
| 3984 | ); | 3986 | ); |
| ... | @@ -4010,15 +4012,19 @@ pub const Object = struct { | ... | @@ -4010,15 +4012,19 @@ pub const Object = struct { |
| 4010 | comptime assert(struct_layout_version == 2); | 4012 | comptime assert(struct_layout_version == 2); |
| 4011 | var llvm_index: usize = 0; | 4013 | var llvm_index: usize = 0; |
| 4012 | var offset: u64 = 0; | 4014 | var offset: u64 = 0; |
| 4013 | var big_align: u32 = 0; | 4015 | var big_align: InternPool.Alignment = .none; |
| 4014 | var need_unnamed = false; | 4016 | var need_unnamed = false; |
| 4015 | var field_it = struct_obj.runtimeFieldIterator(mod); | 4017 | var field_it = struct_type.iterateRuntimeOrder(ip); |
| 4016 | while (field_it.next()) |field_and_index| { | 4018 | while (field_it.next()) |field_index| { |
| 4017 | const field = field_and_index.field; | 4019 | const field_ty = struct_type.field_types.get(ip)[field_index]; |
| 4018 | const field_align = field.alignment(mod, struct_obj.layout); | 4020 | const field_align = mod.structFieldAlignment( |
| 4019 | big_align = @max(big_align, field_align); | 4021 | struct_type.fieldAlign(ip, field_index), |
| 4022 | field_ty.toType(), | ||
| 4023 | struct_type.layout, | ||
| 4024 | ); | ||
| 4025 | big_align = big_align.max(field_align); | ||
| 4020 | const prev_offset = offset; | 4026 | const prev_offset = offset; |
| 4021 | offset = std.mem.alignForward(u64, offset, field_align); | 4027 | offset = field_align.forward(offset); |
| 4022 | 4028 | ||
| 4023 | const padding_len = offset - prev_offset; | 4029 | const padding_len = offset - prev_offset; |
| 4024 | if (padding_len > 0) { | 4030 | if (padding_len > 0) { |
| ... | @@ -4032,18 +4038,18 @@ pub const Object = struct { | ... | @@ -4032,18 +4038,18 @@ pub const Object = struct { |
| 4032 | } | 4038 | } |
| 4033 | 4039 | ||
| 4034 | vals[llvm_index] = try o.lowerValue( | 4040 | vals[llvm_index] = try o.lowerValue( |
| 4035 | (try val.fieldValue(mod, field_and_index.index)).toIntern(), | 4041 | (try val.fieldValue(mod, field_index)).toIntern(), |
| 4036 | ); | 4042 | ); |
| 4037 | fields[llvm_index] = vals[llvm_index].typeOf(&o.builder); | 4043 | fields[llvm_index] = vals[llvm_index].typeOf(&o.builder); |
| 4038 | if (fields[llvm_index] != struct_ty.structFields(&o.builder)[llvm_index]) | 4044 | if (fields[llvm_index] != struct_ty.structFields(&o.builder)[llvm_index]) |
| 4039 | need_unnamed = true; | 4045 | need_unnamed = true; |
| 4040 | llvm_index += 1; | 4046 | llvm_index += 1; |
| 4041 | 4047 | ||
| 4042 | offset += field.ty.abiSize(mod); | 4048 | offset += field_ty.toType().abiSize(mod); |
| 4043 | } | 4049 | } |
| 4044 | { | 4050 | { |
| 4045 | const prev_offset = offset; | 4051 | const prev_offset = offset; |
| 4046 | offset = std.mem.alignForward(u64, offset, big_align); | 4052 | offset = big_align.forward(offset); |
| 4047 | const padding_len = offset - prev_offset; | 4053 | const padding_len = offset - prev_offset; |
| 4048 | if (padding_len > 0) { | 4054 | if (padding_len > 0) { |
| 4049 | fields[llvm_index] = try o.builder.arrayType(padding_len, .i8); | 4055 | fields[llvm_index] = try o.builder.arrayType(padding_len, .i8); |
| ... | @@ -4093,7 +4099,7 @@ pub const Object = struct { | ... | @@ -4093,7 +4099,7 @@ pub const Object = struct { |
| 4093 | const payload = try o.lowerValue(un.val); | 4099 | const payload = try o.lowerValue(un.val); |
| 4094 | const payload_ty = payload.typeOf(&o.builder); | 4100 | const payload_ty = payload.typeOf(&o.builder); |
| 4095 | if (payload_ty != union_ty.structFields(&o.builder)[ | 4101 | if (payload_ty != union_ty.structFields(&o.builder)[ |
| 4096 | @intFromBool(layout.tag_align >= layout.payload_align) | 4102 | @intFromBool(layout.tag_align.compare(.gte, layout.payload_align)) |
| 4097 | ]) need_unnamed = true; | 4103 | ]) need_unnamed = true; |
| 4098 | const field_size = field_ty.abiSize(mod); | 4104 | const field_size = field_ty.abiSize(mod); |
| 4099 | if (field_size == layout.payload_size) break :p payload; | 4105 | if (field_size == layout.payload_size) break :p payload; |
| ... | @@ -4115,7 +4121,7 @@ pub const Object = struct { | ... | @@ -4115,7 +4121,7 @@ pub const Object = struct { |
| 4115 | var fields: [3]Builder.Type = undefined; | 4121 | var fields: [3]Builder.Type = undefined; |
| 4116 | var vals: [3]Builder.Constant = undefined; | 4122 | var vals: [3]Builder.Constant = undefined; |
| 4117 | var len: usize = 2; | 4123 | var len: usize = 2; |
| 4118 | if (layout.tag_align >= layout.payload_align) { | 4124 | if (layout.tag_align.compare(.gte, layout.payload_align)) { |
| 4119 | fields = .{ tag_ty, payload_ty, undefined }; | 4125 | fields = .{ tag_ty, payload_ty, undefined }; |
| 4120 | vals = .{ tag, payload, undefined }; | 4126 | vals = .{ tag, payload, undefined }; |
| 4121 | } else { | 4127 | } else { |
| ... | @@ -4174,14 +4180,15 @@ pub const Object = struct { | ... | @@ -4174,14 +4180,15 @@ pub const Object = struct { |
| 4174 | 4180 | ||
| 4175 | fn lowerParentPtr(o: *Object, ptr_val: Value, byte_aligned: bool) Allocator.Error!Builder.Constant { | 4181 | fn lowerParentPtr(o: *Object, ptr_val: Value, byte_aligned: bool) Allocator.Error!Builder.Constant { |
| 4176 | const mod = o.module; | 4182 | const mod = o.module; |
| 4177 | return switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) { | 4183 | const ip = &mod.intern_pool; |
| 4184 | return switch (ip.indexToKey(ptr_val.toIntern()).ptr.addr) { | ||
| 4178 | .decl => |decl| o.lowerParentPtrDecl(decl), | 4185 | .decl => |decl| o.lowerParentPtrDecl(decl), |
| 4179 | .mut_decl => |mut_decl| o.lowerParentPtrDecl(mut_decl.decl), | 4186 | .mut_decl => |mut_decl| o.lowerParentPtrDecl(mut_decl.decl), |
| 4180 | .int => |int| try o.lowerIntAsPtr(int), | 4187 | .int => |int| try o.lowerIntAsPtr(int), |
| 4181 | .eu_payload => |eu_ptr| { | 4188 | .eu_payload => |eu_ptr| { |
| 4182 | const parent_ptr = try o.lowerParentPtr(eu_ptr.toValue(), true); | 4189 | const parent_ptr = try o.lowerParentPtr(eu_ptr.toValue(), true); |
| 4183 | 4190 | ||
| 4184 | const eu_ty = mod.intern_pool.typeOf(eu_ptr).toType().childType(mod); | 4191 | const eu_ty = ip.typeOf(eu_ptr).toType().childType(mod); |
| 4185 | const payload_ty = eu_ty.errorUnionPayload(mod); | 4192 | const payload_ty = eu_ty.errorUnionPayload(mod); |
| 4186 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | 4193 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 4187 | // In this case, we represent pointer to error union the same as pointer | 4194 | // In this case, we represent pointer to error union the same as pointer |
| ... | @@ -4189,8 +4196,9 @@ pub const Object = struct { | ... | @@ -4189,8 +4196,9 @@ pub const Object = struct { |
| 4189 | return parent_ptr; | 4196 | return parent_ptr; |
| 4190 | } | 4197 | } |
| 4191 | 4198 | ||
| 4192 | const index: u32 = | 4199 | const payload_align = payload_ty.abiAlignment(mod); |
| 4193 | if (payload_ty.abiAlignment(mod) > Type.err_int.abiSize(mod)) 2 else 1; | 4200 | const err_align = Type.err_int.abiAlignment(mod); |
| 4201 | const index: u32 = if (payload_align.compare(.gt, err_align)) 2 else 1; | ||
| 4194 | return o.builder.gepConst(.inbounds, try o.lowerType(eu_ty), parent_ptr, null, &.{ | 4202 | return o.builder.gepConst(.inbounds, try o.lowerType(eu_ty), parent_ptr, null, &.{ |
| 4195 | try o.builder.intConst(.i32, 0), try o.builder.intConst(.i32, index), | 4203 | try o.builder.intConst(.i32, 0), try o.builder.intConst(.i32, index), |
| 4196 | }); | 4204 | }); |
| ... | @@ -4198,7 +4206,7 @@ pub const Object = struct { | ... | @@ -4198,7 +4206,7 @@ pub const Object = struct { |
| 4198 | .opt_payload => |opt_ptr| { | 4206 | .opt_payload => |opt_ptr| { |
| 4199 | const parent_ptr = try o.lowerParentPtr(opt_ptr.toValue(), true); | 4207 | const parent_ptr = try o.lowerParentPtr(opt_ptr.toValue(), true); |
| 4200 | 4208 | ||
| 4201 | const opt_ty = mod.intern_pool.typeOf(opt_ptr).toType().childType(mod); | 4209 | const opt_ty = ip.typeOf(opt_ptr).toType().childType(mod); |
| 4202 | const payload_ty = opt_ty.optionalChild(mod); | 4210 | const payload_ty = opt_ty.optionalChild(mod); |
| 4203 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod) or | 4211 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod) or |
| 4204 | payload_ty.optionalReprIsPayload(mod)) | 4212 | payload_ty.optionalReprIsPayload(mod)) |
| ... | @@ -4215,7 +4223,7 @@ pub const Object = struct { | ... | @@ -4215,7 +4223,7 @@ pub const Object = struct { |
| 4215 | .comptime_field => unreachable, | 4223 | .comptime_field => unreachable, |
| 4216 | .elem => |elem_ptr| { | 4224 | .elem => |elem_ptr| { |
| 4217 | const parent_ptr = try o.lowerParentPtr(elem_ptr.base.toValue(), true); | 4225 | const parent_ptr = try o.lowerParentPtr(elem_ptr.base.toValue(), true); |
| 4218 | const elem_ty = mod.intern_pool.typeOf(elem_ptr.base).toType().elemType2(mod); | 4226 | const elem_ty = ip.typeOf(elem_ptr.base).toType().elemType2(mod); |
| 4219 | 4227 | ||
| 4220 | return o.builder.gepConst(.inbounds, try o.lowerType(elem_ty), parent_ptr, null, &.{ | 4228 | return o.builder.gepConst(.inbounds, try o.lowerType(elem_ty), parent_ptr, null, &.{ |
| 4221 | try o.builder.intConst(try o.lowerType(Type.usize), elem_ptr.index), | 4229 | try o.builder.intConst(try o.lowerType(Type.usize), elem_ptr.index), |
| ... | @@ -4223,7 +4231,7 @@ pub const Object = struct { | ... | @@ -4223,7 +4231,7 @@ pub const Object = struct { |
| 4223 | }, | 4231 | }, |
| 4224 | .field => |field_ptr| { | 4232 | .field => |field_ptr| { |
| 4225 | const parent_ptr = try o.lowerParentPtr(field_ptr.base.toValue(), byte_aligned); | 4233 | const parent_ptr = try o.lowerParentPtr(field_ptr.base.toValue(), byte_aligned); |
| 4226 | const parent_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod); | 4234 | const parent_ty = ip.typeOf(field_ptr.base).toType().childType(mod); |
| 4227 | 4235 | ||
| 4228 | const field_index: u32 = @intCast(field_ptr.index); | 4236 | const field_index: u32 = @intCast(field_ptr.index); |
| 4229 | switch (parent_ty.zigTypeTag(mod)) { | 4237 | switch (parent_ty.zigTypeTag(mod)) { |
| ... | @@ -4241,24 +4249,26 @@ pub const Object = struct { | ... | @@ -4241,24 +4249,26 @@ pub const Object = struct { |
| 4241 | 4249 | ||
| 4242 | const parent_llvm_ty = try o.lowerType(parent_ty); | 4250 | const parent_llvm_ty = try o.lowerType(parent_ty); |
| 4243 | return o.builder.gepConst(.inbounds, parent_llvm_ty, parent_ptr, null, &.{ | 4251 | return o.builder.gepConst(.inbounds, parent_llvm_ty, parent_ptr, null, &.{ |
| 4244 | try o.builder.intConst(.i32, 0), try o.builder.intConst(.i32, @intFromBool( | 4252 | try o.builder.intConst(.i32, 0), |
| 4245 | layout.tag_size > 0 and layout.tag_align >= layout.payload_align, | 4253 | try o.builder.intConst(.i32, @intFromBool( |
| 4254 | layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align), | ||
| 4246 | )), | 4255 | )), |
| 4247 | }); | 4256 | }); |
| 4248 | }, | 4257 | }, |
| 4249 | .Struct => { | 4258 | .Struct => { |
| 4250 | if (parent_ty.containerLayout(mod) == .Packed) { | 4259 | if (mod.typeToPackedStruct(parent_ty)) |struct_type| { |
| 4251 | if (!byte_aligned) return parent_ptr; | 4260 | if (!byte_aligned) return parent_ptr; |
| 4252 | const llvm_usize = try o.lowerType(Type.usize); | 4261 | const llvm_usize = try o.lowerType(Type.usize); |
| 4253 | const base_addr = | 4262 | const base_addr = |
| 4254 | try o.builder.castConst(.ptrtoint, parent_ptr, llvm_usize); | 4263 | try o.builder.castConst(.ptrtoint, parent_ptr, llvm_usize); |
| 4255 | // count bits of fields before this one | 4264 | // count bits of fields before this one |
| 4265 | // TODO https://github.com/ziglang/zig/issues/17178 | ||
| 4256 | const prev_bits = b: { | 4266 | const prev_bits = b: { |
| 4257 | var b: usize = 0; | 4267 | var b: usize = 0; |
| 4258 | for (parent_ty.structFields(mod).values()[0..field_index]) |field| { | 4268 | for (0..field_index) |i| { |
| 4259 | if (field.is_comptime) continue; | 4269 | const field_ty = struct_type.field_types.get(ip)[i].toType(); |
| 4260 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | 4270 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 4261 | b += @intCast(field.ty.bitSize(mod)); | 4271 | b += @intCast(field_ty.bitSize(mod)); |
| 4262 | } | 4272 | } |
| 4263 | break :b b; | 4273 | break :b b; |
| 4264 | }; | 4274 | }; |
| ... | @@ -4407,11 +4417,11 @@ pub const Object = struct { | ... | @@ -4407,11 +4417,11 @@ pub const Object = struct { |
| 4407 | if (ptr_info.flags.is_const) { | 4417 | if (ptr_info.flags.is_const) { |
| 4408 | try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder); | 4418 | try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder); |
| 4409 | } | 4419 | } |
| 4410 | const elem_align = Builder.Alignment.fromByteUnits( | 4420 | const elem_align = if (ptr_info.flags.alignment != .none) |
| 4411 | ptr_info.flags.alignment.toByteUnitsOptional() orelse | 4421 | ptr_info.flags.alignment |
| 4412 | @max(ptr_info.child.toType().abiAlignment(mod), 1), | 4422 | else |
| 4413 | ); | 4423 | ptr_info.child.toType().abiAlignment(mod).max(.@"1"); |
| 4414 | try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder); | 4424 | try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align.toLlvm() }, &o.builder); |
| 4415 | } else if (ccAbiPromoteInt(fn_info.cc, mod, param_ty)) |s| switch (s) { | 4425 | } else if (ccAbiPromoteInt(fn_info.cc, mod, param_ty)) |s| switch (s) { |
| 4416 | .signed => try attributes.addParamAttr(llvm_arg_i, .signext, &o.builder), | 4426 | .signed => try attributes.addParamAttr(llvm_arg_i, .signext, &o.builder), |
| 4417 | .unsigned => try attributes.addParamAttr(llvm_arg_i, .zeroext, &o.builder), | 4427 | .unsigned => try attributes.addParamAttr(llvm_arg_i, .zeroext, &o.builder), |
| ... | @@ -4469,7 +4479,7 @@ pub const DeclGen = struct { | ... | @@ -4469,7 +4479,7 @@ pub const DeclGen = struct { |
| 4469 | } else { | 4479 | } else { |
| 4470 | const variable_index = try o.resolveGlobalDecl(decl_index); | 4480 | const variable_index = try o.resolveGlobalDecl(decl_index); |
| 4471 | variable_index.setAlignment( | 4481 | variable_index.setAlignment( |
| 4472 | Builder.Alignment.fromByteUnits(decl.getAlignment(mod)), | 4482 | decl.getAlignment(mod).toLlvm(), |
| 4473 | &o.builder, | 4483 | &o.builder, |
| 4474 | ); | 4484 | ); |
| 4475 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |section| | 4485 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |section| |
| ... | @@ -4611,9 +4621,7 @@ pub const FuncGen = struct { | ... | @@ -4611,9 +4621,7 @@ pub const FuncGen = struct { |
| 4611 | variable_index.setLinkage(.private, &o.builder); | 4621 | variable_index.setLinkage(.private, &o.builder); |
| 4612 | variable_index.setMutability(.constant, &o.builder); | 4622 | variable_index.setMutability(.constant, &o.builder); |
| 4613 | variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); | 4623 | variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); |
| 4614 | variable_index.setAlignment(Builder.Alignment.fromByteUnits( | 4624 | variable_index.setAlignment(tv.ty.abiAlignment(mod).toLlvm(), &o.builder); |
| 4615 | tv.ty.abiAlignment(mod), | ||
| 4616 | ), &o.builder); | ||
| 4617 | return o.builder.convConst( | 4625 | return o.builder.convConst( |
| 4618 | .unneeded, | 4626 | .unneeded, |
| 4619 | variable_index.toConst(&o.builder), | 4627 | variable_index.toConst(&o.builder), |
| ... | @@ -4929,7 +4937,7 @@ pub const FuncGen = struct { | ... | @@ -4929,7 +4937,7 @@ pub const FuncGen = struct { |
| 4929 | const llvm_ret_ty = try o.lowerType(return_type); | 4937 | const llvm_ret_ty = try o.lowerType(return_type); |
| 4930 | try attributes.addParamAttr(0, .{ .sret = llvm_ret_ty }, &o.builder); | 4938 | try attributes.addParamAttr(0, .{ .sret = llvm_ret_ty }, &o.builder); |
| 4931 | 4939 | ||
| 4932 | const alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod)); | 4940 | const alignment = return_type.abiAlignment(mod).toLlvm(); |
| 4933 | const ret_ptr = try self.buildAlloca(llvm_ret_ty, alignment); | 4941 | const ret_ptr = try self.buildAlloca(llvm_ret_ty, alignment); |
| 4934 | try llvm_args.append(ret_ptr); | 4942 | try llvm_args.append(ret_ptr); |
| 4935 | break :blk ret_ptr; | 4943 | break :blk ret_ptr; |
| ... | @@ -4951,7 +4959,7 @@ pub const FuncGen = struct { | ... | @@ -4951,7 +4959,7 @@ pub const FuncGen = struct { |
| 4951 | const llvm_arg = try self.resolveInst(arg); | 4959 | const llvm_arg = try self.resolveInst(arg); |
| 4952 | const llvm_param_ty = try o.lowerType(param_ty); | 4960 | const llvm_param_ty = try o.lowerType(param_ty); |
| 4953 | if (isByRef(param_ty, mod)) { | 4961 | if (isByRef(param_ty, mod)) { |
| 4954 | const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod)); | 4962 | const alignment = param_ty.abiAlignment(mod).toLlvm(); |
| 4955 | const loaded = try self.wip.load(.normal, llvm_param_ty, llvm_arg, alignment, ""); | 4963 | const loaded = try self.wip.load(.normal, llvm_param_ty, llvm_arg, alignment, ""); |
| 4956 | try llvm_args.append(loaded); | 4964 | try llvm_args.append(loaded); |
| 4957 | } else { | 4965 | } else { |
| ... | @@ -4965,7 +4973,7 @@ pub const FuncGen = struct { | ... | @@ -4965,7 +4973,7 @@ pub const FuncGen = struct { |
| 4965 | if (isByRef(param_ty, mod)) { | 4973 | if (isByRef(param_ty, mod)) { |
| 4966 | try llvm_args.append(llvm_arg); | 4974 | try llvm_args.append(llvm_arg); |
| 4967 | } else { | 4975 | } else { |
| 4968 | const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod)); | 4976 | const alignment = param_ty.abiAlignment(mod).toLlvm(); |
| 4969 | const param_llvm_ty = llvm_arg.typeOfWip(&self.wip); | 4977 | const param_llvm_ty = llvm_arg.typeOfWip(&self.wip); |
| 4970 | const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment); | 4978 | const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment); |
| 4971 | _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment); | 4979 | _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment); |
| ... | @@ -4977,7 +4985,7 @@ pub const FuncGen = struct { | ... | @@ -4977,7 +4985,7 @@ pub const FuncGen = struct { |
| 4977 | const param_ty = self.typeOf(arg); | 4985 | const param_ty = self.typeOf(arg); |
| 4978 | const llvm_arg = try self.resolveInst(arg); | 4986 | const llvm_arg = try self.resolveInst(arg); |
| 4979 | 4987 | ||
| 4980 | const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod)); | 4988 | const alignment = param_ty.abiAlignment(mod).toLlvm(); |
| 4981 | const param_llvm_ty = try o.lowerType(param_ty); | 4989 | const param_llvm_ty = try o.lowerType(param_ty); |
| 4982 | const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment); | 4990 | const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment); |
| 4983 | if (isByRef(param_ty, mod)) { | 4991 | if (isByRef(param_ty, mod)) { |
| ... | @@ -4995,13 +5003,13 @@ pub const FuncGen = struct { | ... | @@ -4995,13 +5003,13 @@ pub const FuncGen = struct { |
| 4995 | const int_llvm_ty = try o.builder.intType(@intCast(param_ty.abiSize(mod) * 8)); | 5003 | const int_llvm_ty = try o.builder.intType(@intCast(param_ty.abiSize(mod) * 8)); |
| 4996 | 5004 | ||
| 4997 | if (isByRef(param_ty, mod)) { | 5005 | if (isByRef(param_ty, mod)) { |
| 4998 | const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod)); | 5006 | const alignment = param_ty.abiAlignment(mod).toLlvm(); |
| 4999 | const loaded = try self.wip.load(.normal, int_llvm_ty, llvm_arg, alignment, ""); | 5007 | const loaded = try self.wip.load(.normal, int_llvm_ty, llvm_arg, alignment, ""); |
| 5000 | try llvm_args.append(loaded); | 5008 | try llvm_args.append(loaded); |
| 5001 | } else { | 5009 | } else { |
| 5002 | // LLVM does not allow bitcasting structs so we must allocate | 5010 | // LLVM does not allow bitcasting structs so we must allocate |
| 5003 | // a local, store as one type, and then load as another type. | 5011 | // a local, store as one type, and then load as another type. |
| 5004 | const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod)); | 5012 | const alignment = param_ty.abiAlignment(mod).toLlvm(); |
| 5005 | const int_ptr = try self.buildAlloca(int_llvm_ty, alignment); | 5013 | const int_ptr = try self.buildAlloca(int_llvm_ty, alignment); |
| 5006 | _ = try self.wip.store(.normal, llvm_arg, int_ptr, alignment); | 5014 | _ = try self.wip.store(.normal, llvm_arg, int_ptr, alignment); |
| 5007 | const loaded = try self.wip.load(.normal, int_llvm_ty, int_ptr, alignment, ""); | 5015 | const loaded = try self.wip.load(.normal, int_llvm_ty, int_ptr, alignment, ""); |
| ... | @@ -5022,7 +5030,7 @@ pub const FuncGen = struct { | ... | @@ -5022,7 +5030,7 @@ pub const FuncGen = struct { |
| 5022 | const llvm_arg = try self.resolveInst(arg); | 5030 | const llvm_arg = try self.resolveInst(arg); |
| 5023 | const is_by_ref = isByRef(param_ty, mod); | 5031 | const is_by_ref = isByRef(param_ty, mod); |
| 5024 | const arg_ptr = if (is_by_ref) llvm_arg else ptr: { | 5032 | const arg_ptr = if (is_by_ref) llvm_arg else ptr: { |
| 5025 | const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod)); | 5033 | const alignment = param_ty.abiAlignment(mod).toLlvm(); |
| 5026 | const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment); | 5034 | const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment); |
| 5027 | _ = try self.wip.store(.normal, llvm_arg, ptr, alignment); | 5035 | _ = try self.wip.store(.normal, llvm_arg, ptr, alignment); |
| 5028 | break :ptr ptr; | 5036 | break :ptr ptr; |
| ... | @@ -5048,7 +5056,7 @@ pub const FuncGen = struct { | ... | @@ -5048,7 +5056,7 @@ pub const FuncGen = struct { |
| 5048 | const arg = args[it.zig_index - 1]; | 5056 | const arg = args[it.zig_index - 1]; |
| 5049 | const arg_ty = self.typeOf(arg); | 5057 | const arg_ty = self.typeOf(arg); |
| 5050 | var llvm_arg = try self.resolveInst(arg); | 5058 | var llvm_arg = try self.resolveInst(arg); |
| 5051 | const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod)); | 5059 | const alignment = arg_ty.abiAlignment(mod).toLlvm(); |
| 5052 | if (!isByRef(arg_ty, mod)) { | 5060 | if (!isByRef(arg_ty, mod)) { |
| 5053 | const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment); | 5061 | const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment); |
| 5054 | _ = try self.wip.store(.normal, llvm_arg, ptr, alignment); | 5062 | _ = try self.wip.store(.normal, llvm_arg, ptr, alignment); |
| ... | @@ -5066,7 +5074,7 @@ pub const FuncGen = struct { | ... | @@ -5066,7 +5074,7 @@ pub const FuncGen = struct { |
| 5066 | const arg = args[it.zig_index - 1]; | 5074 | const arg = args[it.zig_index - 1]; |
| 5067 | const arg_ty = self.typeOf(arg); | 5075 | const arg_ty = self.typeOf(arg); |
| 5068 | var llvm_arg = try self.resolveInst(arg); | 5076 | var llvm_arg = try self.resolveInst(arg); |
| 5069 | const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod)); | 5077 | const alignment = arg_ty.abiAlignment(mod).toLlvm(); |
| 5070 | if (!isByRef(arg_ty, mod)) { | 5078 | if (!isByRef(arg_ty, mod)) { |
| 5071 | const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment); | 5079 | const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment); |
| 5072 | _ = try self.wip.store(.normal, llvm_arg, ptr, alignment); | 5080 | _ = try self.wip.store(.normal, llvm_arg, ptr, alignment); |
| ... | @@ -5097,7 +5105,7 @@ pub const FuncGen = struct { | ... | @@ -5097,7 +5105,7 @@ pub const FuncGen = struct { |
| 5097 | const param_index = it.zig_index - 1; | 5105 | const param_index = it.zig_index - 1; |
| 5098 | const param_ty = fn_info.param_types.get(ip)[param_index].toType(); | 5106 | const param_ty = fn_info.param_types.get(ip)[param_index].toType(); |
| 5099 | const param_llvm_ty = try o.lowerType(param_ty); | 5107 | const param_llvm_ty = try o.lowerType(param_ty); |
| 5100 | const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod)); | 5108 | const alignment = param_ty.abiAlignment(mod).toLlvm(); |
| 5101 | try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty); | 5109 | try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty); |
| 5102 | }, | 5110 | }, |
| 5103 | .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder), | 5111 | .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder), |
| ... | @@ -5128,10 +5136,10 @@ pub const FuncGen = struct { | ... | @@ -5128,10 +5136,10 @@ pub const FuncGen = struct { |
| 5128 | if (ptr_info.flags.is_const) { | 5136 | if (ptr_info.flags.is_const) { |
| 5129 | try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder); | 5137 | try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder); |
| 5130 | } | 5138 | } |
| 5131 | const elem_align = Builder.Alignment.fromByteUnits( | 5139 | const elem_align = (if (ptr_info.flags.alignment != .none) |
| 5132 | ptr_info.flags.alignment.toByteUnitsOptional() orelse | 5140 | @as(InternPool.Alignment, ptr_info.flags.alignment) |
| 5133 | @max(ptr_info.child.toType().abiAlignment(mod), 1), | 5141 | else |
| 5134 | ); | 5142 | ptr_info.child.toType().abiAlignment(mod).max(.@"1")).toLlvm(); |
| 5135 | try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder); | 5143 | try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder); |
| 5136 | }, | 5144 | }, |
| 5137 | }; | 5145 | }; |
| ... | @@ -5166,7 +5174,7 @@ pub const FuncGen = struct { | ... | @@ -5166,7 +5174,7 @@ pub const FuncGen = struct { |
| 5166 | return rp; | 5174 | return rp; |
| 5167 | } else { | 5175 | } else { |
| 5168 | // our by-ref status disagrees with sret so we must load. | 5176 | // our by-ref status disagrees with sret so we must load. |
| 5169 | const return_alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod)); | 5177 | const return_alignment = return_type.abiAlignment(mod).toLlvm(); |
| 5170 | return self.wip.load(.normal, llvm_ret_ty, rp, return_alignment, ""); | 5178 | return self.wip.load(.normal, llvm_ret_ty, rp, return_alignment, ""); |
| 5171 | } | 5179 | } |
| 5172 | } | 5180 | } |
| ... | @@ -5177,7 +5185,7 @@ pub const FuncGen = struct { | ... | @@ -5177,7 +5185,7 @@ pub const FuncGen = struct { |
| 5177 | // In this case the function return type is honoring the calling convention by having | 5185 | // In this case the function return type is honoring the calling convention by having |
| 5178 | // a different LLVM type than the usual one. We solve this here at the callsite | 5186 | // a different LLVM type than the usual one. We solve this here at the callsite |
| 5179 | // by using our canonical type, then loading it if necessary. | 5187 | // by using our canonical type, then loading it if necessary. |
| 5180 | const alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod)); | 5188 | const alignment = return_type.abiAlignment(mod).toLlvm(); |
| 5181 | if (o.builder.useLibLlvm()) | 5189 | if (o.builder.useLibLlvm()) |
| 5182 | assert(o.target_data.abiSizeOfType(abi_ret_ty.toLlvm(&o.builder)) >= | 5190 | assert(o.target_data.abiSizeOfType(abi_ret_ty.toLlvm(&o.builder)) >= |
| 5183 | o.target_data.abiSizeOfType(llvm_ret_ty.toLlvm(&o.builder))); | 5191 | o.target_data.abiSizeOfType(llvm_ret_ty.toLlvm(&o.builder))); |
| ... | @@ -5192,7 +5200,7 @@ pub const FuncGen = struct { | ... | @@ -5192,7 +5200,7 @@ pub const FuncGen = struct { |
| 5192 | if (isByRef(return_type, mod)) { | 5200 | if (isByRef(return_type, mod)) { |
| 5193 | // our by-ref status disagrees with sret so we must allocate, store, | 5201 | // our by-ref status disagrees with sret so we must allocate, store, |
| 5194 | // and return the allocation pointer. | 5202 | // and return the allocation pointer. |
| 5195 | const alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod)); | 5203 | const alignment = return_type.abiAlignment(mod).toLlvm(); |
| 5196 | const rp = try self.buildAlloca(llvm_ret_ty, alignment); | 5204 | const rp = try self.buildAlloca(llvm_ret_ty, alignment); |
| 5197 | _ = try self.wip.store(.normal, call, rp, alignment); | 5205 | _ = try self.wip.store(.normal, call, rp, alignment); |
| 5198 | return rp; | 5206 | return rp; |
| ... | @@ -5266,7 +5274,7 @@ pub const FuncGen = struct { | ... | @@ -5266,7 +5274,7 @@ pub const FuncGen = struct { |
| 5266 | 5274 | ||
| 5267 | const abi_ret_ty = try lowerFnRetTy(o, fn_info); | 5275 | const abi_ret_ty = try lowerFnRetTy(o, fn_info); |
| 5268 | const operand = try self.resolveInst(un_op); | 5276 | const operand = try self.resolveInst(un_op); |
| 5269 | const alignment = Builder.Alignment.fromByteUnits(ret_ty.abiAlignment(mod)); | 5277 | const alignment = ret_ty.abiAlignment(mod).toLlvm(); |
| 5270 | 5278 | ||
| 5271 | if (isByRef(ret_ty, mod)) { | 5279 | if (isByRef(ret_ty, mod)) { |
| 5272 | // operand is a pointer however self.ret_ptr is null so that means | 5280 | // operand is a pointer however self.ret_ptr is null so that means |
| ... | @@ -5311,7 +5319,7 @@ pub const FuncGen = struct { | ... | @@ -5311,7 +5319,7 @@ pub const FuncGen = struct { |
| 5311 | } | 5319 | } |
| 5312 | const ptr = try self.resolveInst(un_op); | 5320 | const ptr = try self.resolveInst(un_op); |
| 5313 | const abi_ret_ty = try lowerFnRetTy(o, fn_info); | 5321 | const abi_ret_ty = try lowerFnRetTy(o, fn_info); |
| 5314 | const alignment = Builder.Alignment.fromByteUnits(ret_ty.abiAlignment(mod)); | 5322 | const alignment = ret_ty.abiAlignment(mod).toLlvm(); |
| 5315 | _ = try self.wip.ret(try self.wip.load(.normal, abi_ret_ty, ptr, alignment, "")); | 5323 | _ = try self.wip.ret(try self.wip.load(.normal, abi_ret_ty, ptr, alignment, "")); |
| 5316 | return .none; | 5324 | return .none; |
| 5317 | } | 5325 | } |
| ... | @@ -5334,7 +5342,7 @@ pub const FuncGen = struct { | ... | @@ -5334,7 +5342,7 @@ pub const FuncGen = struct { |
| 5334 | const llvm_va_list_ty = try o.lowerType(va_list_ty); | 5342 | const llvm_va_list_ty = try o.lowerType(va_list_ty); |
| 5335 | const mod = o.module; | 5343 | const mod = o.module; |
| 5336 | 5344 | ||
| 5337 | const result_alignment = Builder.Alignment.fromByteUnits(va_list_ty.abiAlignment(mod)); | 5345 | const result_alignment = va_list_ty.abiAlignment(mod).toLlvm(); |
| 5338 | const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment); | 5346 | const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment); |
| 5339 | 5347 | ||
| 5340 | _ = try self.wip.callIntrinsic(.normal, .none, .va_copy, &.{}, &.{ dest_list, src_list }, ""); | 5348 | _ = try self.wip.callIntrinsic(.normal, .none, .va_copy, &.{}, &.{ dest_list, src_list }, ""); |
| ... | @@ -5358,7 +5366,7 @@ pub const FuncGen = struct { | ... | @@ -5358,7 +5366,7 @@ pub const FuncGen = struct { |
| 5358 | const va_list_ty = self.typeOfIndex(inst); | 5366 | const va_list_ty = self.typeOfIndex(inst); |
| 5359 | const llvm_va_list_ty = try o.lowerType(va_list_ty); | 5367 | const llvm_va_list_ty = try o.lowerType(va_list_ty); |
| 5360 | 5368 | ||
| 5361 | const result_alignment = Builder.Alignment.fromByteUnits(va_list_ty.abiAlignment(mod)); | 5369 | const result_alignment = va_list_ty.abiAlignment(mod).toLlvm(); |
| 5362 | const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment); | 5370 | const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment); |
| 5363 | 5371 | ||
| 5364 | _ = try self.wip.callIntrinsic(.normal, .none, .va_start, &.{}, &.{dest_list}, ""); | 5372 | _ = try self.wip.callIntrinsic(.normal, .none, .va_start, &.{}, &.{dest_list}, ""); |
| ... | @@ -5690,7 +5698,7 @@ pub const FuncGen = struct { | ... | @@ -5690,7 +5698,7 @@ pub const FuncGen = struct { |
| 5690 | return fg.wip.gepStruct(err_union_llvm_ty, err_union, offset, ""); | 5698 | return fg.wip.gepStruct(err_union_llvm_ty, err_union, offset, ""); |
| 5691 | } else if (isByRef(err_union_ty, mod)) { | 5699 | } else if (isByRef(err_union_ty, mod)) { |
| 5692 | const payload_ptr = try fg.wip.gepStruct(err_union_llvm_ty, err_union, offset, ""); | 5700 | const payload_ptr = try fg.wip.gepStruct(err_union_llvm_ty, err_union, offset, ""); |
| 5693 | const payload_alignment = Builder.Alignment.fromByteUnits(payload_ty.abiAlignment(mod)); | 5701 | const payload_alignment = payload_ty.abiAlignment(mod).toLlvm(); |
| 5694 | if (isByRef(payload_ty, mod)) { | 5702 | if (isByRef(payload_ty, mod)) { |
| 5695 | if (can_elide_load) | 5703 | if (can_elide_load) |
| 5696 | return payload_ptr; | 5704 | return payload_ptr; |
| ... | @@ -5997,7 +6005,7 @@ pub const FuncGen = struct { | ... | @@ -5997,7 +6005,7 @@ pub const FuncGen = struct { |
| 5997 | if (self.canElideLoad(body_tail)) | 6005 | if (self.canElideLoad(body_tail)) |
| 5998 | return ptr; | 6006 | return ptr; |
| 5999 | 6007 | ||
| 6000 | const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod)); | 6008 | const elem_alignment = elem_ty.abiAlignment(mod).toLlvm(); |
| 6001 | return self.loadByRef(ptr, elem_ty, elem_alignment, .normal); | 6009 | return self.loadByRef(ptr, elem_ty, elem_alignment, .normal); |
| 6002 | } | 6010 | } |
| 6003 | 6011 | ||
| ... | @@ -6037,7 +6045,7 @@ pub const FuncGen = struct { | ... | @@ -6037,7 +6045,7 @@ pub const FuncGen = struct { |
| 6037 | const elem_ptr = | 6045 | const elem_ptr = |
| 6038 | try self.wip.gep(.inbounds, array_llvm_ty, array_llvm_val, &indices, ""); | 6046 | try self.wip.gep(.inbounds, array_llvm_ty, array_llvm_val, &indices, ""); |
| 6039 | if (canElideLoad(self, body_tail)) return elem_ptr; | 6047 | if (canElideLoad(self, body_tail)) return elem_ptr; |
| 6040 | const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod)); | 6048 | const elem_alignment = elem_ty.abiAlignment(mod).toLlvm(); |
| 6041 | return self.loadByRef(elem_ptr, elem_ty, elem_alignment, .normal); | 6049 | return self.loadByRef(elem_ptr, elem_ty, elem_alignment, .normal); |
| 6042 | } else { | 6050 | } else { |
| 6043 | const elem_llvm_ty = try o.lowerType(elem_ty); | 6051 | const elem_llvm_ty = try o.lowerType(elem_ty); |
| ... | @@ -6097,7 +6105,7 @@ pub const FuncGen = struct { | ... | @@ -6097,7 +6105,7 @@ pub const FuncGen = struct { |
| 6097 | &.{rhs}, ""); | 6105 | &.{rhs}, ""); |
| 6098 | if (isByRef(elem_ty, mod)) { | 6106 | if (isByRef(elem_ty, mod)) { |
| 6099 | if (self.canElideLoad(body_tail)) return ptr; | 6107 | if (self.canElideLoad(body_tail)) return ptr; |
| 6100 | const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod)); | 6108 | const elem_alignment = elem_ty.abiAlignment(mod).toLlvm(); |
| 6101 | return self.loadByRef(ptr, elem_ty, elem_alignment, .normal); | 6109 | return self.loadByRef(ptr, elem_ty, elem_alignment, .normal); |
| 6102 | } | 6110 | } |
| 6103 | 6111 | ||
| ... | @@ -6163,8 +6171,8 @@ pub const FuncGen = struct { | ... | @@ -6163,8 +6171,8 @@ pub const FuncGen = struct { |
| 6163 | switch (struct_ty.zigTypeTag(mod)) { | 6171 | switch (struct_ty.zigTypeTag(mod)) { |
| 6164 | .Struct => switch (struct_ty.containerLayout(mod)) { | 6172 | .Struct => switch (struct_ty.containerLayout(mod)) { |
| 6165 | .Packed => { | 6173 | .Packed => { |
| 6166 | const struct_obj = mod.typeToStruct(struct_ty).?; | 6174 | const struct_type = mod.typeToStruct(struct_ty).?; |
| 6167 | const bit_offset = struct_obj.packedFieldBitOffset(mod, field_index); | 6175 | const bit_offset = mod.structPackedFieldBitOffset(struct_type, field_index); |
| 6168 | const containing_int = struct_llvm_val; | 6176 | const containing_int = struct_llvm_val; |
| 6169 | const shift_amt = | 6177 | const shift_amt = |
| 6170 | try o.builder.intValue(containing_int.typeOfWip(&self.wip), bit_offset); | 6178 | try o.builder.intValue(containing_int.typeOfWip(&self.wip), bit_offset); |
| ... | @@ -6220,16 +6228,14 @@ pub const FuncGen = struct { | ... | @@ -6220,16 +6228,14 @@ pub const FuncGen = struct { |
| 6220 | const alignment = struct_ty.structFieldAlign(field_index, mod); | 6228 | const alignment = struct_ty.structFieldAlign(field_index, mod); |
| 6221 | const field_ptr_ty = try mod.ptrType(.{ | 6229 | const field_ptr_ty = try mod.ptrType(.{ |
| 6222 | .child = field_ty.toIntern(), | 6230 | .child = field_ty.toIntern(), |
| 6223 | .flags = .{ | 6231 | .flags = .{ .alignment = alignment }, |
| 6224 | .alignment = InternPool.Alignment.fromNonzeroByteUnits(alignment), | ||
| 6225 | }, | ||
| 6226 | }); | 6232 | }); |
| 6227 | if (isByRef(field_ty, mod)) { | 6233 | if (isByRef(field_ty, mod)) { |
| 6228 | if (canElideLoad(self, body_tail)) | 6234 | if (canElideLoad(self, body_tail)) |
| 6229 | return field_ptr; | 6235 | return field_ptr; |
| 6230 | 6236 | ||
| 6231 | assert(alignment != 0); | 6237 | assert(alignment != .none); |
| 6232 | const field_alignment = Builder.Alignment.fromByteUnits(alignment); | 6238 | const field_alignment = alignment.toLlvm(); |
| 6233 | return self.loadByRef(field_ptr, field_ty, field_alignment, .normal); | 6239 | return self.loadByRef(field_ptr, field_ty, field_alignment, .normal); |
| 6234 | } else { | 6240 | } else { |
| 6235 | return self.load(field_ptr, field_ptr_ty); | 6241 | return self.load(field_ptr, field_ptr_ty); |
| ... | @@ -6238,11 +6244,11 @@ pub const FuncGen = struct { | ... | @@ -6238,11 +6244,11 @@ pub const FuncGen = struct { |
| 6238 | .Union => { | 6244 | .Union => { |
| 6239 | const union_llvm_ty = try o.lowerType(struct_ty); | 6245 | const union_llvm_ty = try o.lowerType(struct_ty); |
| 6240 | const layout = struct_ty.unionGetLayout(mod); | 6246 | const layout = struct_ty.unionGetLayout(mod); |
| 6241 | const payload_index = @intFromBool(layout.tag_align >= layout.payload_align); | 6247 | const payload_index = @intFromBool(layout.tag_align.compare(.gte, layout.payload_align)); |
| 6242 | const field_ptr = | 6248 | const field_ptr = |
| 6243 | try self.wip.gepStruct(union_llvm_ty, struct_llvm_val, payload_index, ""); | 6249 | try self.wip.gepStruct(union_llvm_ty, struct_llvm_val, payload_index, ""); |
| 6244 | const llvm_field_ty = try o.lowerType(field_ty); | 6250 | const llvm_field_ty = try o.lowerType(field_ty); |
| 6245 | const payload_alignment = Builder.Alignment.fromByteUnits(layout.payload_align); | 6251 | const payload_alignment = layout.payload_align.toLlvm(); |
| 6246 | if (isByRef(field_ty, mod)) { | 6252 | if (isByRef(field_ty, mod)) { |
| 6247 | if (canElideLoad(self, body_tail)) return field_ptr; | 6253 | if (canElideLoad(self, body_tail)) return field_ptr; |
| 6248 | return self.loadByRef(field_ptr, field_ty, payload_alignment, .normal); | 6254 | return self.loadByRef(field_ptr, field_ty, payload_alignment, .normal); |
| ... | @@ -6457,7 +6463,7 @@ pub const FuncGen = struct { | ... | @@ -6457,7 +6463,7 @@ pub const FuncGen = struct { |
| 6457 | if (isByRef(operand_ty, mod)) { | 6463 | if (isByRef(operand_ty, mod)) { |
| 6458 | _ = dib.insertDeclareAtEnd(operand.toLlvm(&self.wip), di_local_var, debug_loc, insert_block); | 6464 | _ = dib.insertDeclareAtEnd(operand.toLlvm(&self.wip), di_local_var, debug_loc, insert_block); |
| 6459 | } else if (o.module.comp.bin_file.options.optimize_mode == .Debug) { | 6465 | } else if (o.module.comp.bin_file.options.optimize_mode == .Debug) { |
| 6460 | const alignment = Builder.Alignment.fromByteUnits(operand_ty.abiAlignment(mod)); | 6466 | const alignment = operand_ty.abiAlignment(mod).toLlvm(); |
| 6461 | const alloca = try self.buildAlloca(operand.typeOfWip(&self.wip), alignment); | 6467 | const alloca = try self.buildAlloca(operand.typeOfWip(&self.wip), alignment); |
| 6462 | _ = try self.wip.store(.normal, operand, alloca, alignment); | 6468 | _ = try self.wip.store(.normal, operand, alloca, alignment); |
| 6463 | _ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block); | 6469 | _ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block); |
| ... | @@ -6612,7 +6618,7 @@ pub const FuncGen = struct { | ... | @@ -6612,7 +6618,7 @@ pub const FuncGen = struct { |
| 6612 | llvm_param_values[llvm_param_i] = arg_llvm_value; | 6618 | llvm_param_values[llvm_param_i] = arg_llvm_value; |
| 6613 | llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip); | 6619 | llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip); |
| 6614 | } else { | 6620 | } else { |
| 6615 | const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod)); | 6621 | const alignment = arg_ty.abiAlignment(mod).toLlvm(); |
| 6616 | const arg_llvm_ty = try o.lowerType(arg_ty); | 6622 | const arg_llvm_ty = try o.lowerType(arg_ty); |
| 6617 | const load_inst = | 6623 | const load_inst = |
| 6618 | try self.wip.load(.normal, arg_llvm_ty, arg_llvm_value, alignment, ""); | 6624 | try self.wip.load(.normal, arg_llvm_ty, arg_llvm_value, alignment, ""); |
| ... | @@ -6624,7 +6630,7 @@ pub const FuncGen = struct { | ... | @@ -6624,7 +6630,7 @@ pub const FuncGen = struct { |
| 6624 | llvm_param_values[llvm_param_i] = arg_llvm_value; | 6630 | llvm_param_values[llvm_param_i] = arg_llvm_value; |
| 6625 | llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip); | 6631 | llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip); |
| 6626 | } else { | 6632 | } else { |
| 6627 | const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod)); | 6633 | const alignment = arg_ty.abiAlignment(mod).toLlvm(); |
| 6628 | const arg_ptr = try self.buildAlloca(arg_llvm_value.typeOfWip(&self.wip), alignment); | 6634 | const arg_ptr = try self.buildAlloca(arg_llvm_value.typeOfWip(&self.wip), alignment); |
| 6629 | _ = try self.wip.store(.normal, arg_llvm_value, arg_ptr, alignment); | 6635 | _ = try self.wip.store(.normal, arg_llvm_value, arg_ptr, alignment); |
| 6630 | llvm_param_values[llvm_param_i] = arg_ptr; | 6636 | llvm_param_values[llvm_param_i] = arg_ptr; |
| ... | @@ -6676,7 +6682,7 @@ pub const FuncGen = struct { | ... | @@ -6676,7 +6682,7 @@ pub const FuncGen = struct { |
| 6676 | llvm_param_values[llvm_param_i] = llvm_rw_val; | 6682 | llvm_param_values[llvm_param_i] = llvm_rw_val; |
| 6677 | llvm_param_types[llvm_param_i] = llvm_rw_val.typeOfWip(&self.wip); | 6683 | llvm_param_types[llvm_param_i] = llvm_rw_val.typeOfWip(&self.wip); |
| 6678 | } else { | 6684 | } else { |
| 6679 | const alignment = Builder.Alignment.fromByteUnits(rw_ty.abiAlignment(mod)); | 6685 | const alignment = rw_ty.abiAlignment(mod).toLlvm(); |
| 6680 | const loaded = try self.wip.load(.normal, llvm_elem_ty, llvm_rw_val, alignment, ""); | 6686 | const loaded = try self.wip.load(.normal, llvm_elem_ty, llvm_rw_val, alignment, ""); |
| 6681 | llvm_param_values[llvm_param_i] = loaded; | 6687 | llvm_param_values[llvm_param_i] = loaded; |
| 6682 | llvm_param_types[llvm_param_i] = llvm_elem_ty; | 6688 | llvm_param_types[llvm_param_i] = llvm_elem_ty; |
| ... | @@ -6837,7 +6843,7 @@ pub const FuncGen = struct { | ... | @@ -6837,7 +6843,7 @@ pub const FuncGen = struct { |
| 6837 | const output_ptr = try self.resolveInst(output); | 6843 | const output_ptr = try self.resolveInst(output); |
| 6838 | const output_ptr_ty = self.typeOf(output); | 6844 | const output_ptr_ty = self.typeOf(output); |
| 6839 | 6845 | ||
| 6840 | const alignment = Builder.Alignment.fromByteUnits(output_ptr_ty.ptrAlignment(mod)); | 6846 | const alignment = output_ptr_ty.ptrAlignment(mod).toLlvm(); |
| 6841 | _ = try self.wip.store(.normal, output_value, output_ptr, alignment); | 6847 | _ = try self.wip.store(.normal, output_value, output_ptr, alignment); |
| 6842 | } else { | 6848 | } else { |
| 6843 | ret_val = output_value; | 6849 | ret_val = output_value; |
| ... | @@ -7030,7 +7036,7 @@ pub const FuncGen = struct { | ... | @@ -7030,7 +7036,7 @@ pub const FuncGen = struct { |
| 7030 | if (operand_is_ptr) { | 7036 | if (operand_is_ptr) { |
| 7031 | return self.wip.gepStruct(err_union_llvm_ty, operand, offset, ""); | 7037 | return self.wip.gepStruct(err_union_llvm_ty, operand, offset, ""); |
| 7032 | } else if (isByRef(err_union_ty, mod)) { | 7038 | } else if (isByRef(err_union_ty, mod)) { |
| 7033 | const payload_alignment = Builder.Alignment.fromByteUnits(payload_ty.abiAlignment(mod)); | 7039 | const payload_alignment = payload_ty.abiAlignment(mod).toLlvm(); |
| 7034 | const payload_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, offset, ""); | 7040 | const payload_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, offset, ""); |
| 7035 | if (isByRef(payload_ty, mod)) { | 7041 | if (isByRef(payload_ty, mod)) { |
| 7036 | if (self.canElideLoad(body_tail)) return payload_ptr; | 7042 | if (self.canElideLoad(body_tail)) return payload_ptr; |
| ... | @@ -7093,7 +7099,7 @@ pub const FuncGen = struct { | ... | @@ -7093,7 +7099,7 @@ pub const FuncGen = struct { |
| 7093 | } | 7099 | } |
| 7094 | const err_union_llvm_ty = try o.lowerType(err_union_ty); | 7100 | const err_union_llvm_ty = try o.lowerType(err_union_ty); |
| 7095 | { | 7101 | { |
| 7096 | const error_alignment = Builder.Alignment.fromByteUnits(Type.err_int.abiAlignment(mod)); | 7102 | const error_alignment = Type.err_int.abiAlignment(mod).toLlvm(); |
| 7097 | const error_offset = errUnionErrorOffset(payload_ty, mod); | 7103 | const error_offset = errUnionErrorOffset(payload_ty, mod); |
| 7098 | // First set the non-error value. | 7104 | // First set the non-error value. |
| 7099 | const non_null_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, error_offset, ""); | 7105 | const non_null_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, error_offset, ""); |
| ... | @@ -7133,9 +7139,7 @@ pub const FuncGen = struct { | ... | @@ -7133,9 +7139,7 @@ pub const FuncGen = struct { |
| 7133 | const field_ty = struct_ty.structFieldType(field_index, mod); | 7139 | const field_ty = struct_ty.structFieldType(field_index, mod); |
| 7134 | const field_ptr_ty = try mod.ptrType(.{ | 7140 | const field_ptr_ty = try mod.ptrType(.{ |
| 7135 | .child = field_ty.toIntern(), | 7141 | .child = field_ty.toIntern(), |
| 7136 | .flags = .{ | 7142 | .flags = .{ .alignment = field_alignment }, |
| 7137 | .alignment = InternPool.Alignment.fromNonzeroByteUnits(field_alignment), | ||
| 7138 | }, | ||
| 7139 | }); | 7143 | }); |
| 7140 | return self.load(field_ptr, field_ptr_ty); | 7144 | return self.load(field_ptr, field_ptr_ty); |
| 7141 | } | 7145 | } |
| ... | @@ -7153,7 +7157,7 @@ pub const FuncGen = struct { | ... | @@ -7153,7 +7157,7 @@ pub const FuncGen = struct { |
| 7153 | if (optional_ty.optionalReprIsPayload(mod)) return operand; | 7157 | if (optional_ty.optionalReprIsPayload(mod)) return operand; |
| 7154 | const llvm_optional_ty = try o.lowerType(optional_ty); | 7158 | const llvm_optional_ty = try o.lowerType(optional_ty); |
| 7155 | if (isByRef(optional_ty, mod)) { | 7159 | if (isByRef(optional_ty, mod)) { |
| 7156 | const alignment = Builder.Alignment.fromByteUnits(optional_ty.abiAlignment(mod)); | 7160 | const alignment = optional_ty.abiAlignment(mod).toLlvm(); |
| 7157 | const optional_ptr = try self.buildAlloca(llvm_optional_ty, alignment); | 7161 | const optional_ptr = try self.buildAlloca(llvm_optional_ty, alignment); |
| 7158 | const payload_ptr = try self.wip.gepStruct(llvm_optional_ty, optional_ptr, 0, ""); | 7162 | const payload_ptr = try self.wip.gepStruct(llvm_optional_ty, optional_ptr, 0, ""); |
| 7159 | const payload_ptr_ty = try mod.singleMutPtrType(payload_ty); | 7163 | const payload_ptr_ty = try mod.singleMutPtrType(payload_ty); |
| ... | @@ -7181,10 +7185,10 @@ pub const FuncGen = struct { | ... | @@ -7181,10 +7185,10 @@ pub const FuncGen = struct { |
| 7181 | const payload_offset = errUnionPayloadOffset(payload_ty, mod); | 7185 | const payload_offset = errUnionPayloadOffset(payload_ty, mod); |
| 7182 | const error_offset = errUnionErrorOffset(payload_ty, mod); | 7186 | const error_offset = errUnionErrorOffset(payload_ty, mod); |
| 7183 | if (isByRef(err_un_ty, mod)) { | 7187 | if (isByRef(err_un_ty, mod)) { |
| 7184 | const alignment = Builder.Alignment.fromByteUnits(err_un_ty.abiAlignment(mod)); | 7188 | const alignment = err_un_ty.abiAlignment(mod).toLlvm(); |
| 7185 | const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment); | 7189 | const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment); |
| 7186 | const err_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, error_offset, ""); | 7190 | const err_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, error_offset, ""); |
| 7187 | const error_alignment = Builder.Alignment.fromByteUnits(Type.err_int.abiAlignment(mod)); | 7191 | const error_alignment = Type.err_int.abiAlignment(mod).toLlvm(); |
| 7188 | _ = try self.wip.store(.normal, ok_err_code, err_ptr, error_alignment); | 7192 | _ = try self.wip.store(.normal, ok_err_code, err_ptr, error_alignment); |
| 7189 | const payload_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, payload_offset, ""); | 7193 | const payload_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, payload_offset, ""); |
| 7190 | const payload_ptr_ty = try mod.singleMutPtrType(payload_ty); | 7194 | const payload_ptr_ty = try mod.singleMutPtrType(payload_ty); |
| ... | @@ -7210,10 +7214,10 @@ pub const FuncGen = struct { | ... | @@ -7210,10 +7214,10 @@ pub const FuncGen = struct { |
| 7210 | const payload_offset = errUnionPayloadOffset(payload_ty, mod); | 7214 | const payload_offset = errUnionPayloadOffset(payload_ty, mod); |
| 7211 | const error_offset = errUnionErrorOffset(payload_ty, mod); | 7215 | const error_offset = errUnionErrorOffset(payload_ty, mod); |
| 7212 | if (isByRef(err_un_ty, mod)) { | 7216 | if (isByRef(err_un_ty, mod)) { |
| 7213 | const alignment = Builder.Alignment.fromByteUnits(err_un_ty.abiAlignment(mod)); | 7217 | const alignment = err_un_ty.abiAlignment(mod).toLlvm(); |
| 7214 | const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment); | 7218 | const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment); |
| 7215 | const err_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, error_offset, ""); | 7219 | const err_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, error_offset, ""); |
| 7216 | const error_alignment = Builder.Alignment.fromByteUnits(Type.err_int.abiAlignment(mod)); | 7220 | const error_alignment = Type.err_int.abiAlignment(mod).toLlvm(); |
| 7217 | _ = try self.wip.store(.normal, operand, err_ptr, error_alignment); | 7221 | _ = try self.wip.store(.normal, operand, err_ptr, error_alignment); |
| 7218 | const payload_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, payload_offset, ""); | 7222 | const payload_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, payload_offset, ""); |
| 7219 | const payload_ptr_ty = try mod.singleMutPtrType(payload_ty); | 7223 | const payload_ptr_ty = try mod.singleMutPtrType(payload_ty); |
| ... | @@ -7260,7 +7264,7 @@ pub const FuncGen = struct { | ... | @@ -7260,7 +7264,7 @@ pub const FuncGen = struct { |
| 7260 | const access_kind: Builder.MemoryAccessKind = | 7264 | const access_kind: Builder.MemoryAccessKind = |
| 7261 | if (vector_ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal; | 7265 | if (vector_ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal; |
| 7262 | const elem_llvm_ty = try o.lowerType(vector_ptr_ty.childType(mod)); | 7266 | const elem_llvm_ty = try o.lowerType(vector_ptr_ty.childType(mod)); |
| 7263 | const alignment = Builder.Alignment.fromByteUnits(vector_ptr_ty.ptrAlignment(mod)); | 7267 | const alignment = vector_ptr_ty.ptrAlignment(mod).toLlvm(); |
| 7264 | const loaded = try self.wip.load(access_kind, elem_llvm_ty, vector_ptr, alignment, ""); | 7268 | const loaded = try self.wip.load(access_kind, elem_llvm_ty, vector_ptr, alignment, ""); |
| 7265 | 7269 | ||
| 7266 | const new_vector = try self.wip.insertElement(loaded, operand, index, ""); | 7270 | const new_vector = try self.wip.insertElement(loaded, operand, index, ""); |
| ... | @@ -7690,7 +7694,7 @@ pub const FuncGen = struct { | ... | @@ -7690,7 +7694,7 @@ pub const FuncGen = struct { |
| 7690 | const overflow_index = o.llvmFieldIndex(inst_ty, 1).?; | 7694 | const overflow_index = o.llvmFieldIndex(inst_ty, 1).?; |
| 7691 | 7695 | ||
| 7692 | if (isByRef(inst_ty, mod)) { | 7696 | if (isByRef(inst_ty, mod)) { |
| 7693 | const result_alignment = Builder.Alignment.fromByteUnits(inst_ty.abiAlignment(mod)); | 7697 | const result_alignment = inst_ty.abiAlignment(mod).toLlvm(); |
| 7694 | const alloca_inst = try self.buildAlloca(llvm_inst_ty, result_alignment); | 7698 | const alloca_inst = try self.buildAlloca(llvm_inst_ty, result_alignment); |
| 7695 | { | 7699 | { |
| 7696 | const field_ptr = try self.wip.gepStruct(llvm_inst_ty, alloca_inst, result_index, ""); | 7700 | const field_ptr = try self.wip.gepStruct(llvm_inst_ty, alloca_inst, result_index, ""); |
| ... | @@ -8048,7 +8052,7 @@ pub const FuncGen = struct { | ... | @@ -8048,7 +8052,7 @@ pub const FuncGen = struct { |
| 8048 | const overflow_index = o.llvmFieldIndex(dest_ty, 1).?; | 8052 | const overflow_index = o.llvmFieldIndex(dest_ty, 1).?; |
| 8049 | 8053 | ||
| 8050 | if (isByRef(dest_ty, mod)) { | 8054 | if (isByRef(dest_ty, mod)) { |
| 8051 | const result_alignment = Builder.Alignment.fromByteUnits(dest_ty.abiAlignment(mod)); | 8055 | const result_alignment = dest_ty.abiAlignment(mod).toLlvm(); |
| 8052 | const alloca_inst = try self.buildAlloca(llvm_dest_ty, result_alignment); | 8056 | const alloca_inst = try self.buildAlloca(llvm_dest_ty, result_alignment); |
| 8053 | { | 8057 | { |
| 8054 | const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, result_index, ""); | 8058 | const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, result_index, ""); |
| ... | @@ -8321,7 +8325,7 @@ pub const FuncGen = struct { | ... | @@ -8321,7 +8325,7 @@ pub const FuncGen = struct { |
| 8321 | const array_ptr = try self.buildAlloca(llvm_dest_ty, .default); | 8325 | const array_ptr = try self.buildAlloca(llvm_dest_ty, .default); |
| 8322 | const bitcast_ok = elem_ty.bitSize(mod) == elem_ty.abiSize(mod) * 8; | 8326 | const bitcast_ok = elem_ty.bitSize(mod) == elem_ty.abiSize(mod) * 8; |
| 8323 | if (bitcast_ok) { | 8327 | if (bitcast_ok) { |
| 8324 | const alignment = Builder.Alignment.fromByteUnits(inst_ty.abiAlignment(mod)); | 8328 | const alignment = inst_ty.abiAlignment(mod).toLlvm(); |
| 8325 | _ = try self.wip.store(.normal, operand, array_ptr, alignment); | 8329 | _ = try self.wip.store(.normal, operand, array_ptr, alignment); |
| 8326 | } else { | 8330 | } else { |
| 8327 | // If the ABI size of the element type is not evenly divisible by size in bits; | 8331 | // If the ABI size of the element type is not evenly divisible by size in bits; |
| ... | @@ -8349,7 +8353,7 @@ pub const FuncGen = struct { | ... | @@ -8349,7 +8353,7 @@ pub const FuncGen = struct { |
| 8349 | if (bitcast_ok) { | 8353 | if (bitcast_ok) { |
| 8350 | // The array is aligned to the element's alignment, while the vector might have a completely | 8354 | // The array is aligned to the element's alignment, while the vector might have a completely |
| 8351 | // different alignment. This means we need to enforce the alignment of this load. | 8355 | // different alignment. This means we need to enforce the alignment of this load. |
| 8352 | const alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod)); | 8356 | const alignment = elem_ty.abiAlignment(mod).toLlvm(); |
| 8353 | return self.wip.load(.normal, llvm_vector_ty, operand, alignment, ""); | 8357 | return self.wip.load(.normal, llvm_vector_ty, operand, alignment, ""); |
| 8354 | } else { | 8358 | } else { |
| 8355 | // If the ABI size of the element type is not evenly divisible by size in bits; | 8359 | // If the ABI size of the element type is not evenly divisible by size in bits; |
| ... | @@ -8374,14 +8378,12 @@ pub const FuncGen = struct { | ... | @@ -8374,14 +8378,12 @@ pub const FuncGen = struct { |
| 8374 | } | 8378 | } |
| 8375 | 8379 | ||
| 8376 | if (operand_is_ref) { | 8380 | if (operand_is_ref) { |
| 8377 | const alignment = Builder.Alignment.fromByteUnits(operand_ty.abiAlignment(mod)); | 8381 | const alignment = operand_ty.abiAlignment(mod).toLlvm(); |
| 8378 | return self.wip.load(.normal, llvm_dest_ty, operand, alignment, ""); | 8382 | return self.wip.load(.normal, llvm_dest_ty, operand, alignment, ""); |
| 8379 | } | 8383 | } |
| 8380 | 8384 | ||
| 8381 | if (result_is_ref) { | 8385 | if (result_is_ref) { |
| 8382 | const alignment = Builder.Alignment.fromByteUnits( | 8386 | const alignment = operand_ty.abiAlignment(mod).max(inst_ty.abiAlignment(mod)).toLlvm(); |
| 8383 | @max(operand_ty.abiAlignment(mod), inst_ty.abiAlignment(mod)), | ||
| 8384 | ); | ||
| 8385 | const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment); | 8387 | const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment); |
| 8386 | _ = try self.wip.store(.normal, operand, result_ptr, alignment); | 8388 | _ = try self.wip.store(.normal, operand, result_ptr, alignment); |
| 8387 | return result_ptr; | 8389 | return result_ptr; |
| ... | @@ -8393,9 +8395,7 @@ pub const FuncGen = struct { | ... | @@ -8393,9 +8395,7 @@ pub const FuncGen = struct { |
| 8393 | // Both our operand and our result are values, not pointers, | 8395 | // Both our operand and our result are values, not pointers, |
| 8394 | // but LLVM won't let us bitcast struct values or vectors with padding bits. | 8396 | // but LLVM won't let us bitcast struct values or vectors with padding bits. |
| 8395 | // Therefore, we store operand to alloca, then load for result. | 8397 | // Therefore, we store operand to alloca, then load for result. |
| 8396 | const alignment = Builder.Alignment.fromByteUnits( | 8398 | const alignment = operand_ty.abiAlignment(mod).max(inst_ty.abiAlignment(mod)).toLlvm(); |
| 8397 | @max(operand_ty.abiAlignment(mod), inst_ty.abiAlignment(mod)), | ||
| 8398 | ); | ||
| 8399 | const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment); | 8399 | const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment); |
| 8400 | _ = try self.wip.store(.normal, operand, result_ptr, alignment); | 8400 | _ = try self.wip.store(.normal, operand, result_ptr, alignment); |
| 8401 | return self.wip.load(.normal, llvm_dest_ty, result_ptr, alignment, ""); | 8401 | return self.wip.load(.normal, llvm_dest_ty, result_ptr, alignment, ""); |
| ... | @@ -8441,7 +8441,7 @@ pub const FuncGen = struct { | ... | @@ -8441,7 +8441,7 @@ pub const FuncGen = struct { |
| 8441 | if (isByRef(inst_ty, mod)) { | 8441 | if (isByRef(inst_ty, mod)) { |
| 8442 | _ = dib.insertDeclareAtEnd(arg_val.toLlvm(&self.wip), di_local_var, debug_loc, insert_block); | 8442 | _ = dib.insertDeclareAtEnd(arg_val.toLlvm(&self.wip), di_local_var, debug_loc, insert_block); |
| 8443 | } else if (o.module.comp.bin_file.options.optimize_mode == .Debug) { | 8443 | } else if (o.module.comp.bin_file.options.optimize_mode == .Debug) { |
| 8444 | const alignment = Builder.Alignment.fromByteUnits(inst_ty.abiAlignment(mod)); | 8444 | const alignment = inst_ty.abiAlignment(mod).toLlvm(); |
| 8445 | const alloca = try self.buildAlloca(arg_val.typeOfWip(&self.wip), alignment); | 8445 | const alloca = try self.buildAlloca(arg_val.typeOfWip(&self.wip), alignment); |
| 8446 | _ = try self.wip.store(.normal, arg_val, alloca, alignment); | 8446 | _ = try self.wip.store(.normal, arg_val, alloca, alignment); |
| 8447 | _ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block); | 8447 | _ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block); |
| ... | @@ -8462,7 +8462,7 @@ pub const FuncGen = struct { | ... | @@ -8462,7 +8462,7 @@ pub const FuncGen = struct { |
| 8462 | return (try o.lowerPtrToVoid(ptr_ty)).toValue(); | 8462 | return (try o.lowerPtrToVoid(ptr_ty)).toValue(); |
| 8463 | 8463 | ||
| 8464 | const pointee_llvm_ty = try o.lowerType(pointee_type); | 8464 | const pointee_llvm_ty = try o.lowerType(pointee_type); |
| 8465 | const alignment = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod)); | 8465 | const alignment = ptr_ty.ptrAlignment(mod).toLlvm(); |
| 8466 | return self.buildAlloca(pointee_llvm_ty, alignment); | 8466 | return self.buildAlloca(pointee_llvm_ty, alignment); |
| 8467 | } | 8467 | } |
| 8468 | 8468 | ||
| ... | @@ -8475,7 +8475,7 @@ pub const FuncGen = struct { | ... | @@ -8475,7 +8475,7 @@ pub const FuncGen = struct { |
| 8475 | return (try o.lowerPtrToVoid(ptr_ty)).toValue(); | 8475 | return (try o.lowerPtrToVoid(ptr_ty)).toValue(); |
| 8476 | if (self.ret_ptr != .none) return self.ret_ptr; | 8476 | if (self.ret_ptr != .none) return self.ret_ptr; |
| 8477 | const ret_llvm_ty = try o.lowerType(ret_ty); | 8477 | const ret_llvm_ty = try o.lowerType(ret_ty); |
| 8478 | const alignment = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod)); | 8478 | const alignment = ptr_ty.ptrAlignment(mod).toLlvm(); |
| 8479 | return self.buildAlloca(ret_llvm_ty, alignment); | 8479 | return self.buildAlloca(ret_llvm_ty, alignment); |
| 8480 | } | 8480 | } |
| 8481 | 8481 | ||
| ... | @@ -8515,7 +8515,7 @@ pub const FuncGen = struct { | ... | @@ -8515,7 +8515,7 @@ pub const FuncGen = struct { |
| 8515 | const len = try o.builder.intValue(try o.lowerType(Type.usize), operand_ty.abiSize(mod)); | 8515 | const len = try o.builder.intValue(try o.lowerType(Type.usize), operand_ty.abiSize(mod)); |
| 8516 | _ = try self.wip.callMemSet( | 8516 | _ = try self.wip.callMemSet( |
| 8517 | dest_ptr, | 8517 | dest_ptr, |
| 8518 | Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod)), | 8518 | ptr_ty.ptrAlignment(mod).toLlvm(), |
| 8519 | if (safety) try o.builder.intValue(.i8, 0xaa) else try o.builder.undefValue(.i8), | 8519 | if (safety) try o.builder.intValue(.i8, 0xaa) else try o.builder.undefValue(.i8), |
| 8520 | len, | 8520 | len, |
| 8521 | if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal, | 8521 | if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal, |
| ... | @@ -8646,7 +8646,7 @@ pub const FuncGen = struct { | ... | @@ -8646,7 +8646,7 @@ pub const FuncGen = struct { |
| 8646 | self.sync_scope, | 8646 | self.sync_scope, |
| 8647 | toLlvmAtomicOrdering(extra.successOrder()), | 8647 | toLlvmAtomicOrdering(extra.successOrder()), |
| 8648 | toLlvmAtomicOrdering(extra.failureOrder()), | 8648 | toLlvmAtomicOrdering(extra.failureOrder()), |
| 8649 | Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod)), | 8649 | ptr_ty.ptrAlignment(mod).toLlvm(), |
| 8650 | "", | 8650 | "", |
| 8651 | ); | 8651 | ); |
| 8652 | 8652 | ||
| ... | @@ -8685,7 +8685,7 @@ pub const FuncGen = struct { | ... | @@ -8685,7 +8685,7 @@ pub const FuncGen = struct { |
| 8685 | 8685 | ||
| 8686 | const access_kind: Builder.MemoryAccessKind = | 8686 | const access_kind: Builder.MemoryAccessKind = |
| 8687 | if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal; | 8687 | if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal; |
| 8688 | const ptr_alignment = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod)); | 8688 | const ptr_alignment = ptr_ty.ptrAlignment(mod).toLlvm(); |
| 8689 | 8689 | ||
| 8690 | if (llvm_abi_ty != .none) { | 8690 | if (llvm_abi_ty != .none) { |
| 8691 | // operand needs widening and truncating or bitcasting. | 8691 | // operand needs widening and truncating or bitcasting. |
| ... | @@ -8741,9 +8741,10 @@ pub const FuncGen = struct { | ... | @@ -8741,9 +8741,10 @@ pub const FuncGen = struct { |
| 8741 | if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none; | 8741 | if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none; |
| 8742 | const ordering = toLlvmAtomicOrdering(atomic_load.order); | 8742 | const ordering = toLlvmAtomicOrdering(atomic_load.order); |
| 8743 | const llvm_abi_ty = try o.getAtomicAbiType(elem_ty, false); | 8743 | const llvm_abi_ty = try o.getAtomicAbiType(elem_ty, false); |
| 8744 | const ptr_alignment = Builder.Alignment.fromByteUnits( | 8744 | const ptr_alignment = (if (info.flags.alignment != .none) |
| 8745 | info.flags.alignment.toByteUnitsOptional() orelse info.child.toType().abiAlignment(mod), | 8745 | @as(InternPool.Alignment, info.flags.alignment) |
| 8746 | ); | 8746 | else |
| 8747 | info.child.toType().abiAlignment(mod)).toLlvm(); | ||
| 8747 | const access_kind: Builder.MemoryAccessKind = | 8748 | const access_kind: Builder.MemoryAccessKind = |
| 8748 | if (info.flags.is_volatile) .@"volatile" else .normal; | 8749 | if (info.flags.is_volatile) .@"volatile" else .normal; |
| 8749 | const elem_llvm_ty = try o.lowerType(elem_ty); | 8750 | const elem_llvm_ty = try o.lowerType(elem_ty); |
| ... | @@ -8807,7 +8808,7 @@ pub const FuncGen = struct { | ... | @@ -8807,7 +8808,7 @@ pub const FuncGen = struct { |
| 8807 | const dest_slice = try self.resolveInst(bin_op.lhs); | 8808 | const dest_slice = try self.resolveInst(bin_op.lhs); |
| 8808 | const ptr_ty = self.typeOf(bin_op.lhs); | 8809 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 8809 | const elem_ty = self.typeOf(bin_op.rhs); | 8810 | const elem_ty = self.typeOf(bin_op.rhs); |
| 8810 | const dest_ptr_align = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod)); | 8811 | const dest_ptr_align = ptr_ty.ptrAlignment(mod).toLlvm(); |
| 8811 | const dest_ptr = try self.sliceOrArrayPtr(dest_slice, ptr_ty); | 8812 | const dest_ptr = try self.sliceOrArrayPtr(dest_slice, ptr_ty); |
| 8812 | const access_kind: Builder.MemoryAccessKind = | 8813 | const access_kind: Builder.MemoryAccessKind = |
| 8813 | if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal; | 8814 | if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal; |
| ... | @@ -8911,15 +8912,13 @@ pub const FuncGen = struct { | ... | @@ -8911,15 +8912,13 @@ pub const FuncGen = struct { |
| 8911 | 8912 | ||
| 8912 | self.wip.cursor = .{ .block = body_block }; | 8913 | self.wip.cursor = .{ .block = body_block }; |
| 8913 | const elem_abi_align = elem_ty.abiAlignment(mod); | 8914 | const elem_abi_align = elem_ty.abiAlignment(mod); |
| 8914 | const it_ptr_align = Builder.Alignment.fromByteUnits( | 8915 | const it_ptr_align = InternPool.Alignment.fromLlvm(dest_ptr_align).min(elem_abi_align).toLlvm(); |
| 8915 | @min(elem_abi_align, dest_ptr_align.toByteUnits() orelse std.math.maxInt(u64)), | ||
| 8916 | ); | ||
| 8917 | if (isByRef(elem_ty, mod)) { | 8916 | if (isByRef(elem_ty, mod)) { |
| 8918 | _ = try self.wip.callMemCpy( | 8917 | _ = try self.wip.callMemCpy( |
| 8919 | it_ptr.toValue(), | 8918 | it_ptr.toValue(), |
| 8920 | it_ptr_align, | 8919 | it_ptr_align, |
| 8921 | value, | 8920 | value, |
| 8922 | Builder.Alignment.fromByteUnits(elem_abi_align), | 8921 | elem_abi_align.toLlvm(), |
| 8923 | try o.builder.intValue(llvm_usize_ty, elem_abi_size), | 8922 | try o.builder.intValue(llvm_usize_ty, elem_abi_size), |
| 8924 | access_kind, | 8923 | access_kind, |
| 8925 | ); | 8924 | ); |
| ... | @@ -8985,9 +8984,9 @@ pub const FuncGen = struct { | ... | @@ -8985,9 +8984,9 @@ pub const FuncGen = struct { |
| 8985 | self.wip.cursor = .{ .block = memcpy_block }; | 8984 | self.wip.cursor = .{ .block = memcpy_block }; |
| 8986 | _ = try self.wip.callMemCpy( | 8985 | _ = try self.wip.callMemCpy( |
| 8987 | dest_ptr, | 8986 | dest_ptr, |
| 8988 | Builder.Alignment.fromByteUnits(dest_ptr_ty.ptrAlignment(mod)), | 8987 | dest_ptr_ty.ptrAlignment(mod).toLlvm(), |
| 8989 | src_ptr, | 8988 | src_ptr, |
| 8990 | Builder.Alignment.fromByteUnits(src_ptr_ty.ptrAlignment(mod)), | 8989 | src_ptr_ty.ptrAlignment(mod).toLlvm(), |
| 8991 | len, | 8990 | len, |
| 8992 | access_kind, | 8991 | access_kind, |
| 8993 | ); | 8992 | ); |
| ... | @@ -8998,9 +8997,9 @@ pub const FuncGen = struct { | ... | @@ -8998,9 +8997,9 @@ pub const FuncGen = struct { |
| 8998 | 8997 | ||
| 8999 | _ = try self.wip.callMemCpy( | 8998 | _ = try self.wip.callMemCpy( |
| 9000 | dest_ptr, | 8999 | dest_ptr, |
| 9001 | Builder.Alignment.fromByteUnits(dest_ptr_ty.ptrAlignment(mod)), | 9000 | dest_ptr_ty.ptrAlignment(mod).toLlvm(), |
| 9002 | src_ptr, | 9001 | src_ptr, |
| 9003 | Builder.Alignment.fromByteUnits(src_ptr_ty.ptrAlignment(mod)), | 9002 | src_ptr_ty.ptrAlignment(mod).toLlvm(), |
| 9004 | len, | 9003 | len, |
| 9005 | access_kind, | 9004 | access_kind, |
| 9006 | ); | 9005 | ); |
| ... | @@ -9021,7 +9020,7 @@ pub const FuncGen = struct { | ... | @@ -9021,7 +9020,7 @@ pub const FuncGen = struct { |
| 9021 | _ = try self.wip.store(.normal, new_tag, union_ptr, .default); | 9020 | _ = try self.wip.store(.normal, new_tag, union_ptr, .default); |
| 9022 | return .none; | 9021 | return .none; |
| 9023 | } | 9022 | } |
| 9024 | const tag_index = @intFromBool(layout.tag_align < layout.payload_align); | 9023 | const tag_index = @intFromBool(layout.tag_align.compare(.lt, layout.payload_align)); |
| 9025 | const tag_field_ptr = try self.wip.gepStruct(try o.lowerType(un_ty), union_ptr, tag_index, ""); | 9024 | const tag_field_ptr = try self.wip.gepStruct(try o.lowerType(un_ty), union_ptr, tag_index, ""); |
| 9026 | // TODO alignment on this store | 9025 | // TODO alignment on this store |
| 9027 | _ = try self.wip.store(.normal, new_tag, tag_field_ptr, .default); | 9026 | _ = try self.wip.store(.normal, new_tag, tag_field_ptr, .default); |
| ... | @@ -9040,13 +9039,13 @@ pub const FuncGen = struct { | ... | @@ -9040,13 +9039,13 @@ pub const FuncGen = struct { |
| 9040 | const llvm_un_ty = try o.lowerType(un_ty); | 9039 | const llvm_un_ty = try o.lowerType(un_ty); |
| 9041 | if (layout.payload_size == 0) | 9040 | if (layout.payload_size == 0) |
| 9042 | return self.wip.load(.normal, llvm_un_ty, union_handle, .default, ""); | 9041 | return self.wip.load(.normal, llvm_un_ty, union_handle, .default, ""); |
| 9043 | const tag_index = @intFromBool(layout.tag_align < layout.payload_align); | 9042 | const tag_index = @intFromBool(layout.tag_align.compare(.lt, layout.payload_align)); |
| 9044 | const tag_field_ptr = try self.wip.gepStruct(llvm_un_ty, union_handle, tag_index, ""); | 9043 | const tag_field_ptr = try self.wip.gepStruct(llvm_un_ty, union_handle, tag_index, ""); |
| 9045 | const llvm_tag_ty = llvm_un_ty.structFields(&o.builder)[tag_index]; | 9044 | const llvm_tag_ty = llvm_un_ty.structFields(&o.builder)[tag_index]; |
| 9046 | return self.wip.load(.normal, llvm_tag_ty, tag_field_ptr, .default, ""); | 9045 | return self.wip.load(.normal, llvm_tag_ty, tag_field_ptr, .default, ""); |
| 9047 | } else { | 9046 | } else { |
| 9048 | if (layout.payload_size == 0) return union_handle; | 9047 | if (layout.payload_size == 0) return union_handle; |
| 9049 | const tag_index = @intFromBool(layout.tag_align < layout.payload_align); | 9048 | const tag_index = @intFromBool(layout.tag_align.compare(.lt, layout.payload_align)); |
| 9050 | return self.wip.extractValue(union_handle, &.{tag_index}, ""); | 9049 | return self.wip.extractValue(union_handle, &.{tag_index}, ""); |
| 9051 | } | 9050 | } |
| 9052 | } | 9051 | } |
| ... | @@ -9605,6 +9604,7 @@ pub const FuncGen = struct { | ... | @@ -9605,6 +9604,7 @@ pub const FuncGen = struct { |
| 9605 | fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { | 9604 | fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 9606 | const o = self.dg.object; | 9605 | const o = self.dg.object; |
| 9607 | const mod = o.module; | 9606 | const mod = o.module; |
| 9607 | const ip = &mod.intern_pool; | ||
| 9608 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 9608 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 9609 | const result_ty = self.typeOfIndex(inst); | 9609 | const result_ty = self.typeOfIndex(inst); |
| 9610 | const len: usize = @intCast(result_ty.arrayLen(mod)); | 9610 | const len: usize = @intCast(result_ty.arrayLen(mod)); |
| ... | @@ -9622,23 +9622,21 @@ pub const FuncGen = struct { | ... | @@ -9622,23 +9622,21 @@ pub const FuncGen = struct { |
| 9622 | return vector; | 9622 | return vector; |
| 9623 | }, | 9623 | }, |
| 9624 | .Struct => { | 9624 | .Struct => { |
| 9625 | if (result_ty.containerLayout(mod) == .Packed) { | 9625 | if (mod.typeToPackedStruct(result_ty)) |struct_type| { |
| 9626 | const struct_obj = mod.typeToStruct(result_ty).?; | 9626 | const backing_int_ty = struct_type.backingIntType(ip).*; |
| 9627 | assert(struct_obj.haveLayout()); | 9627 | assert(backing_int_ty != .none); |
| 9628 | const big_bits = struct_obj.backing_int_ty.bitSize(mod); | 9628 | const big_bits = backing_int_ty.toType().bitSize(mod); |
| 9629 | const int_ty = try o.builder.intType(@intCast(big_bits)); | 9629 | const int_ty = try o.builder.intType(@intCast(big_bits)); |
| 9630 | const fields = struct_obj.fields.values(); | ||
| 9631 | comptime assert(Type.packed_struct_layout_version == 2); | 9630 | comptime assert(Type.packed_struct_layout_version == 2); |
| 9632 | var running_int = try o.builder.intValue(int_ty, 0); | 9631 | var running_int = try o.builder.intValue(int_ty, 0); |
| 9633 | var running_bits: u16 = 0; | 9632 | var running_bits: u16 = 0; |
| 9634 | for (elements, 0..) |elem, i| { | 9633 | for (elements, struct_type.field_types.get(ip)) |elem, field_ty| { |
| 9635 | const field = fields[i]; | 9634 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 9636 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | ||
| 9637 | 9635 | ||
| 9638 | const non_int_val = try self.resolveInst(elem); | 9636 | const non_int_val = try self.resolveInst(elem); |
| 9639 | const ty_bit_size: u16 = @intCast(field.ty.bitSize(mod)); | 9637 | const ty_bit_size: u16 = @intCast(field_ty.toType().bitSize(mod)); |
| 9640 | const small_int_ty = try o.builder.intType(ty_bit_size); | 9638 | const small_int_ty = try o.builder.intType(ty_bit_size); |
| 9641 | const small_int_val = if (field.ty.isPtrAtRuntime(mod)) | 9639 | const small_int_val = if (field_ty.toType().isPtrAtRuntime(mod)) |
| 9642 | try self.wip.cast(.ptrtoint, non_int_val, small_int_ty, "") | 9640 | try self.wip.cast(.ptrtoint, non_int_val, small_int_ty, "") |
| 9643 | else | 9641 | else |
| 9644 | try self.wip.cast(.bitcast, non_int_val, small_int_ty, ""); | 9642 | try self.wip.cast(.bitcast, non_int_val, small_int_ty, ""); |
| ... | @@ -9652,10 +9650,12 @@ pub const FuncGen = struct { | ... | @@ -9652,10 +9650,12 @@ pub const FuncGen = struct { |
| 9652 | return running_int; | 9650 | return running_int; |
| 9653 | } | 9651 | } |
| 9654 | 9652 | ||
| 9653 | assert(result_ty.containerLayout(mod) != .Packed); | ||
| 9654 | |||
| 9655 | if (isByRef(result_ty, mod)) { | 9655 | if (isByRef(result_ty, mod)) { |
| 9656 | // TODO in debug builds init to undef so that the padding will be 0xaa | 9656 | // TODO in debug builds init to undef so that the padding will be 0xaa |
| 9657 | // even if we fully populate the fields. | 9657 | // even if we fully populate the fields. |
| 9658 | const alignment = Builder.Alignment.fromByteUnits(result_ty.abiAlignment(mod)); | 9658 | const alignment = result_ty.abiAlignment(mod).toLlvm(); |
| 9659 | const alloca_inst = try self.buildAlloca(llvm_result_ty, alignment); | 9659 | const alloca_inst = try self.buildAlloca(llvm_result_ty, alignment); |
| 9660 | 9660 | ||
| 9661 | for (elements, 0..) |elem, i| { | 9661 | for (elements, 0..) |elem, i| { |
| ... | @@ -9668,9 +9668,7 @@ pub const FuncGen = struct { | ... | @@ -9668,9 +9668,7 @@ pub const FuncGen = struct { |
| 9668 | const field_ptr_ty = try mod.ptrType(.{ | 9668 | const field_ptr_ty = try mod.ptrType(.{ |
| 9669 | .child = self.typeOf(elem).toIntern(), | 9669 | .child = self.typeOf(elem).toIntern(), |
| 9670 | .flags = .{ | 9670 | .flags = .{ |
| 9671 | .alignment = InternPool.Alignment.fromNonzeroByteUnits( | 9671 | .alignment = result_ty.structFieldAlign(i, mod), |
| 9672 | result_ty.structFieldAlign(i, mod), | ||
| 9673 | ), | ||
| 9674 | }, | 9672 | }, |
| 9675 | }); | 9673 | }); |
| 9676 | try self.store(field_ptr, field_ptr_ty, llvm_elem, .none); | 9674 | try self.store(field_ptr, field_ptr_ty, llvm_elem, .none); |
| ... | @@ -9694,7 +9692,7 @@ pub const FuncGen = struct { | ... | @@ -9694,7 +9692,7 @@ pub const FuncGen = struct { |
| 9694 | 9692 | ||
| 9695 | const llvm_usize = try o.lowerType(Type.usize); | 9693 | const llvm_usize = try o.lowerType(Type.usize); |
| 9696 | const usize_zero = try o.builder.intValue(llvm_usize, 0); | 9694 | const usize_zero = try o.builder.intValue(llvm_usize, 0); |
| 9697 | const alignment = Builder.Alignment.fromByteUnits(result_ty.abiAlignment(mod)); | 9695 | const alignment = result_ty.abiAlignment(mod).toLlvm(); |
| 9698 | const alloca_inst = try self.buildAlloca(llvm_result_ty, alignment); | 9696 | const alloca_inst = try self.buildAlloca(llvm_result_ty, alignment); |
| 9699 | 9697 | ||
| 9700 | const array_info = result_ty.arrayInfo(mod); | 9698 | const array_info = result_ty.arrayInfo(mod); |
| ... | @@ -9770,7 +9768,7 @@ pub const FuncGen = struct { | ... | @@ -9770,7 +9768,7 @@ pub const FuncGen = struct { |
| 9770 | // necessarily match the format that we need, depending on which tag is active. | 9768 | // necessarily match the format that we need, depending on which tag is active. |
| 9771 | // We must construct the correct unnamed struct type here, in order to then set | 9769 | // We must construct the correct unnamed struct type here, in order to then set |
| 9772 | // the fields appropriately. | 9770 | // the fields appropriately. |
| 9773 | const alignment = Builder.Alignment.fromByteUnits(layout.abi_align); | 9771 | const alignment = layout.abi_align.toLlvm(); |
| 9774 | const result_ptr = try self.buildAlloca(union_llvm_ty, alignment); | 9772 | const result_ptr = try self.buildAlloca(union_llvm_ty, alignment); |
| 9775 | const llvm_payload = try self.resolveInst(extra.init); | 9773 | const llvm_payload = try self.resolveInst(extra.init); |
| 9776 | const field_ty = union_obj.field_types.get(ip)[extra.field_index].toType(); | 9774 | const field_ty = union_obj.field_types.get(ip)[extra.field_index].toType(); |
| ... | @@ -9799,7 +9797,7 @@ pub const FuncGen = struct { | ... | @@ -9799,7 +9797,7 @@ pub const FuncGen = struct { |
| 9799 | const tag_ty = try o.lowerType(union_obj.enum_tag_ty.toType()); | 9797 | const tag_ty = try o.lowerType(union_obj.enum_tag_ty.toType()); |
| 9800 | var fields: [3]Builder.Type = undefined; | 9798 | var fields: [3]Builder.Type = undefined; |
| 9801 | var fields_len: usize = 2; | 9799 | var fields_len: usize = 2; |
| 9802 | if (layout.tag_align >= layout.payload_align) { | 9800 | if (layout.tag_align.compare(.gte, layout.payload_align)) { |
| 9803 | fields = .{ tag_ty, payload_ty, undefined }; | 9801 | fields = .{ tag_ty, payload_ty, undefined }; |
| 9804 | } else { | 9802 | } else { |
| 9805 | fields = .{ payload_ty, tag_ty, undefined }; | 9803 | fields = .{ payload_ty, tag_ty, undefined }; |
| ... | @@ -9815,7 +9813,7 @@ pub const FuncGen = struct { | ... | @@ -9815,7 +9813,7 @@ pub const FuncGen = struct { |
| 9815 | // tag and the payload. | 9813 | // tag and the payload. |
| 9816 | const field_ptr_ty = try mod.ptrType(.{ | 9814 | const field_ptr_ty = try mod.ptrType(.{ |
| 9817 | .child = field_ty.toIntern(), | 9815 | .child = field_ty.toIntern(), |
| 9818 | .flags = .{ .alignment = InternPool.Alignment.fromNonzeroByteUnits(field_align) }, | 9816 | .flags = .{ .alignment = field_align }, |
| 9819 | }); | 9817 | }); |
| 9820 | if (layout.tag_size == 0) { | 9818 | if (layout.tag_size == 0) { |
| 9821 | const indices = [3]Builder.Value{ usize_zero, i32_zero, i32_zero }; | 9819 | const indices = [3]Builder.Value{ usize_zero, i32_zero, i32_zero }; |
| ... | @@ -9827,7 +9825,7 @@ pub const FuncGen = struct { | ... | @@ -9827,7 +9825,7 @@ pub const FuncGen = struct { |
| 9827 | } | 9825 | } |
| 9828 | 9826 | ||
| 9829 | { | 9827 | { |
| 9830 | const payload_index = @intFromBool(layout.tag_align >= layout.payload_align); | 9828 | const payload_index = @intFromBool(layout.tag_align.compare(.gte, layout.payload_align)); |
| 9831 | const indices: [3]Builder.Value = | 9829 | const indices: [3]Builder.Value = |
| 9832 | .{ usize_zero, try o.builder.intValue(.i32, payload_index), i32_zero }; | 9830 | .{ usize_zero, try o.builder.intValue(.i32, payload_index), i32_zero }; |
| 9833 | const len: usize = if (field_size == layout.payload_size) 2 else 3; | 9831 | const len: usize = if (field_size == layout.payload_size) 2 else 3; |
| ... | @@ -9836,12 +9834,12 @@ pub const FuncGen = struct { | ... | @@ -9836,12 +9834,12 @@ pub const FuncGen = struct { |
| 9836 | try self.store(field_ptr, field_ptr_ty, llvm_payload, .none); | 9834 | try self.store(field_ptr, field_ptr_ty, llvm_payload, .none); |
| 9837 | } | 9835 | } |
| 9838 | { | 9836 | { |
| 9839 | const tag_index = @intFromBool(layout.tag_align < layout.payload_align); | 9837 | const tag_index = @intFromBool(layout.tag_align.compare(.lt, layout.payload_align)); |
| 9840 | const indices: [2]Builder.Value = .{ usize_zero, try o.builder.intValue(.i32, tag_index) }; | 9838 | const indices: [2]Builder.Value = .{ usize_zero, try o.builder.intValue(.i32, tag_index) }; |
| 9841 | const field_ptr = try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, &indices, ""); | 9839 | const field_ptr = try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, &indices, ""); |
| 9842 | const tag_ty = try o.lowerType(union_obj.enum_tag_ty.toType()); | 9840 | const tag_ty = try o.lowerType(union_obj.enum_tag_ty.toType()); |
| 9843 | const llvm_tag = try o.builder.intValue(tag_ty, tag_int); | 9841 | const llvm_tag = try o.builder.intValue(tag_ty, tag_int); |
| 9844 | const tag_alignment = Builder.Alignment.fromByteUnits(union_obj.enum_tag_ty.toType().abiAlignment(mod)); | 9842 | const tag_alignment = union_obj.enum_tag_ty.toType().abiAlignment(mod).toLlvm(); |
| 9845 | _ = try self.wip.store(.normal, llvm_tag, field_ptr, tag_alignment); | 9843 | _ = try self.wip.store(.normal, llvm_tag, field_ptr, tag_alignment); |
| 9846 | } | 9844 | } |
| 9847 | 9845 | ||
| ... | @@ -9978,7 +9976,7 @@ pub const FuncGen = struct { | ... | @@ -9978,7 +9976,7 @@ pub const FuncGen = struct { |
| 9978 | variable_index.setMutability(.constant, &o.builder); | 9976 | variable_index.setMutability(.constant, &o.builder); |
| 9979 | variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); | 9977 | variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); |
| 9980 | variable_index.setAlignment( | 9978 | variable_index.setAlignment( |
| 9981 | Builder.Alignment.fromByteUnits(Type.slice_const_u8_sentinel_0.abiAlignment(mod)), | 9979 | Type.slice_const_u8_sentinel_0.abiAlignment(mod).toLlvm(), |
| 9982 | &o.builder, | 9980 | &o.builder, |
| 9983 | ); | 9981 | ); |
| 9984 | 9982 | ||
| ... | @@ -10023,7 +10021,7 @@ pub const FuncGen = struct { | ... | @@ -10023,7 +10021,7 @@ pub const FuncGen = struct { |
| 10023 | // We have a pointer and we need to return a pointer to the first field. | 10021 | // We have a pointer and we need to return a pointer to the first field. |
| 10024 | const payload_ptr = try fg.wip.gepStruct(opt_llvm_ty, opt_handle, 0, ""); | 10022 | const payload_ptr = try fg.wip.gepStruct(opt_llvm_ty, opt_handle, 0, ""); |
| 10025 | 10023 | ||
| 10026 | const payload_alignment = Builder.Alignment.fromByteUnits(payload_ty.abiAlignment(mod)); | 10024 | const payload_alignment = payload_ty.abiAlignment(mod).toLlvm(); |
| 10027 | if (isByRef(payload_ty, mod)) { | 10025 | if (isByRef(payload_ty, mod)) { |
| 10028 | if (can_elide_load) | 10026 | if (can_elide_load) |
| 10029 | return payload_ptr; | 10027 | return payload_ptr; |
| ... | @@ -10050,7 +10048,7 @@ pub const FuncGen = struct { | ... | @@ -10050,7 +10048,7 @@ pub const FuncGen = struct { |
| 10050 | const mod = o.module; | 10048 | const mod = o.module; |
| 10051 | 10049 | ||
| 10052 | if (isByRef(optional_ty, mod)) { | 10050 | if (isByRef(optional_ty, mod)) { |
| 10053 | const payload_alignment = Builder.Alignment.fromByteUnits(optional_ty.abiAlignment(mod)); | 10051 | const payload_alignment = optional_ty.abiAlignment(mod).toLlvm(); |
| 10054 | const alloca_inst = try self.buildAlloca(optional_llvm_ty, payload_alignment); | 10052 | const alloca_inst = try self.buildAlloca(optional_llvm_ty, payload_alignment); |
| 10055 | 10053 | ||
| 10056 | { | 10054 | { |
| ... | @@ -10123,7 +10121,7 @@ pub const FuncGen = struct { | ... | @@ -10123,7 +10121,7 @@ pub const FuncGen = struct { |
| 10123 | .Union => { | 10121 | .Union => { |
| 10124 | const layout = struct_ty.unionGetLayout(mod); | 10122 | const layout = struct_ty.unionGetLayout(mod); |
| 10125 | if (layout.payload_size == 0 or struct_ty.containerLayout(mod) == .Packed) return struct_ptr; | 10123 | if (layout.payload_size == 0 or struct_ty.containerLayout(mod) == .Packed) return struct_ptr; |
| 10126 | const payload_index = @intFromBool(layout.tag_align >= layout.payload_align); | 10124 | const payload_index = @intFromBool(layout.tag_align.compare(.gte, layout.payload_align)); |
| 10127 | const union_llvm_ty = try o.lowerType(struct_ty); | 10125 | const union_llvm_ty = try o.lowerType(struct_ty); |
| 10128 | return self.wip.gepStruct(union_llvm_ty, struct_ptr, payload_index, ""); | 10126 | return self.wip.gepStruct(union_llvm_ty, struct_ptr, payload_index, ""); |
| 10129 | }, | 10127 | }, |
| ... | @@ -10142,9 +10140,7 @@ pub const FuncGen = struct { | ... | @@ -10142,9 +10140,7 @@ pub const FuncGen = struct { |
| 10142 | const o = fg.dg.object; | 10140 | const o = fg.dg.object; |
| 10143 | const mod = o.module; | 10141 | const mod = o.module; |
| 10144 | const pointee_llvm_ty = try o.lowerType(pointee_type); | 10142 | const pointee_llvm_ty = try o.lowerType(pointee_type); |
| 10145 | const result_align = Builder.Alignment.fromByteUnits( | 10143 | const result_align = InternPool.Alignment.fromLlvm(ptr_alignment).max(pointee_type.abiAlignment(mod)).toLlvm(); |
| 10146 | @max(ptr_alignment.toByteUnits() orelse 0, pointee_type.abiAlignment(mod)), | ||
| 10147 | ); | ||
| 10148 | const result_ptr = try fg.buildAlloca(pointee_llvm_ty, result_align); | 10144 | const result_ptr = try fg.buildAlloca(pointee_llvm_ty, result_align); |
| 10149 | const size_bytes = pointee_type.abiSize(mod); | 10145 | const size_bytes = pointee_type.abiSize(mod); |
| 10150 | _ = try fg.wip.callMemCpy( | 10146 | _ = try fg.wip.callMemCpy( |
| ... | @@ -10168,9 +10164,11 @@ pub const FuncGen = struct { | ... | @@ -10168,9 +10164,11 @@ pub const FuncGen = struct { |
| 10168 | const elem_ty = info.child.toType(); | 10164 | const elem_ty = info.child.toType(); |
| 10169 | if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none; | 10165 | if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none; |
| 10170 | 10166 | ||
| 10171 | const ptr_alignment = Builder.Alignment.fromByteUnits( | 10167 | const ptr_alignment = (if (info.flags.alignment != .none) |
| 10172 | info.flags.alignment.toByteUnitsOptional() orelse elem_ty.abiAlignment(mod), | 10168 | @as(InternPool.Alignment, info.flags.alignment) |
| 10173 | ); | 10169 | else |
| 10170 | elem_ty.abiAlignment(mod)).toLlvm(); | ||
| 10171 | |||
| 10174 | const access_kind: Builder.MemoryAccessKind = | 10172 | const access_kind: Builder.MemoryAccessKind = |
| 10175 | if (info.flags.is_volatile) .@"volatile" else .normal; | 10173 | if (info.flags.is_volatile) .@"volatile" else .normal; |
| 10176 | 10174 | ||
| ... | @@ -10201,7 +10199,7 @@ pub const FuncGen = struct { | ... | @@ -10201,7 +10199,7 @@ pub const FuncGen = struct { |
| 10201 | const elem_llvm_ty = try o.lowerType(elem_ty); | 10199 | const elem_llvm_ty = try o.lowerType(elem_ty); |
| 10202 | 10200 | ||
| 10203 | if (isByRef(elem_ty, mod)) { | 10201 | if (isByRef(elem_ty, mod)) { |
| 10204 | const result_align = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod)); | 10202 | const result_align = elem_ty.abiAlignment(mod).toLlvm(); |
| 10205 | const result_ptr = try self.buildAlloca(elem_llvm_ty, result_align); | 10203 | const result_ptr = try self.buildAlloca(elem_llvm_ty, result_align); |
| 10206 | 10204 | ||
| 10207 | const same_size_int = try o.builder.intType(@intCast(elem_bits)); | 10205 | const same_size_int = try o.builder.intType(@intCast(elem_bits)); |
| ... | @@ -10239,7 +10237,7 @@ pub const FuncGen = struct { | ... | @@ -10239,7 +10237,7 @@ pub const FuncGen = struct { |
| 10239 | if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) { | 10237 | if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) { |
| 10240 | return; | 10238 | return; |
| 10241 | } | 10239 | } |
| 10242 | const ptr_alignment = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod)); | 10240 | const ptr_alignment = ptr_ty.ptrAlignment(mod).toLlvm(); |
| 10243 | const access_kind: Builder.MemoryAccessKind = | 10241 | const access_kind: Builder.MemoryAccessKind = |
| 10244 | if (info.flags.is_volatile) .@"volatile" else .normal; | 10242 | if (info.flags.is_volatile) .@"volatile" else .normal; |
| 10245 | 10243 | ||
| ... | @@ -10305,7 +10303,7 @@ pub const FuncGen = struct { | ... | @@ -10305,7 +10303,7 @@ pub const FuncGen = struct { |
| 10305 | ptr, | 10303 | ptr, |
| 10306 | ptr_alignment, | 10304 | ptr_alignment, |
| 10307 | elem, | 10305 | elem, |
| 10308 | Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod)), | 10306 | elem_ty.abiAlignment(mod).toLlvm(), |
| 10309 | try o.builder.intValue(try o.lowerType(Type.usize), elem_ty.abiSize(mod)), | 10307 | try o.builder.intValue(try o.lowerType(Type.usize), elem_ty.abiSize(mod)), |
| 10310 | access_kind, | 10308 | access_kind, |
| 10311 | ); | 10309 | ); |
| ... | @@ -10337,7 +10335,7 @@ pub const FuncGen = struct { | ... | @@ -10337,7 +10335,7 @@ pub const FuncGen = struct { |
| 10337 | if (!target_util.hasValgrindSupport(target)) return default_value; | 10335 | if (!target_util.hasValgrindSupport(target)) return default_value; |
| 10338 | 10336 | ||
| 10339 | const llvm_usize = try o.lowerType(Type.usize); | 10337 | const llvm_usize = try o.lowerType(Type.usize); |
| 10340 | const usize_alignment = Builder.Alignment.fromByteUnits(Type.usize.abiAlignment(mod)); | 10338 | const usize_alignment = Type.usize.abiAlignment(mod).toLlvm(); |
| 10341 | 10339 | ||
| 10342 | const array_llvm_ty = try o.builder.arrayType(6, llvm_usize); | 10340 | const array_llvm_ty = try o.builder.arrayType(6, llvm_usize); |
| 10343 | const array_ptr = if (fg.valgrind_client_request_array == .none) a: { | 10341 | const array_ptr = if (fg.valgrind_client_request_array == .none) a: { |
| ... | @@ -10718,6 +10716,7 @@ fn lowerWin64FnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Err | ... | @@ -10718,6 +10716,7 @@ fn lowerWin64FnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Err |
| 10718 | 10716 | ||
| 10719 | fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type { | 10717 | fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type { |
| 10720 | const mod = o.module; | 10718 | const mod = o.module; |
| 10719 | const ip = &mod.intern_pool; | ||
| 10721 | const return_type = fn_info.return_type.toType(); | 10720 | const return_type = fn_info.return_type.toType(); |
| 10722 | if (isScalar(mod, return_type)) { | 10721 | if (isScalar(mod, return_type)) { |
| 10723 | return o.lowerType(return_type); | 10722 | return o.lowerType(return_type); |
| ... | @@ -10761,12 +10760,16 @@ fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.E | ... | @@ -10761,12 +10760,16 @@ fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.E |
| 10761 | const first_non_integer = std.mem.indexOfNone(x86_64_abi.Class, &classes, &.{.integer}); | 10760 | const first_non_integer = std.mem.indexOfNone(x86_64_abi.Class, &classes, &.{.integer}); |
| 10762 | if (first_non_integer == null or classes[first_non_integer.?] == .none) { | 10761 | if (first_non_integer == null or classes[first_non_integer.?] == .none) { |
| 10763 | assert(first_non_integer orelse classes.len == types_index); | 10762 | assert(first_non_integer orelse classes.len == types_index); |
| 10764 | if (mod.intern_pool.indexToKey(return_type.toIntern()) == .struct_type) { | 10763 | switch (ip.indexToKey(return_type.toIntern())) { |
| 10765 | var struct_it = return_type.iterateStructOffsets(mod); | 10764 | .struct_type => |struct_type| { |
| 10766 | while (struct_it.next()) |_| {} | 10765 | assert(struct_type.haveLayout(ip)); |
| 10767 | assert((std.math.divCeil(u64, struct_it.offset, 8) catch unreachable) == types_index); | 10766 | const size: u64 = struct_type.size(ip).*; |
| 10768 | if (struct_it.offset % 8 > 0) types_buffer[types_index - 1] = | 10767 | assert((std.math.divCeil(u64, size, 8) catch unreachable) == types_index); |
| 10769 | try o.builder.intType(@intCast(struct_it.offset % 8 * 8)); | 10768 | if (size % 8 > 0) { |
| 10769 | types_buffer[types_index - 1] = try o.builder.intType(@intCast(size % 8 * 8)); | ||
| 10770 | } | ||
| 10771 | }, | ||
| 10772 | else => {}, | ||
| 10770 | } | 10773 | } |
| 10771 | if (types_index == 1) return types_buffer[0]; | 10774 | if (types_index == 1) return types_buffer[0]; |
| 10772 | } | 10775 | } |
| ... | @@ -10982,6 +10985,7 @@ const ParamTypeIterator = struct { | ... | @@ -10982,6 +10985,7 @@ const ParamTypeIterator = struct { |
| 10982 | 10985 | ||
| 10983 | fn nextSystemV(it: *ParamTypeIterator, ty: Type) Allocator.Error!?Lowering { | 10986 | fn nextSystemV(it: *ParamTypeIterator, ty: Type) Allocator.Error!?Lowering { |
| 10984 | const mod = it.object.module; | 10987 | const mod = it.object.module; |
| 10988 | const ip = &mod.intern_pool; | ||
| 10985 | const classes = x86_64_abi.classifySystemV(ty, mod, .arg); | 10989 | const classes = x86_64_abi.classifySystemV(ty, mod, .arg); |
| 10986 | if (classes[0] == .memory) { | 10990 | if (classes[0] == .memory) { |
| 10987 | it.zig_index += 1; | 10991 | it.zig_index += 1; |
| ... | @@ -11037,12 +11041,17 @@ const ParamTypeIterator = struct { | ... | @@ -11037,12 +11041,17 @@ const ParamTypeIterator = struct { |
| 11037 | it.llvm_index += 1; | 11041 | it.llvm_index += 1; |
| 11038 | return .abi_sized_int; | 11042 | return .abi_sized_int; |
| 11039 | } | 11043 | } |
| 11040 | if (mod.intern_pool.indexToKey(ty.toIntern()) == .struct_type) { | 11044 | switch (ip.indexToKey(ty.toIntern())) { |
| 11041 | var struct_it = ty.iterateStructOffsets(mod); | 11045 | .struct_type => |struct_type| { |
| 11042 | while (struct_it.next()) |_| {} | 11046 | assert(struct_type.haveLayout(ip)); |
| 11043 | assert((std.math.divCeil(u64, struct_it.offset, 8) catch unreachable) == types_index); | 11047 | const size: u64 = struct_type.size(ip).*; |
| 11044 | if (struct_it.offset % 8 > 0) types_buffer[types_index - 1] = | 11048 | assert((std.math.divCeil(u64, size, 8) catch unreachable) == types_index); |
| 11045 | try it.object.builder.intType(@intCast(struct_it.offset % 8 * 8)); | 11049 | if (size % 8 > 0) { |
| 11050 | types_buffer[types_index - 1] = | ||
| 11051 | try it.object.builder.intType(@intCast(size % 8 * 8)); | ||
| 11052 | } | ||
| 11053 | }, | ||
| 11054 | else => {}, | ||
| 11046 | } | 11055 | } |
| 11047 | } | 11056 | } |
| 11048 | it.types_len = types_index; | 11057 | it.types_len = types_index; |
| ... | @@ -11137,8 +11146,6 @@ fn isByRef(ty: Type, mod: *Module) bool { | ... | @@ -11137,8 +11146,6 @@ fn isByRef(ty: Type, mod: *Module) bool { |
| 11137 | 11146 | ||
| 11138 | .Array, .Frame => return ty.hasRuntimeBits(mod), | 11147 | .Array, .Frame => return ty.hasRuntimeBits(mod), |
| 11139 | .Struct => { | 11148 | .Struct => { |
| 11140 | // Packed structs are represented to LLVM as integers. | ||
| 11141 | if (ty.containerLayout(mod) == .Packed) return false; | ||
| 11142 | const struct_type = switch (ip.indexToKey(ty.toIntern())) { | 11149 | const struct_type = switch (ip.indexToKey(ty.toIntern())) { |
| 11143 | .anon_struct_type => |tuple| { | 11150 | .anon_struct_type => |tuple| { |
| 11144 | var count: usize = 0; | 11151 | var count: usize = 0; |
| ... | @@ -11154,14 +11161,18 @@ fn isByRef(ty: Type, mod: *Module) bool { | ... | @@ -11154,14 +11161,18 @@ fn isByRef(ty: Type, mod: *Module) bool { |
| 11154 | .struct_type => |s| s, | 11161 | .struct_type => |s| s, |
| 11155 | else => unreachable, | 11162 | else => unreachable, |
| 11156 | }; | 11163 | }; |
| 11157 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | ||
| 11158 | var count: usize = 0; | ||
| 11159 | for (struct_obj.fields.values()) |field| { | ||
| 11160 | if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue; | ||
| 11161 | 11164 | ||
| 11165 | // Packed structs are represented to LLVM as integers. | ||
| 11166 | if (struct_type.layout == .Packed) return false; | ||
| 11167 | |||
| 11168 | const field_types = struct_type.field_types.get(ip); | ||
| 11169 | var it = struct_type.iterateRuntimeOrder(ip); | ||
| 11170 | var count: usize = 0; | ||
| 11171 | while (it.next()) |field_index| { | ||
| 11162 | count += 1; | 11172 | count += 1; |
| 11163 | if (count > max_fields_byval) return true; | 11173 | if (count > max_fields_byval) return true; |
| 11164 | if (isByRef(field.ty, mod)) return true; | 11174 | const field_ty = field_types[field_index].toType(); |
| 11175 | if (isByRef(field_ty, mod)) return true; | ||
| 11165 | } | 11176 | } |
| 11166 | return false; | 11177 | return false; |
| 11167 | }, | 11178 | }, |
| ... | @@ -11362,11 +11373,11 @@ fn buildAllocaInner( | ... | @@ -11362,11 +11373,11 @@ fn buildAllocaInner( |
| 11362 | } | 11373 | } |
| 11363 | 11374 | ||
| 11364 | fn errUnionPayloadOffset(payload_ty: Type, mod: *Module) u1 { | 11375 | fn errUnionPayloadOffset(payload_ty: Type, mod: *Module) u1 { |
| 11365 | return @intFromBool(Type.err_int.abiAlignment(mod) > payload_ty.abiAlignment(mod)); | 11376 | return @intFromBool(Type.err_int.abiAlignment(mod).compare(.gt, payload_ty.abiAlignment(mod))); |
| 11366 | } | 11377 | } |
| 11367 | 11378 | ||
| 11368 | fn errUnionErrorOffset(payload_ty: Type, mod: *Module) u1 { | 11379 | fn errUnionErrorOffset(payload_ty: Type, mod: *Module) u1 { |
| 11369 | return @intFromBool(Type.err_int.abiAlignment(mod) <= payload_ty.abiAlignment(mod)); | 11380 | return @intFromBool(Type.err_int.abiAlignment(mod).compare(.lte, payload_ty.abiAlignment(mod))); |
| 11370 | } | 11381 | } |
| 11371 | 11382 | ||
| 11372 | /// Returns true for asm constraint (e.g. "=*m", "=r") if it accepts a memory location | 11383 | /// Returns true for asm constraint (e.g. "=*m", "=r") if it accepts a memory location |
src/codegen/spirv.zig+26-24| ... | @@ -792,24 +792,28 @@ pub const DeclGen = struct { | ... | @@ -792,24 +792,28 @@ pub const DeclGen = struct { |
| 792 | }, | 792 | }, |
| 793 | .vector_type => return dg.todo("indirect constant of type {}", .{ty.fmt(mod)}), | 793 | .vector_type => return dg.todo("indirect constant of type {}", .{ty.fmt(mod)}), |
| 794 | .struct_type => { | 794 | .struct_type => { |
| 795 | const struct_ty = mod.typeToStruct(ty).?; | 795 | const struct_type = mod.typeToStruct(ty).?; |
| 796 | if (struct_ty.layout == .Packed) { | 796 | if (struct_type.layout == .Packed) { |
| 797 | return dg.todo("packed struct constants", .{}); | 797 | return dg.todo("packed struct constants", .{}); |
| 798 | } | 798 | } |
| 799 | 799 | ||
| 800 | // TODO iterate with runtime order instead so that struct field | ||
| 801 | // reordering can be enabled for this backend. | ||
| 800 | const struct_begin = self.size; | 802 | const struct_begin = self.size; |
| 801 | for (struct_ty.fields.values(), 0..) |field, i| { | 803 | for (struct_type.field_types.get(ip), 0..) |field_ty, i_usize| { |
| 802 | if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue; | 804 | const i: u32 = @intCast(i_usize); |
| 805 | if (struct_type.fieldIsComptime(ip, i)) continue; | ||
| 806 | if (!field_ty.toType().hasRuntimeBits(mod)) continue; | ||
| 803 | 807 | ||
| 804 | const field_val = switch (aggregate.storage) { | 808 | const field_val = switch (aggregate.storage) { |
| 805 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ | 809 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ |
| 806 | .ty = field.ty.toIntern(), | 810 | .ty = field_ty, |
| 807 | .storage = .{ .u64 = bytes[i] }, | 811 | .storage = .{ .u64 = bytes[i] }, |
| 808 | } }), | 812 | } }), |
| 809 | .elems => |elems| elems[i], | 813 | .elems => |elems| elems[i], |
| 810 | .repeated_elem => |elem| elem, | 814 | .repeated_elem => |elem| elem, |
| 811 | }; | 815 | }; |
| 812 | try self.lower(field.ty, field_val.toValue()); | 816 | try self.lower(field_ty.toType(), field_val.toValue()); |
| 813 | 817 | ||
| 814 | // Add padding if required. | 818 | // Add padding if required. |
| 815 | // TODO: Add to type generation as well? | 819 | // TODO: Add to type generation as well? |
| ... | @@ -838,7 +842,7 @@ pub const DeclGen = struct { | ... | @@ -838,7 +842,7 @@ pub const DeclGen = struct { |
| 838 | const active_field_ty = union_obj.field_types.get(ip)[active_field].toType(); | 842 | const active_field_ty = union_obj.field_types.get(ip)[active_field].toType(); |
| 839 | 843 | ||
| 840 | const has_tag = layout.tag_size != 0; | 844 | const has_tag = layout.tag_size != 0; |
| 841 | const tag_first = layout.tag_align >= layout.payload_align; | 845 | const tag_first = layout.tag_align.compare(.gte, layout.payload_align); |
| 842 | 846 | ||
| 843 | if (has_tag and tag_first) { | 847 | if (has_tag and tag_first) { |
| 844 | try self.lower(ty.unionTagTypeSafety(mod).?, un.tag.toValue()); | 848 | try self.lower(ty.unionTagTypeSafety(mod).?, un.tag.toValue()); |
| ... | @@ -1094,7 +1098,7 @@ pub const DeclGen = struct { | ... | @@ -1094,7 +1098,7 @@ pub const DeclGen = struct { |
| 1094 | val, | 1098 | val, |
| 1095 | .UniformConstant, | 1099 | .UniformConstant, |
| 1096 | false, | 1100 | false, |
| 1097 | alignment, | 1101 | @intCast(alignment.toByteUnits(0)), |
| 1098 | ); | 1102 | ); |
| 1099 | log.debug("indirect constant: index = {}", .{@intFromEnum(spv_decl_index)}); | 1103 | log.debug("indirect constant: index = {}", .{@intFromEnum(spv_decl_index)}); |
| 1100 | try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {}); | 1104 | try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {}); |
| ... | @@ -1180,7 +1184,7 @@ pub const DeclGen = struct { | ... | @@ -1180,7 +1184,7 @@ pub const DeclGen = struct { |
| 1180 | var member_names = std.BoundedArray(CacheString, 4){}; | 1184 | var member_names = std.BoundedArray(CacheString, 4){}; |
| 1181 | 1185 | ||
| 1182 | const has_tag = layout.tag_size != 0; | 1186 | const has_tag = layout.tag_size != 0; |
| 1183 | const tag_first = layout.tag_align >= layout.payload_align; | 1187 | const tag_first = layout.tag_align.compare(.gte, layout.payload_align); |
| 1184 | const u8_ty_ref = try self.intType(.unsigned, 8); // TODO: What if Int8Type is not enabled? | 1188 | const u8_ty_ref = try self.intType(.unsigned, 8); // TODO: What if Int8Type is not enabled? |
| 1185 | 1189 | ||
| 1186 | if (has_tag and tag_first) { | 1190 | if (has_tag and tag_first) { |
| ... | @@ -1333,7 +1337,7 @@ pub const DeclGen = struct { | ... | @@ -1333,7 +1337,7 @@ pub const DeclGen = struct { |
| 1333 | } }); | 1337 | } }); |
| 1334 | }, | 1338 | }, |
| 1335 | .Struct => { | 1339 | .Struct => { |
| 1336 | const struct_ty = switch (ip.indexToKey(ty.toIntern())) { | 1340 | const struct_type = switch (ip.indexToKey(ty.toIntern())) { |
| 1337 | .anon_struct_type => |tuple| { | 1341 | .anon_struct_type => |tuple| { |
| 1338 | const member_types = try self.gpa.alloc(CacheRef, tuple.values.len); | 1342 | const member_types = try self.gpa.alloc(CacheRef, tuple.values.len); |
| 1339 | defer self.gpa.free(member_types); | 1343 | defer self.gpa.free(member_types); |
| ... | @@ -1350,13 +1354,12 @@ pub const DeclGen = struct { | ... | @@ -1350,13 +1354,12 @@ pub const DeclGen = struct { |
| 1350 | .member_types = member_types[0..member_index], | 1354 | .member_types = member_types[0..member_index], |
| 1351 | } }); | 1355 | } }); |
| 1352 | }, | 1356 | }, |
| 1353 | .struct_type => |struct_ty| struct_ty, | 1357 | .struct_type => |struct_type| struct_type, |
| 1354 | else => unreachable, | 1358 | else => unreachable, |
| 1355 | }; | 1359 | }; |
| 1356 | 1360 | ||
| 1357 | const struct_obj = mod.structPtrUnwrap(struct_ty.index).?; | 1361 | if (struct_type.layout == .Packed) { |
| 1358 | if (struct_obj.layout == .Packed) { | 1362 | return try self.resolveType(struct_type.backingIntType(ip).toType(), .direct); |
| 1359 | return try self.resolveType(struct_obj.backing_int_ty, .direct); | ||
| 1360 | } | 1363 | } |
| 1361 | 1364 | ||
| 1362 | var member_types = std.ArrayList(CacheRef).init(self.gpa); | 1365 | var member_types = std.ArrayList(CacheRef).init(self.gpa); |
| ... | @@ -1365,16 +1368,15 @@ pub const DeclGen = struct { | ... | @@ -1365,16 +1368,15 @@ pub const DeclGen = struct { |
| 1365 | var member_names = std.ArrayList(CacheString).init(self.gpa); | 1368 | var member_names = std.ArrayList(CacheString).init(self.gpa); |
| 1366 | defer member_names.deinit(); | 1369 | defer member_names.deinit(); |
| 1367 | 1370 | ||
| 1368 | var it = struct_obj.runtimeFieldIterator(mod); | 1371 | var it = struct_type.iterateRuntimeOrder(ip); |
| 1369 | while (it.next()) |field_and_index| { | 1372 | while (it.next()) |field_index| { |
| 1370 | const field = field_and_index.field; | 1373 | const field_ty = struct_type.field_types.get(ip)[field_index]; |
| 1371 | const index = field_and_index.index; | 1374 | const field_name = ip.stringToSlice(struct_type.field_names.get(ip)[field_index]); |
| 1372 | const field_name = ip.stringToSlice(struct_obj.fields.keys()[index]); | 1375 | try member_types.append(try self.resolveType(field_ty.toType(), .indirect)); |
| 1373 | try member_types.append(try self.resolveType(field.ty, .indirect)); | ||
| 1374 | try member_names.append(try self.spv.resolveString(field_name)); | 1376 | try member_names.append(try self.spv.resolveString(field_name)); |
| 1375 | } | 1377 | } |
| 1376 | 1378 | ||
| 1377 | const name = ip.stringToSlice(try struct_obj.getFullyQualifiedName(self.module)); | 1379 | const name = ip.stringToSlice(try mod.declPtr(struct_type.decl.unwrap().?).getFullyQualifiedName(mod)); |
| 1378 | 1380 | ||
| 1379 | return try self.spv.resolve(.{ .struct_type = .{ | 1381 | return try self.spv.resolve(.{ .struct_type = .{ |
| 1380 | .name = try self.spv.resolveString(name), | 1382 | .name = try self.spv.resolveString(name), |
| ... | @@ -1500,7 +1502,7 @@ pub const DeclGen = struct { | ... | @@ -1500,7 +1502,7 @@ pub const DeclGen = struct { |
| 1500 | const error_align = Type.anyerror.abiAlignment(mod); | 1502 | const error_align = Type.anyerror.abiAlignment(mod); |
| 1501 | const payload_align = payload_ty.abiAlignment(mod); | 1503 | const payload_align = payload_ty.abiAlignment(mod); |
| 1502 | 1504 | ||
| 1503 | const error_first = error_align > payload_align; | 1505 | const error_first = error_align.compare(.gt, payload_align); |
| 1504 | return .{ | 1506 | return .{ |
| 1505 | .payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(mod), | 1507 | .payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(mod), |
| 1506 | .error_first = error_first, | 1508 | .error_first = error_first, |
| ... | @@ -1662,7 +1664,7 @@ pub const DeclGen = struct { | ... | @@ -1662,7 +1664,7 @@ pub const DeclGen = struct { |
| 1662 | init_val, | 1664 | init_val, |
| 1663 | actual_storage_class, | 1665 | actual_storage_class, |
| 1664 | final_storage_class == .Generic, | 1666 | final_storage_class == .Generic, |
| 1665 | @as(u32, @intCast(decl.alignment.toByteUnits(0))), | 1667 | @intCast(decl.alignment.toByteUnits(0)), |
| 1666 | ); | 1668 | ); |
| 1667 | } | 1669 | } |
| 1668 | } | 1670 | } |
| ... | @@ -2603,7 +2605,7 @@ pub const DeclGen = struct { | ... | @@ -2603,7 +2605,7 @@ pub const DeclGen = struct { |
| 2603 | if (layout.payload_size == 0) return union_handle; | 2605 | if (layout.payload_size == 0) return union_handle; |
| 2604 | 2606 | ||
| 2605 | const tag_ty = un_ty.unionTagTypeSafety(mod).?; | 2607 | const tag_ty = un_ty.unionTagTypeSafety(mod).?; |
| 2606 | const tag_index = @intFromBool(layout.tag_align < layout.payload_align); | 2608 | const tag_index = @intFromBool(layout.tag_align.compare(.lt, layout.payload_align)); |
| 2607 | return try self.extractField(tag_ty, union_handle, tag_index); | 2609 | return try self.extractField(tag_ty, union_handle, tag_index); |
| 2608 | } | 2610 | } |
| 2609 | 2611 |
src/link/Coff.zig+4-4| ... | @@ -1118,7 +1118,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In | ... | @@ -1118,7 +1118,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In |
| 1118 | }, | 1118 | }, |
| 1119 | }; | 1119 | }; |
| 1120 | 1120 | ||
| 1121 | const required_alignment = tv.ty.abiAlignment(mod); | 1121 | const required_alignment: u32 = @intCast(tv.ty.abiAlignment(mod).toByteUnits(0)); |
| 1122 | const atom = self.getAtomPtr(atom_index); | 1122 | const atom = self.getAtomPtr(atom_index); |
| 1123 | atom.size = @as(u32, @intCast(code.len)); | 1123 | atom.size = @as(u32, @intCast(code.len)); |
| 1124 | atom.getSymbolPtr(self).value = try self.allocateAtom(atom_index, atom.size, required_alignment); | 1124 | atom.getSymbolPtr(self).value = try self.allocateAtom(atom_index, atom.size, required_alignment); |
| ... | @@ -1196,7 +1196,7 @@ fn updateLazySymbolAtom( | ... | @@ -1196,7 +1196,7 @@ fn updateLazySymbolAtom( |
| 1196 | const gpa = self.base.allocator; | 1196 | const gpa = self.base.allocator; |
| 1197 | const mod = self.base.options.module.?; | 1197 | const mod = self.base.options.module.?; |
| 1198 | 1198 | ||
| 1199 | var required_alignment: u32 = undefined; | 1199 | var required_alignment: InternPool.Alignment = .none; |
| 1200 | var code_buffer = std.ArrayList(u8).init(gpa); | 1200 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 1201 | defer code_buffer.deinit(); | 1201 | defer code_buffer.deinit(); |
| 1202 | 1202 | ||
| ... | @@ -1240,7 +1240,7 @@ fn updateLazySymbolAtom( | ... | @@ -1240,7 +1240,7 @@ fn updateLazySymbolAtom( |
| 1240 | symbol.section_number = @as(coff.SectionNumber, @enumFromInt(section_index + 1)); | 1240 | symbol.section_number = @as(coff.SectionNumber, @enumFromInt(section_index + 1)); |
| 1241 | symbol.type = .{ .complex_type = .NULL, .base_type = .NULL }; | 1241 | symbol.type = .{ .complex_type = .NULL, .base_type = .NULL }; |
| 1242 | 1242 | ||
| 1243 | const vaddr = try self.allocateAtom(atom_index, code_len, required_alignment); | 1243 | const vaddr = try self.allocateAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits(0))); |
| 1244 | errdefer self.freeAtom(atom_index); | 1244 | errdefer self.freeAtom(atom_index); |
| 1245 | 1245 | ||
| 1246 | log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr }); | 1246 | log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr }); |
| ... | @@ -1322,7 +1322,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []u8, comple | ... | @@ -1322,7 +1322,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []u8, comple |
| 1322 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); | 1322 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| 1323 | 1323 | ||
| 1324 | log.debug("updateDeclCode {s}{*}", .{ decl_name, decl }); | 1324 | log.debug("updateDeclCode {s}{*}", .{ decl_name, decl }); |
| 1325 | const required_alignment = decl.getAlignment(mod); | 1325 | const required_alignment: u32 = @intCast(decl.getAlignment(mod).toByteUnits(0)); |
| 1326 | 1326 | ||
| 1327 | const decl_metadata = self.decls.get(decl_index).?; | 1327 | const decl_metadata = self.decls.get(decl_index).?; |
| 1328 | const atom_index = decl_metadata.atom; | 1328 | const atom_index = decl_metadata.atom; |
src/link/Dwarf.zig+13-15| ... | @@ -341,23 +341,22 @@ pub const DeclState = struct { | ... | @@ -341,23 +341,22 @@ pub const DeclState = struct { |
| 341 | try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); | 341 | try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); |
| 342 | } | 342 | } |
| 343 | }, | 343 | }, |
| 344 | .struct_type => |struct_type| s: { | 344 | .struct_type => |struct_type| { |
| 345 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :s; | ||
| 346 | // DW.AT.name, DW.FORM.string | 345 | // DW.AT.name, DW.FORM.string |
| 347 | try ty.print(dbg_info_buffer.writer(), mod); | 346 | try ty.print(dbg_info_buffer.writer(), mod); |
| 348 | try dbg_info_buffer.append(0); | 347 | try dbg_info_buffer.append(0); |
| 349 | 348 | ||
| 350 | if (struct_obj.layout == .Packed) { | 349 | if (struct_type.layout == .Packed) { |
| 351 | log.debug("TODO implement .debug_info for packed structs", .{}); | 350 | log.debug("TODO implement .debug_info for packed structs", .{}); |
| 352 | break :blk; | 351 | break :blk; |
| 353 | } | 352 | } |
| 354 | 353 | ||
| 355 | for ( | 354 | for ( |
| 356 | struct_obj.fields.keys(), | 355 | struct_type.field_names.get(ip), |
| 357 | struct_obj.fields.values(), | 356 | struct_type.field_types.get(ip), |
| 358 | 0.., | 357 | struct_type.offsets.get(ip), |
| 359 | ) |field_name_ip, field, field_index| { | 358 | ) |field_name_ip, field_ty, field_off| { |
| 360 | if (!field.ty.hasRuntimeBits(mod)) continue; | 359 | if (!field_ty.toType().hasRuntimeBits(mod)) continue; |
| 361 | const field_name = ip.stringToSlice(field_name_ip); | 360 | const field_name = ip.stringToSlice(field_name_ip); |
| 362 | // DW.AT.member | 361 | // DW.AT.member |
| 363 | try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2); | 362 | try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2); |
| ... | @@ -368,9 +367,8 @@ pub const DeclState = struct { | ... | @@ -368,9 +367,8 @@ pub const DeclState = struct { |
| 368 | // DW.AT.type, DW.FORM.ref4 | 367 | // DW.AT.type, DW.FORM.ref4 |
| 369 | var index = dbg_info_buffer.items.len; | 368 | var index = dbg_info_buffer.items.len; |
| 370 | try dbg_info_buffer.resize(index + 4); | 369 | try dbg_info_buffer.resize(index + 4); |
| 371 | try self.addTypeRelocGlobal(atom_index, field.ty, @as(u32, @intCast(index))); | 370 | try self.addTypeRelocGlobal(atom_index, field_ty.toType(), @intCast(index)); |
| 372 | // DW.AT.data_member_location, DW.FORM.udata | 371 | // DW.AT.data_member_location, DW.FORM.udata |
| 373 | const field_off = ty.structFieldOffset(field_index, mod); | ||
| 374 | try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); | 372 | try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); |
| 375 | } | 373 | } |
| 376 | }, | 374 | }, |
| ... | @@ -416,8 +414,8 @@ pub const DeclState = struct { | ... | @@ -416,8 +414,8 @@ pub const DeclState = struct { |
| 416 | .Union => { | 414 | .Union => { |
| 417 | const union_obj = mod.typeToUnion(ty).?; | 415 | const union_obj = mod.typeToUnion(ty).?; |
| 418 | const layout = mod.getUnionLayout(union_obj); | 416 | const layout = mod.getUnionLayout(union_obj); |
| 419 | const payload_offset = if (layout.tag_align >= layout.payload_align) layout.tag_size else 0; | 417 | const payload_offset = if (layout.tag_align.compare(.gte, layout.payload_align)) layout.tag_size else 0; |
| 420 | const tag_offset = if (layout.tag_align >= layout.payload_align) 0 else layout.payload_size; | 418 | const tag_offset = if (layout.tag_align.compare(.gte, layout.payload_align)) 0 else layout.payload_size; |
| 421 | // TODO this is temporary to match current state of unions in Zig - we don't yet have | 419 | // TODO this is temporary to match current state of unions in Zig - we don't yet have |
| 422 | // safety checks implemented meaning the implicit tag is not yet stored and generated | 420 | // safety checks implemented meaning the implicit tag is not yet stored and generated |
| 423 | // for untagged unions. | 421 | // for untagged unions. |
| ... | @@ -496,11 +494,11 @@ pub const DeclState = struct { | ... | @@ -496,11 +494,11 @@ pub const DeclState = struct { |
| 496 | .ErrorUnion => { | 494 | .ErrorUnion => { |
| 497 | const error_ty = ty.errorUnionSet(mod); | 495 | const error_ty = ty.errorUnionSet(mod); |
| 498 | const payload_ty = ty.errorUnionPayload(mod); | 496 | const payload_ty = ty.errorUnionPayload(mod); |
| 499 | const payload_align = if (payload_ty.isNoReturn(mod)) 0 else payload_ty.abiAlignment(mod); | 497 | const payload_align = if (payload_ty.isNoReturn(mod)) .none else payload_ty.abiAlignment(mod); |
| 500 | const error_align = Type.anyerror.abiAlignment(mod); | 498 | const error_align = Type.anyerror.abiAlignment(mod); |
| 501 | const abi_size = ty.abiSize(mod); | 499 | const abi_size = ty.abiSize(mod); |
| 502 | const payload_off = if (error_align >= payload_align) Type.anyerror.abiSize(mod) else 0; | 500 | const payload_off = if (error_align.compare(.gte, payload_align)) Type.anyerror.abiSize(mod) else 0; |
| 503 | const error_off = if (error_align >= payload_align) 0 else payload_ty.abiSize(mod); | 501 | const error_off = if (error_align.compare(.gte, payload_align)) 0 else payload_ty.abiSize(mod); |
| 504 | 502 | ||
| 505 | // DW.AT.structure_type | 503 | // DW.AT.structure_type |
| 506 | try dbg_info_buffer.append(@intFromEnum(AbbrevKind.struct_type)); | 504 | try dbg_info_buffer.append(@intFromEnum(AbbrevKind.struct_type)); |
src/link/Elf.zig+26-26| ... | @@ -409,7 +409,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -409,7 +409,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 409 | const image_base = self.calcImageBase(); | 409 | const image_base = self.calcImageBase(); |
| 410 | 410 | ||
| 411 | if (self.phdr_table_index == null) { | 411 | if (self.phdr_table_index == null) { |
| 412 | self.phdr_table_index = @as(u16, @intCast(self.phdrs.items.len)); | 412 | self.phdr_table_index = @intCast(self.phdrs.items.len); |
| 413 | const p_align: u16 = switch (self.ptr_width) { | 413 | const p_align: u16 = switch (self.ptr_width) { |
| 414 | .p32 => @alignOf(elf.Elf32_Phdr), | 414 | .p32 => @alignOf(elf.Elf32_Phdr), |
| 415 | .p64 => @alignOf(elf.Elf64_Phdr), | 415 | .p64 => @alignOf(elf.Elf64_Phdr), |
| ... | @@ -428,7 +428,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -428,7 +428,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 428 | } | 428 | } |
| 429 | 429 | ||
| 430 | if (self.phdr_table_load_index == null) { | 430 | if (self.phdr_table_load_index == null) { |
| 431 | self.phdr_table_load_index = @as(u16, @intCast(self.phdrs.items.len)); | 431 | self.phdr_table_load_index = @intCast(self.phdrs.items.len); |
| 432 | // TODO Same as for GOT | 432 | // TODO Same as for GOT |
| 433 | try self.phdrs.append(gpa, .{ | 433 | try self.phdrs.append(gpa, .{ |
| 434 | .p_type = elf.PT_LOAD, | 434 | .p_type = elf.PT_LOAD, |
| ... | @@ -444,7 +444,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -444,7 +444,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 444 | } | 444 | } |
| 445 | 445 | ||
| 446 | if (self.phdr_load_re_index == null) { | 446 | if (self.phdr_load_re_index == null) { |
| 447 | self.phdr_load_re_index = @as(u16, @intCast(self.phdrs.items.len)); | 447 | self.phdr_load_re_index = @intCast(self.phdrs.items.len); |
| 448 | const file_size = self.base.options.program_code_size_hint; | 448 | const file_size = self.base.options.program_code_size_hint; |
| 449 | const p_align = self.page_size; | 449 | const p_align = self.page_size; |
| 450 | const off = self.findFreeSpace(file_size, p_align); | 450 | const off = self.findFreeSpace(file_size, p_align); |
| ... | @@ -465,7 +465,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -465,7 +465,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 465 | } | 465 | } |
| 466 | 466 | ||
| 467 | if (self.phdr_got_index == null) { | 467 | if (self.phdr_got_index == null) { |
| 468 | self.phdr_got_index = @as(u16, @intCast(self.phdrs.items.len)); | 468 | self.phdr_got_index = @intCast(self.phdrs.items.len); |
| 469 | const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint; | 469 | const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint; |
| 470 | // We really only need ptr alignment but since we are using PROGBITS, linux requires | 470 | // We really only need ptr alignment but since we are using PROGBITS, linux requires |
| 471 | // page align. | 471 | // page align. |
| ... | @@ -490,7 +490,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -490,7 +490,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 490 | } | 490 | } |
| 491 | 491 | ||
| 492 | if (self.phdr_load_ro_index == null) { | 492 | if (self.phdr_load_ro_index == null) { |
| 493 | self.phdr_load_ro_index = @as(u16, @intCast(self.phdrs.items.len)); | 493 | self.phdr_load_ro_index = @intCast(self.phdrs.items.len); |
| 494 | // TODO Find a hint about how much data need to be in rodata ? | 494 | // TODO Find a hint about how much data need to be in rodata ? |
| 495 | const file_size = 1024; | 495 | const file_size = 1024; |
| 496 | // Same reason as for GOT | 496 | // Same reason as for GOT |
| ... | @@ -513,7 +513,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -513,7 +513,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 513 | } | 513 | } |
| 514 | 514 | ||
| 515 | if (self.phdr_load_rw_index == null) { | 515 | if (self.phdr_load_rw_index == null) { |
| 516 | self.phdr_load_rw_index = @as(u16, @intCast(self.phdrs.items.len)); | 516 | self.phdr_load_rw_index = @intCast(self.phdrs.items.len); |
| 517 | // TODO Find a hint about how much data need to be in data ? | 517 | // TODO Find a hint about how much data need to be in data ? |
| 518 | const file_size = 1024; | 518 | const file_size = 1024; |
| 519 | // Same reason as for GOT | 519 | // Same reason as for GOT |
| ... | @@ -536,7 +536,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -536,7 +536,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 536 | } | 536 | } |
| 537 | 537 | ||
| 538 | if (self.phdr_load_zerofill_index == null) { | 538 | if (self.phdr_load_zerofill_index == null) { |
| 539 | self.phdr_load_zerofill_index = @as(u16, @intCast(self.phdrs.items.len)); | 539 | self.phdr_load_zerofill_index = @intCast(self.phdrs.items.len); |
| 540 | const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); | 540 | const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); |
| 541 | const off = self.phdrs.items[self.phdr_load_rw_index.?].p_offset; | 541 | const off = self.phdrs.items[self.phdr_load_rw_index.?].p_offset; |
| 542 | log.debug("found PT_LOAD zerofill free space 0x{x} to 0x{x}", .{ off, off }); | 542 | log.debug("found PT_LOAD zerofill free space 0x{x} to 0x{x}", .{ off, off }); |
| ... | @@ -556,7 +556,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -556,7 +556,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 556 | } | 556 | } |
| 557 | 557 | ||
| 558 | if (self.shstrtab_section_index == null) { | 558 | if (self.shstrtab_section_index == null) { |
| 559 | self.shstrtab_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 559 | self.shstrtab_section_index = @intCast(self.shdrs.items.len); |
| 560 | assert(self.shstrtab.buffer.items.len == 0); | 560 | assert(self.shstrtab.buffer.items.len == 0); |
| 561 | try self.shstrtab.buffer.append(gpa, 0); // need a 0 at position 0 | 561 | try self.shstrtab.buffer.append(gpa, 0); // need a 0 at position 0 |
| 562 | const off = self.findFreeSpace(self.shstrtab.buffer.items.len, 1); | 562 | const off = self.findFreeSpace(self.shstrtab.buffer.items.len, 1); |
| ... | @@ -578,7 +578,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -578,7 +578,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 578 | } | 578 | } |
| 579 | 579 | ||
| 580 | if (self.strtab_section_index == null) { | 580 | if (self.strtab_section_index == null) { |
| 581 | self.strtab_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 581 | self.strtab_section_index = @intCast(self.shdrs.items.len); |
| 582 | assert(self.strtab.buffer.items.len == 0); | 582 | assert(self.strtab.buffer.items.len == 0); |
| 583 | try self.strtab.buffer.append(gpa, 0); // need a 0 at position 0 | 583 | try self.strtab.buffer.append(gpa, 0); // need a 0 at position 0 |
| 584 | const off = self.findFreeSpace(self.strtab.buffer.items.len, 1); | 584 | const off = self.findFreeSpace(self.strtab.buffer.items.len, 1); |
| ... | @@ -600,7 +600,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -600,7 +600,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 600 | } | 600 | } |
| 601 | 601 | ||
| 602 | if (self.text_section_index == null) { | 602 | if (self.text_section_index == null) { |
| 603 | self.text_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 603 | self.text_section_index = @intCast(self.shdrs.items.len); |
| 604 | const phdr = &self.phdrs.items[self.phdr_load_re_index.?]; | 604 | const phdr = &self.phdrs.items[self.phdr_load_re_index.?]; |
| 605 | try self.shdrs.append(gpa, .{ | 605 | try self.shdrs.append(gpa, .{ |
| 606 | .sh_name = try self.shstrtab.insert(gpa, ".text"), | 606 | .sh_name = try self.shstrtab.insert(gpa, ".text"), |
| ... | @@ -620,7 +620,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -620,7 +620,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 620 | } | 620 | } |
| 621 | 621 | ||
| 622 | if (self.got_section_index == null) { | 622 | if (self.got_section_index == null) { |
| 623 | self.got_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 623 | self.got_section_index = @intCast(self.shdrs.items.len); |
| 624 | const phdr = &self.phdrs.items[self.phdr_got_index.?]; | 624 | const phdr = &self.phdrs.items[self.phdr_got_index.?]; |
| 625 | try self.shdrs.append(gpa, .{ | 625 | try self.shdrs.append(gpa, .{ |
| 626 | .sh_name = try self.shstrtab.insert(gpa, ".got"), | 626 | .sh_name = try self.shstrtab.insert(gpa, ".got"), |
| ... | @@ -639,7 +639,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -639,7 +639,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 639 | } | 639 | } |
| 640 | 640 | ||
| 641 | if (self.rodata_section_index == null) { | 641 | if (self.rodata_section_index == null) { |
| 642 | self.rodata_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 642 | self.rodata_section_index = @intCast(self.shdrs.items.len); |
| 643 | const phdr = &self.phdrs.items[self.phdr_load_ro_index.?]; | 643 | const phdr = &self.phdrs.items[self.phdr_load_ro_index.?]; |
| 644 | try self.shdrs.append(gpa, .{ | 644 | try self.shdrs.append(gpa, .{ |
| 645 | .sh_name = try self.shstrtab.insert(gpa, ".rodata"), | 645 | .sh_name = try self.shstrtab.insert(gpa, ".rodata"), |
| ... | @@ -659,7 +659,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -659,7 +659,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 659 | } | 659 | } |
| 660 | 660 | ||
| 661 | if (self.data_section_index == null) { | 661 | if (self.data_section_index == null) { |
| 662 | self.data_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 662 | self.data_section_index = @intCast(self.shdrs.items.len); |
| 663 | const phdr = &self.phdrs.items[self.phdr_load_rw_index.?]; | 663 | const phdr = &self.phdrs.items[self.phdr_load_rw_index.?]; |
| 664 | try self.shdrs.append(gpa, .{ | 664 | try self.shdrs.append(gpa, .{ |
| 665 | .sh_name = try self.shstrtab.insert(gpa, ".data"), | 665 | .sh_name = try self.shstrtab.insert(gpa, ".data"), |
| ... | @@ -679,7 +679,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -679,7 +679,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 679 | } | 679 | } |
| 680 | 680 | ||
| 681 | if (self.bss_section_index == null) { | 681 | if (self.bss_section_index == null) { |
| 682 | self.bss_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 682 | self.bss_section_index = @intCast(self.shdrs.items.len); |
| 683 | const phdr = &self.phdrs.items[self.phdr_load_zerofill_index.?]; | 683 | const phdr = &self.phdrs.items[self.phdr_load_zerofill_index.?]; |
| 684 | try self.shdrs.append(gpa, .{ | 684 | try self.shdrs.append(gpa, .{ |
| 685 | .sh_name = try self.shstrtab.insert(gpa, ".bss"), | 685 | .sh_name = try self.shstrtab.insert(gpa, ".bss"), |
| ... | @@ -699,7 +699,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -699,7 +699,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 699 | } | 699 | } |
| 700 | 700 | ||
| 701 | if (self.symtab_section_index == null) { | 701 | if (self.symtab_section_index == null) { |
| 702 | self.symtab_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 702 | self.symtab_section_index = @intCast(self.shdrs.items.len); |
| 703 | const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym); | 703 | const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym); |
| 704 | const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym); | 704 | const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym); |
| 705 | const file_size = self.base.options.symbol_count_hint * each_size; | 705 | const file_size = self.base.options.symbol_count_hint * each_size; |
| ... | @@ -714,7 +714,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -714,7 +714,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 714 | .sh_size = file_size, | 714 | .sh_size = file_size, |
| 715 | // The section header index of the associated string table. | 715 | // The section header index of the associated string table. |
| 716 | .sh_link = self.strtab_section_index.?, | 716 | .sh_link = self.strtab_section_index.?, |
| 717 | .sh_info = @as(u32, @intCast(self.symbols.items.len)), | 717 | .sh_info = @intCast(self.symbols.items.len), |
| 718 | .sh_addralign = min_align, | 718 | .sh_addralign = min_align, |
| 719 | .sh_entsize = each_size, | 719 | .sh_entsize = each_size, |
| 720 | }); | 720 | }); |
| ... | @@ -723,7 +723,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -723,7 +723,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 723 | 723 | ||
| 724 | if (self.dwarf) |*dw| { | 724 | if (self.dwarf) |*dw| { |
| 725 | if (self.debug_str_section_index == null) { | 725 | if (self.debug_str_section_index == null) { |
| 726 | self.debug_str_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 726 | self.debug_str_section_index = @intCast(self.shdrs.items.len); |
| 727 | assert(dw.strtab.buffer.items.len == 0); | 727 | assert(dw.strtab.buffer.items.len == 0); |
| 728 | try dw.strtab.buffer.append(gpa, 0); | 728 | try dw.strtab.buffer.append(gpa, 0); |
| 729 | try self.shdrs.append(gpa, .{ | 729 | try self.shdrs.append(gpa, .{ |
| ... | @@ -743,7 +743,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -743,7 +743,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 743 | } | 743 | } |
| 744 | 744 | ||
| 745 | if (self.debug_info_section_index == null) { | 745 | if (self.debug_info_section_index == null) { |
| 746 | self.debug_info_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 746 | self.debug_info_section_index = @intCast(self.shdrs.items.len); |
| 747 | const file_size_hint = 200; | 747 | const file_size_hint = 200; |
| 748 | const p_align = 1; | 748 | const p_align = 1; |
| 749 | const off = self.findFreeSpace(file_size_hint, p_align); | 749 | const off = self.findFreeSpace(file_size_hint, p_align); |
| ... | @@ -768,7 +768,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -768,7 +768,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 768 | } | 768 | } |
| 769 | 769 | ||
| 770 | if (self.debug_abbrev_section_index == null) { | 770 | if (self.debug_abbrev_section_index == null) { |
| 771 | self.debug_abbrev_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 771 | self.debug_abbrev_section_index = @intCast(self.shdrs.items.len); |
| 772 | const file_size_hint = 128; | 772 | const file_size_hint = 128; |
| 773 | const p_align = 1; | 773 | const p_align = 1; |
| 774 | const off = self.findFreeSpace(file_size_hint, p_align); | 774 | const off = self.findFreeSpace(file_size_hint, p_align); |
| ... | @@ -793,7 +793,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -793,7 +793,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 793 | } | 793 | } |
| 794 | 794 | ||
| 795 | if (self.debug_aranges_section_index == null) { | 795 | if (self.debug_aranges_section_index == null) { |
| 796 | self.debug_aranges_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 796 | self.debug_aranges_section_index = @intCast(self.shdrs.items.len); |
| 797 | const file_size_hint = 160; | 797 | const file_size_hint = 160; |
| 798 | const p_align = 16; | 798 | const p_align = 16; |
| 799 | const off = self.findFreeSpace(file_size_hint, p_align); | 799 | const off = self.findFreeSpace(file_size_hint, p_align); |
| ... | @@ -818,7 +818,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -818,7 +818,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 818 | } | 818 | } |
| 819 | 819 | ||
| 820 | if (self.debug_line_section_index == null) { | 820 | if (self.debug_line_section_index == null) { |
| 821 | self.debug_line_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 821 | self.debug_line_section_index = @intCast(self.shdrs.items.len); |
| 822 | const file_size_hint = 250; | 822 | const file_size_hint = 250; |
| 823 | const p_align = 1; | 823 | const p_align = 1; |
| 824 | const off = self.findFreeSpace(file_size_hint, p_align); | 824 | const off = self.findFreeSpace(file_size_hint, p_align); |
| ... | @@ -2666,12 +2666,12 @@ fn updateDeclCode( | ... | @@ -2666,12 +2666,12 @@ fn updateDeclCode( |
| 2666 | 2666 | ||
| 2667 | const old_size = atom_ptr.size; | 2667 | const old_size = atom_ptr.size; |
| 2668 | const old_vaddr = atom_ptr.value; | 2668 | const old_vaddr = atom_ptr.value; |
| 2669 | atom_ptr.alignment = math.log2_int(u64, required_alignment); | 2669 | atom_ptr.alignment = required_alignment; |
| 2670 | atom_ptr.size = code.len; | 2670 | atom_ptr.size = code.len; |
| 2671 | 2671 | ||
| 2672 | if (old_size > 0 and self.base.child_pid == null) { | 2672 | if (old_size > 0 and self.base.child_pid == null) { |
| 2673 | const capacity = atom_ptr.capacity(self); | 2673 | const capacity = atom_ptr.capacity(self); |
| 2674 | const need_realloc = code.len > capacity or !mem.isAlignedGeneric(u64, sym.value, required_alignment); | 2674 | const need_realloc = code.len > capacity or !required_alignment.check(sym.value); |
| 2675 | if (need_realloc) { | 2675 | if (need_realloc) { |
| 2676 | try atom_ptr.grow(self); | 2676 | try atom_ptr.grow(self); |
| 2677 | log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, old_vaddr, atom_ptr.value }); | 2677 | log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, old_vaddr, atom_ptr.value }); |
| ... | @@ -2869,7 +2869,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. | ... | @@ -2869,7 +2869,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. |
| 2869 | const mod = self.base.options.module.?; | 2869 | const mod = self.base.options.module.?; |
| 2870 | const zig_module = self.file(self.zig_module_index.?).?.zig_module; | 2870 | const zig_module = self.file(self.zig_module_index.?).?.zig_module; |
| 2871 | 2871 | ||
| 2872 | var required_alignment: u32 = undefined; | 2872 | var required_alignment: InternPool.Alignment = .none; |
| 2873 | var code_buffer = std.ArrayList(u8).init(gpa); | 2873 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 2874 | defer code_buffer.deinit(); | 2874 | defer code_buffer.deinit(); |
| 2875 | 2875 | ||
| ... | @@ -2918,7 +2918,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. | ... | @@ -2918,7 +2918,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. |
| 2918 | const atom_ptr = local_sym.atom(self).?; | 2918 | const atom_ptr = local_sym.atom(self).?; |
| 2919 | atom_ptr.alive = true; | 2919 | atom_ptr.alive = true; |
| 2920 | atom_ptr.name_offset = name_str_index; | 2920 | atom_ptr.name_offset = name_str_index; |
| 2921 | atom_ptr.alignment = math.log2_int(u64, required_alignment); | 2921 | atom_ptr.alignment = required_alignment; |
| 2922 | atom_ptr.size = code.len; | 2922 | atom_ptr.size = code.len; |
| 2923 | 2923 | ||
| 2924 | try atom_ptr.allocate(self); | 2924 | try atom_ptr.allocate(self); |
| ... | @@ -2995,7 +2995,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module | ... | @@ -2995,7 +2995,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module |
| 2995 | const atom_ptr = local_sym.atom(self).?; | 2995 | const atom_ptr = local_sym.atom(self).?; |
| 2996 | atom_ptr.alive = true; | 2996 | atom_ptr.alive = true; |
| 2997 | atom_ptr.name_offset = name_str_index; | 2997 | atom_ptr.name_offset = name_str_index; |
| 2998 | atom_ptr.alignment = math.log2_int(u64, required_alignment); | 2998 | atom_ptr.alignment = required_alignment; |
| 2999 | atom_ptr.size = code.len; | 2999 | atom_ptr.size = code.len; |
| 3000 | 3000 | ||
| 3001 | try atom_ptr.allocate(self); | 3001 | try atom_ptr.allocate(self); |
src/link/Elf/Atom.zig+8-9| ... | @@ -11,7 +11,7 @@ file_index: File.Index = 0, | ... | @@ -11,7 +11,7 @@ file_index: File.Index = 0, |
| 11 | size: u64 = 0, | 11 | size: u64 = 0, |
| 12 | 12 | ||
| 13 | /// Alignment of this atom as a power of two. | 13 | /// Alignment of this atom as a power of two. |
| 14 | alignment: u8 = 0, | 14 | alignment: Alignment = .@"1", |
| 15 | 15 | ||
| 16 | /// Index of the input section. | 16 | /// Index of the input section. |
| 17 | input_section_index: Index = 0, | 17 | input_section_index: Index = 0, |
| ... | @@ -42,6 +42,8 @@ fde_end: u32 = 0, | ... | @@ -42,6 +42,8 @@ fde_end: u32 = 0, |
| 42 | prev_index: Index = 0, | 42 | prev_index: Index = 0, |
| 43 | next_index: Index = 0, | 43 | next_index: Index = 0, |
| 44 | 44 | ||
| 45 | pub const Alignment = @import("../../InternPool.zig").Alignment; | ||
| 46 | |||
| 45 | pub fn name(self: Atom, elf_file: *Elf) []const u8 { | 47 | pub fn name(self: Atom, elf_file: *Elf) []const u8 { |
| 46 | return elf_file.strtab.getAssumeExists(self.name_offset); | 48 | return elf_file.strtab.getAssumeExists(self.name_offset); |
| 47 | } | 49 | } |
| ... | @@ -112,7 +114,6 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { | ... | @@ -112,7 +114,6 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { |
| 112 | const free_list = &meta.free_list; | 114 | const free_list = &meta.free_list; |
| 113 | const last_atom_index = &meta.last_atom_index; | 115 | const last_atom_index = &meta.last_atom_index; |
| 114 | const new_atom_ideal_capacity = Elf.padToIdeal(self.size); | 116 | const new_atom_ideal_capacity = Elf.padToIdeal(self.size); |
| 115 | const alignment = try std.math.powi(u64, 2, self.alignment); | ||
| 116 | 117 | ||
| 117 | // We use these to indicate our intention to update metadata, placing the new atom, | 118 | // We use these to indicate our intention to update metadata, placing the new atom, |
| 118 | // and possibly removing a free list node. | 119 | // and possibly removing a free list node. |
| ... | @@ -136,7 +137,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { | ... | @@ -136,7 +137,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { |
| 136 | const ideal_capacity_end_vaddr = std.math.add(u64, big_atom.value, ideal_capacity) catch ideal_capacity; | 137 | const ideal_capacity_end_vaddr = std.math.add(u64, big_atom.value, ideal_capacity) catch ideal_capacity; |
| 137 | const capacity_end_vaddr = big_atom.value + cap; | 138 | const capacity_end_vaddr = big_atom.value + cap; |
| 138 | const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity; | 139 | const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity; |
| 139 | const new_start_vaddr = std.mem.alignBackward(u64, new_start_vaddr_unaligned, alignment); | 140 | const new_start_vaddr = self.alignment.backward(new_start_vaddr_unaligned); |
| 140 | if (new_start_vaddr < ideal_capacity_end_vaddr) { | 141 | if (new_start_vaddr < ideal_capacity_end_vaddr) { |
| 141 | // Additional bookkeeping here to notice if this free list node | 142 | // Additional bookkeeping here to notice if this free list node |
| 142 | // should be deleted because the block that it points to has grown to take up | 143 | // should be deleted because the block that it points to has grown to take up |
| ... | @@ -163,7 +164,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { | ... | @@ -163,7 +164,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { |
| 163 | } else if (elf_file.atom(last_atom_index.*)) |last| { | 164 | } else if (elf_file.atom(last_atom_index.*)) |last| { |
| 164 | const ideal_capacity = Elf.padToIdeal(last.size); | 165 | const ideal_capacity = Elf.padToIdeal(last.size); |
| 165 | const ideal_capacity_end_vaddr = last.value + ideal_capacity; | 166 | const ideal_capacity_end_vaddr = last.value + ideal_capacity; |
| 166 | const new_start_vaddr = std.mem.alignForward(u64, ideal_capacity_end_vaddr, alignment); | 167 | const new_start_vaddr = self.alignment.forward(ideal_capacity_end_vaddr); |
| 167 | // Set up the metadata to be updated, after errors are no longer possible. | 168 | // Set up the metadata to be updated, after errors are no longer possible. |
| 168 | atom_placement = last.atom_index; | 169 | atom_placement = last.atom_index; |
| 169 | break :blk new_start_vaddr; | 170 | break :blk new_start_vaddr; |
| ... | @@ -192,7 +193,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { | ... | @@ -192,7 +193,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { |
| 192 | elf_file.debug_aranges_section_dirty = true; | 193 | elf_file.debug_aranges_section_dirty = true; |
| 193 | } | 194 | } |
| 194 | } | 195 | } |
| 195 | shdr.sh_addralign = @max(shdr.sh_addralign, alignment); | 196 | shdr.sh_addralign = @max(shdr.sh_addralign, self.alignment.toByteUnitsOptional().?); |
| 196 | 197 | ||
| 197 | // This function can also reallocate an atom. | 198 | // This function can also reallocate an atom. |
| 198 | // In this case we need to "unplug" it from its previous location before | 199 | // In this case we need to "unplug" it from its previous location before |
| ... | @@ -224,10 +225,8 @@ pub fn shrink(self: *Atom, elf_file: *Elf) void { | ... | @@ -224,10 +225,8 @@ pub fn shrink(self: *Atom, elf_file: *Elf) void { |
| 224 | } | 225 | } |
| 225 | 226 | ||
| 226 | pub fn grow(self: *Atom, elf_file: *Elf) !void { | 227 | pub fn grow(self: *Atom, elf_file: *Elf) !void { |
| 227 | const alignment = try std.math.powi(u64, 2, self.alignment); | 228 | if (!self.alignment.check(self.value) or self.size > self.capacity(elf_file)) |
| 228 | const align_ok = std.mem.alignBackward(u64, self.value, alignment) == self.value; | 229 | try self.allocate(elf_file); |
| 229 | const need_realloc = !align_ok or self.size > self.capacity(elf_file); | ||
| 230 | if (need_realloc) try self.allocate(elf_file); | ||
| 231 | } | 230 | } |
| 232 | 231 | ||
| 233 | pub fn free(self: *Atom, elf_file: *Elf) void { | 232 | pub fn free(self: *Atom, elf_file: *Elf) void { |
src/link/Elf/Object.zig+4-3| ... | @@ -181,10 +181,10 @@ fn addAtom(self: *Object, shdr: elf.Elf64_Shdr, shndx: u16, name: [:0]const u8, | ... | @@ -181,10 +181,10 @@ fn addAtom(self: *Object, shdr: elf.Elf64_Shdr, shndx: u16, name: [:0]const u8, |
| 181 | const data = try self.shdrContents(shndx); | 181 | const data = try self.shdrContents(shndx); |
| 182 | const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*; | 182 | const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*; |
| 183 | atom.size = chdr.ch_size; | 183 | atom.size = chdr.ch_size; |
| 184 | atom.alignment = math.log2_int(u64, chdr.ch_addralign); | 184 | atom.alignment = Alignment.fromNonzeroByteUnits(chdr.ch_addralign); |
| 185 | } else { | 185 | } else { |
| 186 | atom.size = shdr.sh_size; | 186 | atom.size = shdr.sh_size; |
| 187 | atom.alignment = math.log2_int(u64, shdr.sh_addralign); | 187 | atom.alignment = Alignment.fromNonzeroByteUnits(shdr.sh_addralign); |
| 188 | } | 188 | } |
| 189 | } | 189 | } |
| 190 | 190 | ||
| ... | @@ -571,7 +571,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void { | ... | @@ -571,7 +571,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void { |
| 571 | atom.file = self.index; | 571 | atom.file = self.index; |
| 572 | atom.size = this_sym.st_size; | 572 | atom.size = this_sym.st_size; |
| 573 | const alignment = this_sym.st_value; | 573 | const alignment = this_sym.st_value; |
| 574 | atom.alignment = math.log2_int(u64, alignment); | 574 | atom.alignment = Alignment.fromNonzeroByteUnits(alignment); |
| 575 | 575 | ||
| 576 | var sh_flags: u32 = elf.SHF_ALLOC | elf.SHF_WRITE; | 576 | var sh_flags: u32 = elf.SHF_ALLOC | elf.SHF_WRITE; |
| 577 | if (is_tls) sh_flags |= elf.SHF_TLS; | 577 | if (is_tls) sh_flags |= elf.SHF_TLS; |
| ... | @@ -870,3 +870,4 @@ const Fde = eh_frame.Fde; | ... | @@ -870,3 +870,4 @@ const Fde = eh_frame.Fde; |
| 870 | const File = @import("file.zig").File; | 870 | const File = @import("file.zig").File; |
| 871 | const StringTable = @import("../strtab.zig").StringTable; | 871 | const StringTable = @import("../strtab.zig").StringTable; |
| 872 | const Symbol = @import("Symbol.zig"); | 872 | const Symbol = @import("Symbol.zig"); |
| 873 | const Alignment = Atom.Alignment; |
src/link/MachO.zig+17-18| ... | @@ -1425,7 +1425,7 @@ pub fn allocateSpecialSymbols(self: *MachO) !void { | ... | @@ -1425,7 +1425,7 @@ pub fn allocateSpecialSymbols(self: *MachO) !void { |
| 1425 | 1425 | ||
| 1426 | const CreateAtomOpts = struct { | 1426 | const CreateAtomOpts = struct { |
| 1427 | size: u64 = 0, | 1427 | size: u64 = 0, |
| 1428 | alignment: u32 = 0, | 1428 | alignment: Alignment = .@"1", |
| 1429 | }; | 1429 | }; |
| 1430 | 1430 | ||
| 1431 | pub fn createAtom(self: *MachO, sym_index: u32, opts: CreateAtomOpts) !Atom.Index { | 1431 | pub fn createAtom(self: *MachO, sym_index: u32, opts: CreateAtomOpts) !Atom.Index { |
| ... | @@ -1473,7 +1473,7 @@ pub fn createTentativeDefAtoms(self: *MachO) !void { | ... | @@ -1473,7 +1473,7 @@ pub fn createTentativeDefAtoms(self: *MachO) !void { |
| 1473 | 1473 | ||
| 1474 | const atom_index = try self.createAtom(global.sym_index, .{ | 1474 | const atom_index = try self.createAtom(global.sym_index, .{ |
| 1475 | .size = size, | 1475 | .size = size, |
| 1476 | .alignment = alignment, | 1476 | .alignment = @enumFromInt(alignment), |
| 1477 | }); | 1477 | }); |
| 1478 | const atom = self.getAtomPtr(atom_index); | 1478 | const atom = self.getAtomPtr(atom_index); |
| 1479 | atom.file = global.file; | 1479 | atom.file = global.file; |
| ... | @@ -1493,7 +1493,7 @@ pub fn createDyldPrivateAtom(self: *MachO) !void { | ... | @@ -1493,7 +1493,7 @@ pub fn createDyldPrivateAtom(self: *MachO) !void { |
| 1493 | const sym_index = try self.allocateSymbol(); | 1493 | const sym_index = try self.allocateSymbol(); |
| 1494 | const atom_index = try self.createAtom(sym_index, .{ | 1494 | const atom_index = try self.createAtom(sym_index, .{ |
| 1495 | .size = @sizeOf(u64), | 1495 | .size = @sizeOf(u64), |
| 1496 | .alignment = 3, | 1496 | .alignment = .@"8", |
| 1497 | }); | 1497 | }); |
| 1498 | try self.atom_by_index_table.putNoClobber(self.base.allocator, sym_index, atom_index); | 1498 | try self.atom_by_index_table.putNoClobber(self.base.allocator, sym_index, atom_index); |
| 1499 | 1499 | ||
| ... | @@ -1510,7 +1510,7 @@ pub fn createDyldPrivateAtom(self: *MachO) !void { | ... | @@ -1510,7 +1510,7 @@ pub fn createDyldPrivateAtom(self: *MachO) !void { |
| 1510 | switch (self.mode) { | 1510 | switch (self.mode) { |
| 1511 | .zld => self.addAtomToSection(atom_index), | 1511 | .zld => self.addAtomToSection(atom_index), |
| 1512 | .incremental => { | 1512 | .incremental => { |
| 1513 | sym.n_value = try self.allocateAtom(atom_index, atom.size, @alignOf(u64)); | 1513 | sym.n_value = try self.allocateAtom(atom_index, atom.size, .@"8"); |
| 1514 | log.debug("allocated dyld_private atom at 0x{x}", .{sym.n_value}); | 1514 | log.debug("allocated dyld_private atom at 0x{x}", .{sym.n_value}); |
| 1515 | var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64); | 1515 | var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64); |
| 1516 | try self.writeAtom(atom_index, &buffer); | 1516 | try self.writeAtom(atom_index, &buffer); |
| ... | @@ -1521,7 +1521,7 @@ pub fn createDyldPrivateAtom(self: *MachO) !void { | ... | @@ -1521,7 +1521,7 @@ pub fn createDyldPrivateAtom(self: *MachO) !void { |
| 1521 | fn createThreadLocalDescriptorAtom(self: *MachO, sym_name: []const u8, target: SymbolWithLoc) !Atom.Index { | 1521 | fn createThreadLocalDescriptorAtom(self: *MachO, sym_name: []const u8, target: SymbolWithLoc) !Atom.Index { |
| 1522 | const gpa = self.base.allocator; | 1522 | const gpa = self.base.allocator; |
| 1523 | const size = 3 * @sizeOf(u64); | 1523 | const size = 3 * @sizeOf(u64); |
| 1524 | const required_alignment: u32 = 1; | 1524 | const required_alignment: Alignment = .@"1"; |
| 1525 | const sym_index = try self.allocateSymbol(); | 1525 | const sym_index = try self.allocateSymbol(); |
| 1526 | const atom_index = try self.createAtom(sym_index, .{}); | 1526 | const atom_index = try self.createAtom(sym_index, .{}); |
| 1527 | try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index); | 1527 | try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index); |
| ... | @@ -2030,10 +2030,10 @@ fn shrinkAtom(self: *MachO, atom_index: Atom.Index, new_block_size: u64) void { | ... | @@ -2030,10 +2030,10 @@ fn shrinkAtom(self: *MachO, atom_index: Atom.Index, new_block_size: u64) void { |
| 2030 | // capacity, insert a free list node for it. | 2030 | // capacity, insert a free list node for it. |
| 2031 | } | 2031 | } |
| 2032 | 2032 | ||
| 2033 | fn growAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignment: u64) !u64 { | 2033 | fn growAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignment: Alignment) !u64 { |
| 2034 | const atom = self.getAtom(atom_index); | 2034 | const atom = self.getAtom(atom_index); |
| 2035 | const sym = atom.getSymbol(self); | 2035 | const sym = atom.getSymbol(self); |
| 2036 | const align_ok = mem.alignBackward(u64, sym.n_value, alignment) == sym.n_value; | 2036 | const align_ok = alignment.check(sym.n_value); |
| 2037 | const need_realloc = !align_ok or new_atom_size > atom.capacity(self); | 2037 | const need_realloc = !align_ok or new_atom_size > atom.capacity(self); |
| 2038 | if (!need_realloc) return sym.n_value; | 2038 | if (!need_realloc) return sym.n_value; |
| 2039 | return self.allocateAtom(atom_index, new_atom_size, alignment); | 2039 | return self.allocateAtom(atom_index, new_atom_size, alignment); |
| ... | @@ -2350,7 +2350,7 @@ fn updateLazySymbolAtom( | ... | @@ -2350,7 +2350,7 @@ fn updateLazySymbolAtom( |
| 2350 | const gpa = self.base.allocator; | 2350 | const gpa = self.base.allocator; |
| 2351 | const mod = self.base.options.module.?; | 2351 | const mod = self.base.options.module.?; |
| 2352 | 2352 | ||
| 2353 | var required_alignment: u32 = undefined; | 2353 | var required_alignment: Alignment = .none; |
| 2354 | var code_buffer = std.ArrayList(u8).init(gpa); | 2354 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 2355 | defer code_buffer.deinit(); | 2355 | defer code_buffer.deinit(); |
| 2356 | 2356 | ||
| ... | @@ -2617,7 +2617,7 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64 | ... | @@ -2617,7 +2617,7 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64 |
| 2617 | sym.n_desc = 0; | 2617 | sym.n_desc = 0; |
| 2618 | 2618 | ||
| 2619 | const capacity = atom.capacity(self); | 2619 | const capacity = atom.capacity(self); |
| 2620 | const need_realloc = code_len > capacity or !mem.isAlignedGeneric(u64, sym.n_value, required_alignment); | 2620 | const need_realloc = code_len > capacity or !required_alignment.check(sym.n_value); |
| 2621 | 2621 | ||
| 2622 | if (need_realloc) { | 2622 | if (need_realloc) { |
| 2623 | const vaddr = try self.growAtom(atom_index, code_len, required_alignment); | 2623 | const vaddr = try self.growAtom(atom_index, code_len, required_alignment); |
| ... | @@ -3204,7 +3204,7 @@ pub fn addAtomToSection(self: *MachO, atom_index: Atom.Index) void { | ... | @@ -3204,7 +3204,7 @@ pub fn addAtomToSection(self: *MachO, atom_index: Atom.Index) void { |
| 3204 | self.sections.set(sym.n_sect - 1, section); | 3204 | self.sections.set(sym.n_sect - 1, section); |
| 3205 | } | 3205 | } |
| 3206 | 3206 | ||
| 3207 | fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignment: u64) !u64 { | 3207 | fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignment: Alignment) !u64 { |
| 3208 | const tracy = trace(@src()); | 3208 | const tracy = trace(@src()); |
| 3209 | defer tracy.end(); | 3209 | defer tracy.end(); |
| 3210 | 3210 | ||
| ... | @@ -3247,7 +3247,7 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm | ... | @@ -3247,7 +3247,7 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm |
| 3247 | const ideal_capacity_end_vaddr = math.add(u64, sym.n_value, ideal_capacity) catch ideal_capacity; | 3247 | const ideal_capacity_end_vaddr = math.add(u64, sym.n_value, ideal_capacity) catch ideal_capacity; |
| 3248 | const capacity_end_vaddr = sym.n_value + capacity; | 3248 | const capacity_end_vaddr = sym.n_value + capacity; |
| 3249 | const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity; | 3249 | const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity; |
| 3250 | const new_start_vaddr = mem.alignBackward(u64, new_start_vaddr_unaligned, alignment); | 3250 | const new_start_vaddr = alignment.backward(new_start_vaddr_unaligned); |
| 3251 | if (new_start_vaddr < ideal_capacity_end_vaddr) { | 3251 | if (new_start_vaddr < ideal_capacity_end_vaddr) { |
| 3252 | // Additional bookkeeping here to notice if this free list node | 3252 | // Additional bookkeeping here to notice if this free list node |
| 3253 | // should be deleted because the atom that it points to has grown to take up | 3253 | // should be deleted because the atom that it points to has grown to take up |
| ... | @@ -3276,11 +3276,11 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm | ... | @@ -3276,11 +3276,11 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm |
| 3276 | const last_symbol = last.getSymbol(self); | 3276 | const last_symbol = last.getSymbol(self); |
| 3277 | const ideal_capacity = if (requires_padding) padToIdeal(last.size) else last.size; | 3277 | const ideal_capacity = if (requires_padding) padToIdeal(last.size) else last.size; |
| 3278 | const ideal_capacity_end_vaddr = last_symbol.n_value + ideal_capacity; | 3278 | const ideal_capacity_end_vaddr = last_symbol.n_value + ideal_capacity; |
| 3279 | const new_start_vaddr = mem.alignForward(u64, ideal_capacity_end_vaddr, alignment); | 3279 | const new_start_vaddr = alignment.forward(ideal_capacity_end_vaddr); |
| 3280 | atom_placement = last_index; | 3280 | atom_placement = last_index; |
| 3281 | break :blk new_start_vaddr; | 3281 | break :blk new_start_vaddr; |
| 3282 | } else { | 3282 | } else { |
| 3283 | break :blk mem.alignForward(u64, segment.vmaddr, alignment); | 3283 | break :blk alignment.forward(segment.vmaddr); |
| 3284 | } | 3284 | } |
| 3285 | }; | 3285 | }; |
| 3286 | 3286 | ||
| ... | @@ -3295,10 +3295,8 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm | ... | @@ -3295,10 +3295,8 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm |
| 3295 | self.segment_table_dirty = true; | 3295 | self.segment_table_dirty = true; |
| 3296 | } | 3296 | } |
| 3297 | 3297 | ||
| 3298 | const align_pow = @as(u32, @intCast(math.log2(alignment))); | 3298 | assert(alignment != .none); |
| 3299 | if (header.@"align" < align_pow) { | 3299 | header.@"align" = @min(header.@"align", @intFromEnum(alignment)); |
| 3300 | header.@"align" = align_pow; | ||
| 3301 | } | ||
| 3302 | self.getAtomPtr(atom_index).size = new_atom_size; | 3300 | self.getAtomPtr(atom_index).size = new_atom_size; |
| 3303 | 3301 | ||
| 3304 | if (atom.prev_index) |prev_index| { | 3302 | if (atom.prev_index) |prev_index| { |
| ... | @@ -3338,7 +3336,7 @@ pub fn getGlobalSymbol(self: *MachO, name: []const u8, lib_name: ?[]const u8) !u | ... | @@ -3338,7 +3336,7 @@ pub fn getGlobalSymbol(self: *MachO, name: []const u8, lib_name: ?[]const u8) !u |
| 3338 | 3336 | ||
| 3339 | pub fn writeSegmentHeaders(self: *MachO, writer: anytype) !void { | 3337 | pub fn writeSegmentHeaders(self: *MachO, writer: anytype) !void { |
| 3340 | for (self.segments.items, 0..) |seg, i| { | 3338 | for (self.segments.items, 0..) |seg, i| { |
| 3341 | const indexes = self.getSectionIndexes(@as(u8, @intCast(i))); | 3339 | const indexes = self.getSectionIndexes(@intCast(i)); |
| 3342 | var out_seg = seg; | 3340 | var out_seg = seg; |
| 3343 | out_seg.cmdsize = @sizeOf(macho.segment_command_64); | 3341 | out_seg.cmdsize = @sizeOf(macho.segment_command_64); |
| 3344 | out_seg.nsects = 0; | 3342 | out_seg.nsects = 0; |
| ... | @@ -5526,6 +5524,7 @@ const Trie = @import("MachO/Trie.zig"); | ... | @@ -5526,6 +5524,7 @@ const Trie = @import("MachO/Trie.zig"); |
| 5526 | const Type = @import("../type.zig").Type; | 5524 | const Type = @import("../type.zig").Type; |
| 5527 | const TypedValue = @import("../TypedValue.zig"); | 5525 | const TypedValue = @import("../TypedValue.zig"); |
| 5528 | const Value = @import("../value.zig").Value; | 5526 | const Value = @import("../value.zig").Value; |
| 5527 | const Alignment = Atom.Alignment; | ||
| 5529 | 5528 | ||
| 5530 | pub const DebugSymbols = @import("MachO/DebugSymbols.zig"); | 5529 | pub const DebugSymbols = @import("MachO/DebugSymbols.zig"); |
| 5531 | pub const Bind = @import("MachO/dyld_info/bind.zig").Bind(*const MachO, SymbolWithLoc); | 5530 | pub const Bind = @import("MachO/dyld_info/bind.zig").Bind(*const MachO, SymbolWithLoc); |
src/link/MachO/Atom.zig+3-1| ... | @@ -28,13 +28,15 @@ size: u64 = 0, | ... | @@ -28,13 +28,15 @@ size: u64 = 0, |
| 28 | 28 | ||
| 29 | /// Alignment of this atom as a power of 2. | 29 | /// Alignment of this atom as a power of 2. |
| 30 | /// For instance, aligmment of 0 should be read as 2^0 = 1 byte aligned. | 30 | /// For instance, aligmment of 0 should be read as 2^0 = 1 byte aligned. |
| 31 | alignment: u32 = 0, | 31 | alignment: Alignment = .@"1", |
| 32 | 32 | ||
| 33 | /// Points to the previous and next neighbours | 33 | /// Points to the previous and next neighbours |
| 34 | /// TODO use the same trick as with symbols: reserve index 0 as null atom | 34 | /// TODO use the same trick as with symbols: reserve index 0 as null atom |
| 35 | next_index: ?Index = null, | 35 | next_index: ?Index = null, |
| 36 | prev_index: ?Index = null, | 36 | prev_index: ?Index = null, |
| 37 | 37 | ||
| 38 | pub const Alignment = @import("../../InternPool.zig").Alignment; | ||
| 39 | |||
| 38 | pub const Index = u32; | 40 | pub const Index = u32; |
| 39 | 41 | ||
| 40 | pub const Binding = struct { | 42 | pub const Binding = struct { |
src/link/MachO/Object.zig+12-8| ... | @@ -382,7 +382,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) ! | ... | @@ -382,7 +382,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) ! |
| 382 | const out_sect_id = (try Atom.getOutputSection(macho_file, sect)) orelse continue; | 382 | const out_sect_id = (try Atom.getOutputSection(macho_file, sect)) orelse continue; |
| 383 | if (sect.size == 0) continue; | 383 | if (sect.size == 0) continue; |
| 384 | 384 | ||
| 385 | const sect_id = @as(u8, @intCast(id)); | 385 | const sect_id: u8 = @intCast(id); |
| 386 | const sym_index = self.getSectionAliasSymbolIndex(sect_id); | 386 | const sym_index = self.getSectionAliasSymbolIndex(sect_id); |
| 387 | const atom_index = try self.createAtomFromSubsection( | 387 | const atom_index = try self.createAtomFromSubsection( |
| 388 | macho_file, | 388 | macho_file, |
| ... | @@ -391,7 +391,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) ! | ... | @@ -391,7 +391,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) ! |
| 391 | sym_index, | 391 | sym_index, |
| 392 | 1, | 392 | 1, |
| 393 | sect.size, | 393 | sect.size, |
| 394 | sect.@"align", | 394 | Alignment.fromLog2Units(sect.@"align"), |
| 395 | out_sect_id, | 395 | out_sect_id, |
| 396 | ); | 396 | ); |
| 397 | macho_file.addAtomToSection(atom_index); | 397 | macho_file.addAtomToSection(atom_index); |
| ... | @@ -470,7 +470,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) ! | ... | @@ -470,7 +470,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) ! |
| 470 | sym_index, | 470 | sym_index, |
| 471 | 1, | 471 | 1, |
| 472 | atom_size, | 472 | atom_size, |
| 473 | sect.@"align", | 473 | Alignment.fromLog2Units(sect.@"align"), |
| 474 | out_sect_id, | 474 | out_sect_id, |
| 475 | ); | 475 | ); |
| 476 | if (!sect.isZerofill()) { | 476 | if (!sect.isZerofill()) { |
| ... | @@ -494,10 +494,10 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) ! | ... | @@ -494,10 +494,10 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) ! |
| 494 | else | 494 | else |
| 495 | sect.addr + sect.size - addr; | 495 | sect.addr + sect.size - addr; |
| 496 | 496 | ||
| 497 | const atom_align = if (addr > 0) | 497 | const atom_align = Alignment.fromLog2Units(if (addr > 0) |
| 498 | @min(@ctz(addr), sect.@"align") | 498 | @min(@ctz(addr), sect.@"align") |
| 499 | else | 499 | else |
| 500 | sect.@"align"; | 500 | sect.@"align"); |
| 501 | 501 | ||
| 502 | const atom_index = try self.createAtomFromSubsection( | 502 | const atom_index = try self.createAtomFromSubsection( |
| 503 | macho_file, | 503 | macho_file, |
| ... | @@ -532,7 +532,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) ! | ... | @@ -532,7 +532,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) ! |
| 532 | sect_start_index, | 532 | sect_start_index, |
| 533 | sect_loc.len, | 533 | sect_loc.len, |
| 534 | sect.size, | 534 | sect.size, |
| 535 | sect.@"align", | 535 | Alignment.fromLog2Units(sect.@"align"), |
| 536 | out_sect_id, | 536 | out_sect_id, |
| 537 | ); | 537 | ); |
| 538 | if (!sect.isZerofill()) { | 538 | if (!sect.isZerofill()) { |
| ... | @@ -551,11 +551,14 @@ fn createAtomFromSubsection( | ... | @@ -551,11 +551,14 @@ fn createAtomFromSubsection( |
| 551 | inner_sym_index: u32, | 551 | inner_sym_index: u32, |
| 552 | inner_nsyms_trailing: u32, | 552 | inner_nsyms_trailing: u32, |
| 553 | size: u64, | 553 | size: u64, |
| 554 | alignment: u32, | 554 | alignment: Alignment, |
| 555 | out_sect_id: u8, | 555 | out_sect_id: u8, |
| 556 | ) !Atom.Index { | 556 | ) !Atom.Index { |
| 557 | const gpa = macho_file.base.allocator; | 557 | const gpa = macho_file.base.allocator; |
| 558 | const atom_index = try macho_file.createAtom(sym_index, .{ .size = size, .alignment = alignment }); | 558 | const atom_index = try macho_file.createAtom(sym_index, .{ |
| 559 | .size = size, | ||
| 560 | .alignment = alignment, | ||
| 561 | }); | ||
| 559 | const atom = macho_file.getAtomPtr(atom_index); | 562 | const atom = macho_file.getAtomPtr(atom_index); |
| 560 | atom.inner_sym_index = inner_sym_index; | 563 | atom.inner_sym_index = inner_sym_index; |
| 561 | atom.inner_nsyms_trailing = inner_nsyms_trailing; | 564 | atom.inner_nsyms_trailing = inner_nsyms_trailing; |
| ... | @@ -1115,3 +1118,4 @@ const MachO = @import("../MachO.zig"); | ... | @@ -1115,3 +1118,4 @@ const MachO = @import("../MachO.zig"); |
| 1115 | const Platform = @import("load_commands.zig").Platform; | 1118 | const Platform = @import("load_commands.zig").Platform; |
| 1116 | const SymbolWithLoc = MachO.SymbolWithLoc; | 1119 | const SymbolWithLoc = MachO.SymbolWithLoc; |
| 1117 | const UnwindInfo = @import("UnwindInfo.zig"); | 1120 | const UnwindInfo = @import("UnwindInfo.zig"); |
| 1121 | const Alignment = Atom.Alignment; |
src/link/MachO/thunks.zig+7-4| ... | @@ -104,7 +104,7 @@ pub fn createThunks(macho_file: *MachO, sect_id: u8) !void { | ... | @@ -104,7 +104,7 @@ pub fn createThunks(macho_file: *MachO, sect_id: u8) !void { |
| 104 | 104 | ||
| 105 | while (true) { | 105 | while (true) { |
| 106 | const atom = macho_file.getAtom(group_end); | 106 | const atom = macho_file.getAtom(group_end); |
| 107 | offset = mem.alignForward(u64, offset, try math.powi(u32, 2, atom.alignment)); | 107 | offset = atom.alignment.forward(offset); |
| 108 | 108 | ||
| 109 | const sym = macho_file.getSymbolPtr(atom.getSymbolWithLoc()); | 109 | const sym = macho_file.getSymbolPtr(atom.getSymbolWithLoc()); |
| 110 | sym.n_value = offset; | 110 | sym.n_value = offset; |
| ... | @@ -112,7 +112,7 @@ pub fn createThunks(macho_file: *MachO, sect_id: u8) !void { | ... | @@ -112,7 +112,7 @@ pub fn createThunks(macho_file: *MachO, sect_id: u8) !void { |
| 112 | 112 | ||
| 113 | macho_file.logAtom(group_end, log); | 113 | macho_file.logAtom(group_end, log); |
| 114 | 114 | ||
| 115 | header.@"align" = @max(header.@"align", atom.alignment); | 115 | header.@"align" = @max(header.@"align", atom.alignment.toLog2Units()); |
| 116 | 116 | ||
| 117 | allocated.putAssumeCapacityNoClobber(group_end, {}); | 117 | allocated.putAssumeCapacityNoClobber(group_end, {}); |
| 118 | 118 | ||
| ... | @@ -196,7 +196,7 @@ fn allocateThunk( | ... | @@ -196,7 +196,7 @@ fn allocateThunk( |
| 196 | 196 | ||
| 197 | macho_file.logAtom(atom_index, log); | 197 | macho_file.logAtom(atom_index, log); |
| 198 | 198 | ||
| 199 | header.@"align" = @max(header.@"align", atom.alignment); | 199 | header.@"align" = @max(header.@"align", atom.alignment.toLog2Units()); |
| 200 | 200 | ||
| 201 | if (end_atom_index == atom_index) break; | 201 | if (end_atom_index == atom_index) break; |
| 202 | 202 | ||
| ... | @@ -326,7 +326,10 @@ fn isReachable( | ... | @@ -326,7 +326,10 @@ fn isReachable( |
| 326 | 326 | ||
| 327 | fn createThunkAtom(macho_file: *MachO) !Atom.Index { | 327 | fn createThunkAtom(macho_file: *MachO) !Atom.Index { |
| 328 | const sym_index = try macho_file.allocateSymbol(); | 328 | const sym_index = try macho_file.allocateSymbol(); |
| 329 | const atom_index = try macho_file.createAtom(sym_index, .{ .size = @sizeOf(u32) * 3, .alignment = 2 }); | 329 | const atom_index = try macho_file.createAtom(sym_index, .{ |
| 330 | .size = @sizeOf(u32) * 3, | ||
| 331 | .alignment = .@"4", | ||
| 332 | }); | ||
| 330 | const sym = macho_file.getSymbolPtr(.{ .sym_index = sym_index }); | 333 | const sym = macho_file.getSymbolPtr(.{ .sym_index = sym_index }); |
| 331 | sym.n_type = macho.N_SECT; | 334 | sym.n_type = macho.N_SECT; |
| 332 | sym.n_sect = macho_file.text_section_index.? + 1; | 335 | sym.n_sect = macho_file.text_section_index.? + 1; |
src/link/MachO/zld.zig+3-6| ... | @@ -985,19 +985,16 @@ fn calcSectionSizes(macho_file: *MachO) !void { | ... | @@ -985,19 +985,16 @@ fn calcSectionSizes(macho_file: *MachO) !void { |
| 985 | 985 | ||
| 986 | while (true) { | 986 | while (true) { |
| 987 | const atom = macho_file.getAtom(atom_index); | 987 | const atom = macho_file.getAtom(atom_index); |
| 988 | const atom_alignment = try math.powi(u32, 2, atom.alignment); | 988 | const atom_offset = atom.alignment.forward(header.size); |
| 989 | const atom_offset = mem.alignForward(u64, header.size, atom_alignment); | ||
| 990 | const padding = atom_offset - header.size; | 989 | const padding = atom_offset - header.size; |
| 991 | 990 | ||
| 992 | const sym = macho_file.getSymbolPtr(atom.getSymbolWithLoc()); | 991 | const sym = macho_file.getSymbolPtr(atom.getSymbolWithLoc()); |
| 993 | sym.n_value = atom_offset; | 992 | sym.n_value = atom_offset; |
| 994 | 993 | ||
| 995 | header.size += padding + atom.size; | 994 | header.size += padding + atom.size; |
| 996 | header.@"align" = @max(header.@"align", atom.alignment); | 995 | header.@"align" = @max(header.@"align", atom.alignment.toLog2Units()); |
| 997 | 996 | ||
| 998 | if (atom.next_index) |next_index| { | 997 | atom_index = atom.next_index orelse break; |
| 999 | atom_index = next_index; | ||
| 1000 | } else break; | ||
| 1001 | } | 998 | } |
| 1002 | } | 999 | } |
| 1003 | 1000 |
src/link/Plan9.zig+1-1| ... | @@ -1106,7 +1106,7 @@ fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Ind | ... | @@ -1106,7 +1106,7 @@ fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Ind |
| 1106 | const gpa = self.base.allocator; | 1106 | const gpa = self.base.allocator; |
| 1107 | const mod = self.base.options.module.?; | 1107 | const mod = self.base.options.module.?; |
| 1108 | 1108 | ||
| 1109 | var required_alignment: u32 = undefined; | 1109 | var required_alignment: InternPool.Alignment = .none; |
| 1110 | var code_buffer = std.ArrayList(u8).init(gpa); | 1110 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 1111 | defer code_buffer.deinit(); | 1111 | defer code_buffer.deinit(); |
| 1112 | 1112 |
src/link/Wasm.zig+23-21| ... | @@ -187,8 +187,10 @@ debug_pubtypes_atom: ?Atom.Index = null, | ... | @@ -187,8 +187,10 @@ debug_pubtypes_atom: ?Atom.Index = null, |
| 187 | /// rather than by the linker. | 187 | /// rather than by the linker. |
| 188 | synthetic_functions: std.ArrayListUnmanaged(Atom.Index) = .{}, | 188 | synthetic_functions: std.ArrayListUnmanaged(Atom.Index) = .{}, |
| 189 | 189 | ||
| 190 | pub const Alignment = types.Alignment; | ||
| 191 | |||
| 190 | pub const Segment = struct { | 192 | pub const Segment = struct { |
| 191 | alignment: u32, | 193 | alignment: Alignment, |
| 192 | size: u32, | 194 | size: u32, |
| 193 | offset: u32, | 195 | offset: u32, |
| 194 | flags: u32, | 196 | flags: u32, |
| ... | @@ -1490,7 +1492,7 @@ fn finishUpdateDecl(wasm: *Wasm, decl_index: Module.Decl.Index, code: []const u8 | ... | @@ -1490,7 +1492,7 @@ fn finishUpdateDecl(wasm: *Wasm, decl_index: Module.Decl.Index, code: []const u8 |
| 1490 | try atom.code.appendSlice(wasm.base.allocator, code); | 1492 | try atom.code.appendSlice(wasm.base.allocator, code); |
| 1491 | try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {}); | 1493 | try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {}); |
| 1492 | 1494 | ||
| 1493 | atom.size = @as(u32, @intCast(code.len)); | 1495 | atom.size = @intCast(code.len); |
| 1494 | if (code.len == 0) return; | 1496 | if (code.len == 0) return; |
| 1495 | atom.alignment = decl.getAlignment(mod); | 1497 | atom.alignment = decl.getAlignment(mod); |
| 1496 | } | 1498 | } |
| ... | @@ -2050,7 +2052,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { | ... | @@ -2050,7 +2052,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { |
| 2050 | }; | 2052 | }; |
| 2051 | 2053 | ||
| 2052 | const segment: *Segment = &wasm.segments.items[final_index]; | 2054 | const segment: *Segment = &wasm.segments.items[final_index]; |
| 2053 | segment.alignment = @max(segment.alignment, atom.alignment); | 2055 | segment.alignment = segment.alignment.max(atom.alignment); |
| 2054 | 2056 | ||
| 2055 | try wasm.appendAtomAtIndex(final_index, atom_index); | 2057 | try wasm.appendAtomAtIndex(final_index, atom_index); |
| 2056 | } | 2058 | } |
| ... | @@ -2121,7 +2123,7 @@ fn allocateAtoms(wasm: *Wasm) !void { | ... | @@ -2121,7 +2123,7 @@ fn allocateAtoms(wasm: *Wasm) !void { |
| 2121 | } | 2123 | } |
| 2122 | } | 2124 | } |
| 2123 | } | 2125 | } |
| 2124 | offset = std.mem.alignForward(u32, offset, atom.alignment); | 2126 | offset = @intCast(atom.alignment.forward(offset)); |
| 2125 | atom.offset = offset; | 2127 | atom.offset = offset; |
| 2126 | log.debug("Atom '{s}' allocated from 0x{x:0>8} to 0x{x:0>8} size={d}", .{ | 2128 | log.debug("Atom '{s}' allocated from 0x{x:0>8} to 0x{x:0>8} size={d}", .{ |
| 2127 | symbol_loc.getName(wasm), | 2129 | symbol_loc.getName(wasm), |
| ... | @@ -2132,7 +2134,7 @@ fn allocateAtoms(wasm: *Wasm) !void { | ... | @@ -2132,7 +2134,7 @@ fn allocateAtoms(wasm: *Wasm) !void { |
| 2132 | offset += atom.size; | 2134 | offset += atom.size; |
| 2133 | atom_index = atom.prev orelse break; | 2135 | atom_index = atom.prev orelse break; |
| 2134 | } | 2136 | } |
| 2135 | segment.size = std.mem.alignForward(u32, offset, segment.alignment); | 2137 | segment.size = @intCast(segment.alignment.forward(offset)); |
| 2136 | } | 2138 | } |
| 2137 | } | 2139 | } |
| 2138 | 2140 | ||
| ... | @@ -2351,7 +2353,7 @@ fn createSyntheticFunction( | ... | @@ -2351,7 +2353,7 @@ fn createSyntheticFunction( |
| 2351 | .offset = 0, | 2353 | .offset = 0, |
| 2352 | .sym_index = loc.index, | 2354 | .sym_index = loc.index, |
| 2353 | .file = null, | 2355 | .file = null, |
| 2354 | .alignment = 1, | 2356 | .alignment = .@"1", |
| 2355 | .next = null, | 2357 | .next = null, |
| 2356 | .prev = null, | 2358 | .prev = null, |
| 2357 | .code = function_body.moveToUnmanaged(), | 2359 | .code = function_body.moveToUnmanaged(), |
| ... | @@ -2382,11 +2384,11 @@ pub fn createFunction( | ... | @@ -2382,11 +2384,11 @@ pub fn createFunction( |
| 2382 | const atom_index = @as(Atom.Index, @intCast(wasm.managed_atoms.items.len)); | 2384 | const atom_index = @as(Atom.Index, @intCast(wasm.managed_atoms.items.len)); |
| 2383 | const atom = try wasm.managed_atoms.addOne(wasm.base.allocator); | 2385 | const atom = try wasm.managed_atoms.addOne(wasm.base.allocator); |
| 2384 | atom.* = .{ | 2386 | atom.* = .{ |
| 2385 | .size = @as(u32, @intCast(function_body.items.len)), | 2387 | .size = @intCast(function_body.items.len), |
| 2386 | .offset = 0, | 2388 | .offset = 0, |
| 2387 | .sym_index = loc.index, | 2389 | .sym_index = loc.index, |
| 2388 | .file = null, | 2390 | .file = null, |
| 2389 | .alignment = 1, | 2391 | .alignment = .@"1", |
| 2390 | .next = null, | 2392 | .next = null, |
| 2391 | .prev = null, | 2393 | .prev = null, |
| 2392 | .code = function_body.moveToUnmanaged(), | 2394 | .code = function_body.moveToUnmanaged(), |
| ... | @@ -2734,8 +2736,8 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2734,8 +2736,8 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2734 | const page_size = std.wasm.page_size; // 64kb | 2736 | const page_size = std.wasm.page_size; // 64kb |
| 2735 | // Use the user-provided stack size or else we use 1MB by default | 2737 | // Use the user-provided stack size or else we use 1MB by default |
| 2736 | const stack_size = wasm.base.options.stack_size_override orelse page_size * 16; | 2738 | const stack_size = wasm.base.options.stack_size_override orelse page_size * 16; |
| 2737 | const stack_alignment = 16; // wasm's stack alignment as specified by tool-convention | 2739 | const stack_alignment: Alignment = .@"16"; // wasm's stack alignment as specified by tool-convention |
| 2738 | const heap_alignment = 16; // wasm's heap alignment as specified by tool-convention | 2740 | const heap_alignment: Alignment = .@"16"; // wasm's heap alignment as specified by tool-convention |
| 2739 | 2741 | ||
| 2740 | // Always place the stack at the start by default | 2742 | // Always place the stack at the start by default |
| 2741 | // unless the user specified the global-base flag | 2743 | // unless the user specified the global-base flag |
| ... | @@ -2748,7 +2750,7 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2748,7 +2750,7 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2748 | const is_obj = wasm.base.options.output_mode == .Obj; | 2750 | const is_obj = wasm.base.options.output_mode == .Obj; |
| 2749 | 2751 | ||
| 2750 | if (place_stack_first and !is_obj) { | 2752 | if (place_stack_first and !is_obj) { |
| 2751 | memory_ptr = std.mem.alignForward(u64, memory_ptr, stack_alignment); | 2753 | memory_ptr = stack_alignment.forward(memory_ptr); |
| 2752 | memory_ptr += stack_size; | 2754 | memory_ptr += stack_size; |
| 2753 | // We always put the stack pointer global at index 0 | 2755 | // We always put the stack pointer global at index 0 |
| 2754 | wasm.wasm_globals.items[0].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr)))); | 2756 | wasm.wasm_globals.items[0].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr)))); |
| ... | @@ -2758,7 +2760,7 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2758,7 +2760,7 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2758 | var data_seg_it = wasm.data_segments.iterator(); | 2760 | var data_seg_it = wasm.data_segments.iterator(); |
| 2759 | while (data_seg_it.next()) |entry| { | 2761 | while (data_seg_it.next()) |entry| { |
| 2760 | const segment = &wasm.segments.items[entry.value_ptr.*]; | 2762 | const segment = &wasm.segments.items[entry.value_ptr.*]; |
| 2761 | memory_ptr = std.mem.alignForward(u64, memory_ptr, segment.alignment); | 2763 | memory_ptr = segment.alignment.forward(memory_ptr); |
| 2762 | 2764 | ||
| 2763 | // set TLS-related symbols | 2765 | // set TLS-related symbols |
| 2764 | if (mem.eql(u8, entry.key_ptr.*, ".tdata")) { | 2766 | if (mem.eql(u8, entry.key_ptr.*, ".tdata")) { |
| ... | @@ -2768,7 +2770,7 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2768,7 +2770,7 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2768 | } | 2770 | } |
| 2769 | if (wasm.findGlobalSymbol("__tls_align")) |loc| { | 2771 | if (wasm.findGlobalSymbol("__tls_align")) |loc| { |
| 2770 | const sym = loc.getSymbol(wasm); | 2772 | const sym = loc.getSymbol(wasm); |
| 2771 | wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.alignment); | 2773 | wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.alignment.toByteUnitsOptional().?); |
| 2772 | } | 2774 | } |
| 2773 | if (wasm.findGlobalSymbol("__tls_base")) |loc| { | 2775 | if (wasm.findGlobalSymbol("__tls_base")) |loc| { |
| 2774 | const sym = loc.getSymbol(wasm); | 2776 | const sym = loc.getSymbol(wasm); |
| ... | @@ -2795,7 +2797,7 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2795,7 +2797,7 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2795 | } | 2797 | } |
| 2796 | 2798 | ||
| 2797 | if (!place_stack_first and !is_obj) { | 2799 | if (!place_stack_first and !is_obj) { |
| 2798 | memory_ptr = std.mem.alignForward(u64, memory_ptr, stack_alignment); | 2800 | memory_ptr = stack_alignment.forward(memory_ptr); |
| 2799 | memory_ptr += stack_size; | 2801 | memory_ptr += stack_size; |
| 2800 | wasm.wasm_globals.items[0].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr)))); | 2802 | wasm.wasm_globals.items[0].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr)))); |
| 2801 | } | 2803 | } |
| ... | @@ -2804,7 +2806,7 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2804,7 +2806,7 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2804 | // We must set its virtual address so it can be used in relocations. | 2806 | // We must set its virtual address so it can be used in relocations. |
| 2805 | if (wasm.findGlobalSymbol("__heap_base")) |loc| { | 2807 | if (wasm.findGlobalSymbol("__heap_base")) |loc| { |
| 2806 | const symbol = loc.getSymbol(wasm); | 2808 | const symbol = loc.getSymbol(wasm); |
| 2807 | symbol.virtual_address = @as(u32, @intCast(mem.alignForward(u64, memory_ptr, heap_alignment))); | 2809 | symbol.virtual_address = @intCast(heap_alignment.forward(memory_ptr)); |
| 2808 | } | 2810 | } |
| 2809 | 2811 | ||
| 2810 | // Setup the max amount of pages | 2812 | // Setup the max amount of pages |
| ... | @@ -2879,7 +2881,7 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32 | ... | @@ -2879,7 +2881,7 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32 |
| 2879 | flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE); | 2881 | flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE); |
| 2880 | } | 2882 | } |
| 2881 | try wasm.segments.append(wasm.base.allocator, .{ | 2883 | try wasm.segments.append(wasm.base.allocator, .{ |
| 2882 | .alignment = 1, | 2884 | .alignment = .@"1", |
| 2883 | .size = 0, | 2885 | .size = 0, |
| 2884 | .offset = 0, | 2886 | .offset = 0, |
| 2885 | .flags = flags, | 2887 | .flags = flags, |
| ... | @@ -2954,7 +2956,7 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32 | ... | @@ -2954,7 +2956,7 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32 |
| 2954 | /// Appends a new segment with default field values | 2956 | /// Appends a new segment with default field values |
| 2955 | fn appendDummySegment(wasm: *Wasm) !void { | 2957 | fn appendDummySegment(wasm: *Wasm) !void { |
| 2956 | try wasm.segments.append(wasm.base.allocator, .{ | 2958 | try wasm.segments.append(wasm.base.allocator, .{ |
| 2957 | .alignment = 1, | 2959 | .alignment = .@"1", |
| 2958 | .size = 0, | 2960 | .size = 0, |
| 2959 | .offset = 0, | 2961 | .offset = 0, |
| 2960 | .flags = 0, | 2962 | .flags = 0, |
| ... | @@ -3011,7 +3013,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void { | ... | @@ -3011,7 +3013,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void { |
| 3011 | // the pointers into the list using addends which are appended to the relocation. | 3013 | // the pointers into the list using addends which are appended to the relocation. |
| 3012 | const names_atom_index = try wasm.createAtom(); | 3014 | const names_atom_index = try wasm.createAtom(); |
| 3013 | const names_atom = wasm.getAtomPtr(names_atom_index); | 3015 | const names_atom = wasm.getAtomPtr(names_atom_index); |
| 3014 | names_atom.alignment = 1; | 3016 | names_atom.alignment = .@"1"; |
| 3015 | const sym_name = try wasm.string_table.put(wasm.base.allocator, "__zig_err_names"); | 3017 | const sym_name = try wasm.string_table.put(wasm.base.allocator, "__zig_err_names"); |
| 3016 | const names_symbol = &wasm.symbols.items[names_atom.sym_index]; | 3018 | const names_symbol = &wasm.symbols.items[names_atom.sym_index]; |
| 3017 | names_symbol.* = .{ | 3019 | names_symbol.* = .{ |
| ... | @@ -3085,7 +3087,7 @@ pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) ! | ... | @@ -3085,7 +3087,7 @@ pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) ! |
| 3085 | .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL), | 3087 | .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL), |
| 3086 | }; | 3088 | }; |
| 3087 | 3089 | ||
| 3088 | atom.alignment = 1; // debug sections are always 1-byte-aligned | 3090 | atom.alignment = .@"1"; // debug sections are always 1-byte-aligned |
| 3089 | return atom_index; | 3091 | return atom_index; |
| 3090 | } | 3092 | } |
| 3091 | 3093 | ||
| ... | @@ -4724,12 +4726,12 @@ fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.ArrayList(u8)) !void { | ... | @@ -4724,12 +4726,12 @@ fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.ArrayList(u8)) !void { |
| 4724 | for (wasm.segment_info.values()) |segment_info| { | 4726 | for (wasm.segment_info.values()) |segment_info| { |
| 4725 | log.debug("Emit segment: {s} align({d}) flags({b})", .{ | 4727 | log.debug("Emit segment: {s} align({d}) flags({b})", .{ |
| 4726 | segment_info.name, | 4728 | segment_info.name, |
| 4727 | @ctz(segment_info.alignment), | 4729 | segment_info.alignment, |
| 4728 | segment_info.flags, | 4730 | segment_info.flags, |
| 4729 | }); | 4731 | }); |
| 4730 | try leb.writeULEB128(writer, @as(u32, @intCast(segment_info.name.len))); | 4732 | try leb.writeULEB128(writer, @as(u32, @intCast(segment_info.name.len))); |
| 4731 | try writer.writeAll(segment_info.name); | 4733 | try writer.writeAll(segment_info.name); |
| 4732 | try leb.writeULEB128(writer, @ctz(segment_info.alignment)); | 4734 | try leb.writeULEB128(writer, segment_info.alignment.toLog2Units()); |
| 4733 | try leb.writeULEB128(writer, segment_info.flags); | 4735 | try leb.writeULEB128(writer, segment_info.flags); |
| 4734 | } | 4736 | } |
| 4735 | 4737 |
src/link/Wasm/Atom.zig+2-2| ... | @@ -19,7 +19,7 @@ relocs: std.ArrayListUnmanaged(types.Relocation) = .{}, | ... | @@ -19,7 +19,7 @@ relocs: std.ArrayListUnmanaged(types.Relocation) = .{}, |
| 19 | /// Contains the binary data of an atom, which can be non-relocated | 19 | /// Contains the binary data of an atom, which can be non-relocated |
| 20 | code: std.ArrayListUnmanaged(u8) = .{}, | 20 | code: std.ArrayListUnmanaged(u8) = .{}, |
| 21 | /// For code this is 1, for data this is set to the highest value of all segments | 21 | /// For code this is 1, for data this is set to the highest value of all segments |
| 22 | alignment: u32, | 22 | alignment: Wasm.Alignment, |
| 23 | /// Offset into the section where the atom lives, this already accounts | 23 | /// Offset into the section where the atom lives, this already accounts |
| 24 | /// for alignment. | 24 | /// for alignment. |
| 25 | offset: u32, | 25 | offset: u32, |
| ... | @@ -43,7 +43,7 @@ pub const Index = u32; | ... | @@ -43,7 +43,7 @@ pub const Index = u32; |
| 43 | 43 | ||
| 44 | /// Represents a default empty wasm `Atom` | 44 | /// Represents a default empty wasm `Atom` |
| 45 | pub const empty: Atom = .{ | 45 | pub const empty: Atom = .{ |
| 46 | .alignment = 1, | 46 | .alignment = .@"1", |
| 47 | .file = null, | 47 | .file = null, |
| 48 | .next = null, | 48 | .next = null, |
| 49 | .offset = 0, | 49 | .offset = 0, |
src/link/Wasm/Object.zig+7-9| ... | @@ -8,6 +8,7 @@ const types = @import("types.zig"); | ... | @@ -8,6 +8,7 @@ const types = @import("types.zig"); |
| 8 | const std = @import("std"); | 8 | const std = @import("std"); |
| 9 | const Wasm = @import("../Wasm.zig"); | 9 | const Wasm = @import("../Wasm.zig"); |
| 10 | const Symbol = @import("Symbol.zig"); | 10 | const Symbol = @import("Symbol.zig"); |
| 11 | const Alignment = types.Alignment; | ||
| 11 | 12 | ||
| 12 | const Allocator = std.mem.Allocator; | 13 | const Allocator = std.mem.Allocator; |
| 13 | const leb = std.leb; | 14 | const leb = std.leb; |
| ... | @@ -88,12 +89,9 @@ const RelocatableData = struct { | ... | @@ -88,12 +89,9 @@ const RelocatableData = struct { |
| 88 | /// meta data of the given object file. | 89 | /// meta data of the given object file. |
| 89 | /// NOTE: Alignment is encoded as a power of 2, so we shift the symbol's | 90 | /// NOTE: Alignment is encoded as a power of 2, so we shift the symbol's |
| 90 | /// alignment to retrieve the natural alignment. | 91 | /// alignment to retrieve the natural alignment. |
| 91 | pub fn getAlignment(relocatable_data: RelocatableData, object: *const Object) u32 { | 92 | pub fn getAlignment(relocatable_data: RelocatableData, object: *const Object) Alignment { |
| 92 | if (relocatable_data.type != .data) return 1; | 93 | if (relocatable_data.type != .data) return .@"1"; |
| 93 | const data_alignment = object.segment_info[relocatable_data.index].alignment; | 94 | return object.segment_info[relocatable_data.index].alignment; |
| 94 | if (data_alignment == 0) return 1; | ||
| 95 | // Decode from power of 2 to natural alignment | ||
| 96 | return @as(u32, 1) << @as(u5, @intCast(data_alignment)); | ||
| 97 | } | 95 | } |
| 98 | 96 | ||
| 99 | /// Returns the symbol kind that corresponds to the relocatable section | 97 | /// Returns the symbol kind that corresponds to the relocatable section |
| ... | @@ -671,7 +669,7 @@ fn Parser(comptime ReaderType: type) type { | ... | @@ -671,7 +669,7 @@ fn Parser(comptime ReaderType: type) type { |
| 671 | try reader.readNoEof(name); | 669 | try reader.readNoEof(name); |
| 672 | segment.* = .{ | 670 | segment.* = .{ |
| 673 | .name = name, | 671 | .name = name, |
| 674 | .alignment = try leb.readULEB128(u32, reader), | 672 | .alignment = @enumFromInt(try leb.readULEB128(u32, reader)), |
| 675 | .flags = try leb.readULEB128(u32, reader), | 673 | .flags = try leb.readULEB128(u32, reader), |
| 676 | }; | 674 | }; |
| 677 | log.debug("Found segment: {s} align({d}) flags({b})", .{ | 675 | log.debug("Found segment: {s} align({d}) flags({b})", .{ |
| ... | @@ -919,7 +917,7 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b | ... | @@ -919,7 +917,7 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b |
| 919 | continue; // found unknown section, so skip parsing into atom as we do not know how to handle it. | 917 | continue; // found unknown section, so skip parsing into atom as we do not know how to handle it. |
| 920 | }; | 918 | }; |
| 921 | 919 | ||
| 922 | const atom_index = @as(Atom.Index, @intCast(wasm_bin.managed_atoms.items.len)); | 920 | const atom_index: Atom.Index = @intCast(wasm_bin.managed_atoms.items.len); |
| 923 | const atom = try wasm_bin.managed_atoms.addOne(gpa); | 921 | const atom = try wasm_bin.managed_atoms.addOne(gpa); |
| 924 | atom.* = Atom.empty; | 922 | atom.* = Atom.empty; |
| 925 | atom.file = object_index; | 923 | atom.file = object_index; |
| ... | @@ -984,7 +982,7 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b | ... | @@ -984,7 +982,7 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b |
| 984 | 982 | ||
| 985 | const segment: *Wasm.Segment = &wasm_bin.segments.items[final_index]; | 983 | const segment: *Wasm.Segment = &wasm_bin.segments.items[final_index]; |
| 986 | if (relocatable_data.type == .data) { //code section and debug sections are 1-byte aligned | 984 | if (relocatable_data.type == .data) { //code section and debug sections are 1-byte aligned |
| 987 | segment.alignment = @max(segment.alignment, atom.alignment); | 985 | segment.alignment = segment.alignment.max(atom.alignment); |
| 988 | } | 986 | } |
| 989 | 987 | ||
| 990 | try wasm_bin.appendAtomAtIndex(final_index, atom_index); | 988 | try wasm_bin.appendAtomAtIndex(final_index, atom_index); |
src/link/Wasm/types.zig+3-1| ... | @@ -109,11 +109,13 @@ pub const SubsectionType = enum(u8) { | ... | @@ -109,11 +109,13 @@ pub const SubsectionType = enum(u8) { |
| 109 | WASM_SYMBOL_TABLE = 8, | 109 | WASM_SYMBOL_TABLE = 8, |
| 110 | }; | 110 | }; |
| 111 | 111 | ||
| 112 | pub const Alignment = @import("../../InternPool.zig").Alignment; | ||
| 113 | |||
| 112 | pub const Segment = struct { | 114 | pub const Segment = struct { |
| 113 | /// Segment's name, encoded as UTF-8 bytes. | 115 | /// Segment's name, encoded as UTF-8 bytes. |
| 114 | name: []const u8, | 116 | name: []const u8, |
| 115 | /// The required alignment of the segment, encoded as a power of 2 | 117 | /// The required alignment of the segment, encoded as a power of 2 |
| 116 | alignment: u32, | 118 | alignment: Alignment, |
| 117 | /// Bitfield containing flags for a segment | 119 | /// Bitfield containing flags for a segment |
| 118 | flags: u32, | 120 | flags: u32, |
| 119 | 121 |
src/target.zig+7-6| ... | @@ -1,6 +1,7 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const Type = @import("type.zig").Type; | 2 | const Type = @import("type.zig").Type; |
| 3 | const AddressSpace = std.builtin.AddressSpace; | 3 | const AddressSpace = std.builtin.AddressSpace; |
| 4 | const Alignment = @import("InternPool.zig").Alignment; | ||
| 4 | 5 | ||
| 5 | pub const ArchOsAbi = struct { | 6 | pub const ArchOsAbi = struct { |
| 6 | arch: std.Target.Cpu.Arch, | 7 | arch: std.Target.Cpu.Arch, |
| ... | @@ -595,13 +596,13 @@ pub fn llvmMachineAbi(target: std.Target) ?[:0]const u8 { | ... | @@ -595,13 +596,13 @@ pub fn llvmMachineAbi(target: std.Target) ?[:0]const u8 { |
| 595 | } | 596 | } |
| 596 | 597 | ||
| 597 | /// This function returns 1 if function alignment is not observable or settable. | 598 | /// This function returns 1 if function alignment is not observable or settable. |
| 598 | pub fn defaultFunctionAlignment(target: std.Target) u32 { | 599 | pub fn defaultFunctionAlignment(target: std.Target) Alignment { |
| 599 | return switch (target.cpu.arch) { | 600 | return switch (target.cpu.arch) { |
| 600 | .arm, .armeb => 4, | 601 | .arm, .armeb => .@"4", |
| 601 | .aarch64, .aarch64_32, .aarch64_be => 4, | 602 | .aarch64, .aarch64_32, .aarch64_be => .@"4", |
| 602 | .sparc, .sparcel, .sparc64 => 4, | 603 | .sparc, .sparcel, .sparc64 => .@"4", |
| 603 | .riscv64 => 2, | 604 | .riscv64 => .@"2", |
| 604 | else => 1, | 605 | else => .@"1", |
| 605 | }; | 606 | }; |
| 606 | } | 607 | } |
| 607 | 608 |
src/type.zig+261-390| ... | @@ -9,6 +9,7 @@ const target_util = @import("target.zig"); | ... | @@ -9,6 +9,7 @@ const target_util = @import("target.zig"); |
| 9 | const TypedValue = @import("TypedValue.zig"); | 9 | const TypedValue = @import("TypedValue.zig"); |
| 10 | const Sema = @import("Sema.zig"); | 10 | const Sema = @import("Sema.zig"); |
| 11 | const InternPool = @import("InternPool.zig"); | 11 | const InternPool = @import("InternPool.zig"); |
| 12 | const Alignment = InternPool.Alignment; | ||
| 12 | 13 | ||
| 13 | /// Both types and values are canonically represented by a single 32-bit integer | 14 | /// Both types and values are canonically represented by a single 32-bit integer |
| 14 | /// which is an index into an `InternPool` data structure. | 15 | /// which is an index into an `InternPool` data structure. |
| ... | @@ -196,7 +197,9 @@ pub const Type = struct { | ... | @@ -196,7 +197,9 @@ pub const Type = struct { |
| 196 | info.packed_offset.host_size != 0 or | 197 | info.packed_offset.host_size != 0 or |
| 197 | info.flags.vector_index != .none) | 198 | info.flags.vector_index != .none) |
| 198 | { | 199 | { |
| 199 | const alignment = info.flags.alignment.toByteUnitsOptional() orelse | 200 | const alignment = if (info.flags.alignment != .none) |
| 201 | info.flags.alignment | ||
| 202 | else | ||
| 200 | info.child.toType().abiAlignment(mod); | 203 | info.child.toType().abiAlignment(mod); |
| 201 | try writer.print("align({d}", .{alignment}); | 204 | try writer.print("align({d}", .{alignment}); |
| 202 | 205 | ||
| ... | @@ -315,8 +318,8 @@ pub const Type = struct { | ... | @@ -315,8 +318,8 @@ pub const Type = struct { |
| 315 | .generic_poison => unreachable, | 318 | .generic_poison => unreachable, |
| 316 | }, | 319 | }, |
| 317 | .struct_type => |struct_type| { | 320 | .struct_type => |struct_type| { |
| 318 | if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| { | 321 | if (struct_type.decl.unwrap()) |decl_index| { |
| 319 | const decl = mod.declPtr(struct_obj.owner_decl); | 322 | const decl = mod.declPtr(decl_index); |
| 320 | try decl.renderFullyQualifiedName(mod, writer); | 323 | try decl.renderFullyQualifiedName(mod, writer); |
| 321 | } else if (struct_type.namespace.unwrap()) |namespace_index| { | 324 | } else if (struct_type.namespace.unwrap()) |namespace_index| { |
| 322 | const namespace = mod.namespacePtr(namespace_index); | 325 | const namespace = mod.namespacePtr(namespace_index); |
| ... | @@ -561,24 +564,20 @@ pub const Type = struct { | ... | @@ -561,24 +564,20 @@ pub const Type = struct { |
| 561 | .generic_poison => unreachable, | 564 | .generic_poison => unreachable, |
| 562 | }, | 565 | }, |
| 563 | .struct_type => |struct_type| { | 566 | .struct_type => |struct_type| { |
| 564 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse { | 567 | if (struct_type.assumeRuntimeBitsIfFieldTypesWip(ip)) { |
| 565 | // This struct has no fields. | ||
| 566 | return false; | ||
| 567 | }; | ||
| 568 | if (struct_obj.status == .field_types_wip) { | ||
| 569 | // In this case, we guess that hasRuntimeBits() for this type is true, | 568 | // In this case, we guess that hasRuntimeBits() for this type is true, |
| 570 | // and then later if our guess was incorrect, we emit a compile error. | 569 | // and then later if our guess was incorrect, we emit a compile error. |
| 571 | struct_obj.assumed_runtime_bits = true; | ||
| 572 | return true; | 570 | return true; |
| 573 | } | 571 | } |
| 574 | switch (strat) { | 572 | switch (strat) { |
| 575 | .sema => |sema| _ = try sema.resolveTypeFields(ty), | 573 | .sema => |sema| _ = try sema.resolveTypeFields(ty), |
| 576 | .eager => assert(struct_obj.haveFieldTypes()), | 574 | .eager => assert(struct_type.haveFieldTypes(ip)), |
| 577 | .lazy => if (!struct_obj.haveFieldTypes()) return error.NeedLazy, | 575 | .lazy => if (!struct_type.haveFieldTypes(ip)) return error.NeedLazy, |
| 578 | } | 576 | } |
| 579 | for (struct_obj.fields.values()) |field| { | 577 | for (0..struct_type.field_types.len) |i| { |
| 580 | if (field.is_comptime) continue; | 578 | if (struct_type.comptime_bits.getBit(ip, i)) continue; |
| 581 | if (try field.ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) | 579 | const field_ty = struct_type.field_types.get(ip)[i].toType(); |
| 580 | if (try field_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) | ||
| 582 | return true; | 581 | return true; |
| 583 | } else { | 582 | } else { |
| 584 | return false; | 583 | return false; |
| ... | @@ -728,11 +727,8 @@ pub const Type = struct { | ... | @@ -728,11 +727,8 @@ pub const Type = struct { |
| 728 | => false, | 727 | => false, |
| 729 | }, | 728 | }, |
| 730 | .struct_type => |struct_type| { | 729 | .struct_type => |struct_type| { |
| 731 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse { | 730 | // Struct with no fields have a well-defined layout of no bits. |
| 732 | // Struct with no fields has a well-defined layout of no bits. | 731 | return struct_type.layout != .Auto or struct_type.field_types.len == 0; |
| 733 | return true; | ||
| 734 | }; | ||
| 735 | return struct_obj.layout != .Auto; | ||
| 736 | }, | 732 | }, |
| 737 | .union_type => |union_type| switch (union_type.flagsPtr(ip).runtime_tag) { | 733 | .union_type => |union_type| switch (union_type.flagsPtr(ip).runtime_tag) { |
| 738 | .none, .safety => union_type.flagsPtr(ip).layout != .Auto, | 734 | .none, .safety => union_type.flagsPtr(ip).layout != .Auto, |
| ... | @@ -806,22 +802,23 @@ pub const Type = struct { | ... | @@ -806,22 +802,23 @@ pub const Type = struct { |
| 806 | return mod.intern_pool.isNoReturn(ty.toIntern()); | 802 | return mod.intern_pool.isNoReturn(ty.toIntern()); |
| 807 | } | 803 | } |
| 808 | 804 | ||
| 809 | /// Returns 0 if the pointer is naturally aligned and the element type is 0-bit. | 805 | /// Returns `none` if the pointer is naturally aligned and the element type is 0-bit. |
| 810 | pub fn ptrAlignment(ty: Type, mod: *Module) u32 { | 806 | pub fn ptrAlignment(ty: Type, mod: *Module) Alignment { |
| 811 | return ptrAlignmentAdvanced(ty, mod, null) catch unreachable; | 807 | return ptrAlignmentAdvanced(ty, mod, null) catch unreachable; |
| 812 | } | 808 | } |
| 813 | 809 | ||
| 814 | pub fn ptrAlignmentAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) !u32 { | 810 | pub fn ptrAlignmentAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) !Alignment { |
| 815 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | 811 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 816 | .ptr_type => |ptr_type| { | 812 | .ptr_type => |ptr_type| { |
| 817 | if (ptr_type.flags.alignment.toByteUnitsOptional()) |a| { | 813 | if (ptr_type.flags.alignment != .none) |
| 818 | return @as(u32, @intCast(a)); | 814 | return ptr_type.flags.alignment; |
| 819 | } else if (opt_sema) |sema| { | 815 | |
| 816 | if (opt_sema) |sema| { | ||
| 820 | const res = try ptr_type.child.toType().abiAlignmentAdvanced(mod, .{ .sema = sema }); | 817 | const res = try ptr_type.child.toType().abiAlignmentAdvanced(mod, .{ .sema = sema }); |
| 821 | return res.scalar; | 818 | return res.scalar; |
| 822 | } else { | ||
| 823 | return (ptr_type.child.toType().abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar; | ||
| 824 | } | 819 | } |
| 820 | |||
| 821 | return (ptr_type.child.toType().abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar; | ||
| 825 | }, | 822 | }, |
| 826 | .opt_type => |child| child.toType().ptrAlignmentAdvanced(mod, opt_sema), | 823 | .opt_type => |child| child.toType().ptrAlignmentAdvanced(mod, opt_sema), |
| 827 | else => unreachable, | 824 | else => unreachable, |
| ... | @@ -836,8 +833,8 @@ pub const Type = struct { | ... | @@ -836,8 +833,8 @@ pub const Type = struct { |
| 836 | }; | 833 | }; |
| 837 | } | 834 | } |
| 838 | 835 | ||
| 839 | /// Returns 0 for 0-bit types. | 836 | /// Returns `none` for 0-bit types. |
| 840 | pub fn abiAlignment(ty: Type, mod: *Module) u32 { | 837 | pub fn abiAlignment(ty: Type, mod: *Module) Alignment { |
| 841 | return (ty.abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar; | 838 | return (ty.abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar; |
| 842 | } | 839 | } |
| 843 | 840 | ||
| ... | @@ -846,12 +843,12 @@ pub const Type = struct { | ... | @@ -846,12 +843,12 @@ pub const Type = struct { |
| 846 | pub fn lazyAbiAlignment(ty: Type, mod: *Module) !Value { | 843 | pub fn lazyAbiAlignment(ty: Type, mod: *Module) !Value { |
| 847 | switch (try ty.abiAlignmentAdvanced(mod, .lazy)) { | 844 | switch (try ty.abiAlignmentAdvanced(mod, .lazy)) { |
| 848 | .val => |val| return val, | 845 | .val => |val| return val, |
| 849 | .scalar => |x| return mod.intValue(Type.comptime_int, x), | 846 | .scalar => |x| return mod.intValue(Type.comptime_int, x.toByteUnitsOptional().?), |
| 850 | } | 847 | } |
| 851 | } | 848 | } |
| 852 | 849 | ||
| 853 | pub const AbiAlignmentAdvanced = union(enum) { | 850 | pub const AbiAlignmentAdvanced = union(enum) { |
| 854 | scalar: u32, | 851 | scalar: Alignment, |
| 855 | val: Value, | 852 | val: Value, |
| 856 | }; | 853 | }; |
| 857 | 854 | ||
| ... | @@ -881,36 +878,36 @@ pub const Type = struct { | ... | @@ -881,36 +878,36 @@ pub const Type = struct { |
| 881 | }; | 878 | }; |
| 882 | 879 | ||
| 883 | switch (ty.toIntern()) { | 880 | switch (ty.toIntern()) { |
| 884 | .empty_struct_type => return AbiAlignmentAdvanced{ .scalar = 0 }, | 881 | .empty_struct_type => return AbiAlignmentAdvanced{ .scalar = .none }, |
| 885 | else => switch (ip.indexToKey(ty.toIntern())) { | 882 | else => switch (ip.indexToKey(ty.toIntern())) { |
| 886 | .int_type => |int_type| { | 883 | .int_type => |int_type| { |
| 887 | if (int_type.bits == 0) return AbiAlignmentAdvanced{ .scalar = 0 }; | 884 | if (int_type.bits == 0) return AbiAlignmentAdvanced{ .scalar = .none }; |
| 888 | return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(int_type.bits, target) }; | 885 | return .{ .scalar = intAbiAlignment(int_type.bits, target) }; |
| 889 | }, | 886 | }, |
| 890 | .ptr_type, .anyframe_type => { | 887 | .ptr_type, .anyframe_type => { |
| 891 | return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }; | 888 | return .{ .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)) }; |
| 892 | }, | 889 | }, |
| 893 | .array_type => |array_type| { | 890 | .array_type => |array_type| { |
| 894 | return array_type.child.toType().abiAlignmentAdvanced(mod, strat); | 891 | return array_type.child.toType().abiAlignmentAdvanced(mod, strat); |
| 895 | }, | 892 | }, |
| 896 | .vector_type => |vector_type| { | 893 | .vector_type => |vector_type| { |
| 897 | const bits_u64 = try bitSizeAdvanced(vector_type.child.toType(), mod, opt_sema); | 894 | const bits_u64 = try bitSizeAdvanced(vector_type.child.toType(), mod, opt_sema); |
| 898 | const bits = @as(u32, @intCast(bits_u64)); | 895 | const bits: u32 = @intCast(bits_u64); |
| 899 | const bytes = ((bits * vector_type.len) + 7) / 8; | 896 | const bytes = ((bits * vector_type.len) + 7) / 8; |
| 900 | const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes); | 897 | const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes); |
| 901 | return AbiAlignmentAdvanced{ .scalar = alignment }; | 898 | return .{ .scalar = Alignment.fromByteUnits(alignment) }; |
| 902 | }, | 899 | }, |
| 903 | 900 | ||
| 904 | .opt_type => return abiAlignmentAdvancedOptional(ty, mod, strat), | 901 | .opt_type => return abiAlignmentAdvancedOptional(ty, mod, strat), |
| 905 | .error_union_type => |info| return abiAlignmentAdvancedErrorUnion(ty, mod, strat, info.payload_type.toType()), | 902 | .error_union_type => |info| return abiAlignmentAdvancedErrorUnion(ty, mod, strat, info.payload_type.toType()), |
| 906 | 903 | ||
| 907 | // TODO revisit this when we have the concept of the error tag type | 904 | // TODO revisit this when we have the concept of the error tag type |
| 908 | .error_set_type, .inferred_error_set_type => return AbiAlignmentAdvanced{ .scalar = 2 }, | 905 | .error_set_type, .inferred_error_set_type => return .{ .scalar = .@"2" }, |
| 909 | 906 | ||
| 910 | // represents machine code; not a pointer | 907 | // represents machine code; not a pointer |
| 911 | .func_type => |func_type| return AbiAlignmentAdvanced{ | 908 | .func_type => |func_type| return .{ |
| 912 | .scalar = if (func_type.alignment.toByteUnitsOptional()) |a| | 909 | .scalar = if (func_type.alignment != .none) |
| 913 | @as(u32, @intCast(a)) | 910 | func_type.alignment |
| 914 | else | 911 | else |
| 915 | target_util.defaultFunctionAlignment(target), | 912 | target_util.defaultFunctionAlignment(target), |
| 916 | }, | 913 | }, |
| ... | @@ -926,47 +923,49 @@ pub const Type = struct { | ... | @@ -926,47 +923,49 @@ pub const Type = struct { |
| 926 | .call_modifier, | 923 | .call_modifier, |
| 927 | .prefetch_options, | 924 | .prefetch_options, |
| 928 | .anyopaque, | 925 | .anyopaque, |
| 929 | => return AbiAlignmentAdvanced{ .scalar = 1 }, | 926 | => return .{ .scalar = .@"1" }, |
| 930 | 927 | ||
| 931 | .usize, | 928 | .usize, |
| 932 | .isize, | 929 | .isize, |
| 933 | .export_options, | 930 | .export_options, |
| 934 | .extern_options, | 931 | .extern_options, |
| 935 | => return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, | 932 | => return .{ |
| 936 | 933 | .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)), | |
| 937 | .c_char => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.char) }, | 934 | }, |
| 938 | .c_short => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.short) }, | 935 | |
| 939 | .c_ushort => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ushort) }, | 936 | .c_char => return .{ .scalar = cTypeAlign(target, .char) }, |
| 940 | .c_int => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.int) }, | 937 | .c_short => return .{ .scalar = cTypeAlign(target, .short) }, |
| 941 | .c_uint => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.uint) }, | 938 | .c_ushort => return .{ .scalar = cTypeAlign(target, .ushort) }, |
| 942 | .c_long => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.long) }, | 939 | .c_int => return .{ .scalar = cTypeAlign(target, .int) }, |
| 943 | .c_ulong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ulong) }, | 940 | .c_uint => return .{ .scalar = cTypeAlign(target, .uint) }, |
| 944 | .c_longlong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longlong) }, | 941 | .c_long => return .{ .scalar = cTypeAlign(target, .long) }, |
| 945 | .c_ulonglong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ulonglong) }, | 942 | .c_ulong => return .{ .scalar = cTypeAlign(target, .ulong) }, |
| 946 | .c_longdouble => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) }, | 943 | .c_longlong => return .{ .scalar = cTypeAlign(target, .longlong) }, |
| 947 | 944 | .c_ulonglong => return .{ .scalar = cTypeAlign(target, .ulonglong) }, | |
| 948 | .f16 => return AbiAlignmentAdvanced{ .scalar = 2 }, | 945 | .c_longdouble => return .{ .scalar = cTypeAlign(target, .longdouble) }, |
| 949 | .f32 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.float) }, | 946 | |
| 947 | .f16 => return .{ .scalar = .@"2" }, | ||
| 948 | .f32 => return .{ .scalar = cTypeAlign(target, .float) }, | ||
| 950 | .f64 => switch (target.c_type_bit_size(.double)) { | 949 | .f64 => switch (target.c_type_bit_size(.double)) { |
| 951 | 64 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.double) }, | 950 | 64 => return .{ .scalar = cTypeAlign(target, .double) }, |
| 952 | else => return AbiAlignmentAdvanced{ .scalar = 8 }, | 951 | else => return .{ .scalar = .@"8" }, |
| 953 | }, | 952 | }, |
| 954 | .f80 => switch (target.c_type_bit_size(.longdouble)) { | 953 | .f80 => switch (target.c_type_bit_size(.longdouble)) { |
| 955 | 80 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) }, | 954 | 80 => return .{ .scalar = cTypeAlign(target, .longdouble) }, |
| 956 | else => { | 955 | else => { |
| 957 | const u80_ty: Type = .{ .ip_index = .u80_type }; | 956 | const u80_ty: Type = .{ .ip_index = .u80_type }; |
| 958 | return AbiAlignmentAdvanced{ .scalar = abiAlignment(u80_ty, mod) }; | 957 | return .{ .scalar = abiAlignment(u80_ty, mod) }; |
| 959 | }, | 958 | }, |
| 960 | }, | 959 | }, |
| 961 | .f128 => switch (target.c_type_bit_size(.longdouble)) { | 960 | .f128 => switch (target.c_type_bit_size(.longdouble)) { |
| 962 | 128 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) }, | 961 | 128 => return .{ .scalar = cTypeAlign(target, .longdouble) }, |
| 963 | else => return AbiAlignmentAdvanced{ .scalar = 16 }, | 962 | else => return .{ .scalar = .@"16" }, |
| 964 | }, | 963 | }, |
| 965 | 964 | ||
| 966 | // TODO revisit this when we have the concept of the error tag type | 965 | // TODO revisit this when we have the concept of the error tag type |
| 967 | .anyerror, | 966 | .anyerror, |
| 968 | .adhoc_inferred_error_set, | 967 | .adhoc_inferred_error_set, |
| 969 | => return AbiAlignmentAdvanced{ .scalar = 2 }, | 968 | => return .{ .scalar = .@"2" }, |
| 970 | 969 | ||
| 971 | .void, | 970 | .void, |
| 972 | .type, | 971 | .type, |
| ... | @@ -976,89 +975,57 @@ pub const Type = struct { | ... | @@ -976,89 +975,57 @@ pub const Type = struct { |
| 976 | .undefined, | 975 | .undefined, |
| 977 | .enum_literal, | 976 | .enum_literal, |
| 978 | .type_info, | 977 | .type_info, |
| 979 | => return AbiAlignmentAdvanced{ .scalar = 0 }, | 978 | => return .{ .scalar = .none }, |
| 980 | 979 | ||
| 981 | .noreturn => unreachable, | 980 | .noreturn => unreachable, |
| 982 | .generic_poison => unreachable, | 981 | .generic_poison => unreachable, |
| 983 | }, | 982 | }, |
| 984 | .struct_type => |struct_type| { | 983 | .struct_type => |struct_type| { |
| 985 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse | 984 | if (struct_type.layout == .Packed) { |
| 986 | return AbiAlignmentAdvanced{ .scalar = 0 }; | ||
| 987 | |||
| 988 | if (opt_sema) |sema| { | ||
| 989 | if (struct_obj.status == .field_types_wip) { | ||
| 990 | // We'll guess "pointer-aligned", if the struct has an | ||
| 991 | // underaligned pointer field then some allocations | ||
| 992 | // might require explicit alignment. | ||
| 993 | return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }; | ||
| 994 | } | ||
| 995 | _ = try sema.resolveTypeFields(ty); | ||
| 996 | } | ||
| 997 | if (!struct_obj.haveFieldTypes()) switch (strat) { | ||
| 998 | .eager => unreachable, // struct layout not resolved | ||
| 999 | .sema => unreachable, // handled above | ||
| 1000 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ | ||
| 1001 | .ty = .comptime_int_type, | ||
| 1002 | .storage = .{ .lazy_align = ty.toIntern() }, | ||
| 1003 | } })).toValue() }, | ||
| 1004 | }; | ||
| 1005 | if (struct_obj.layout == .Packed) { | ||
| 1006 | switch (strat) { | 985 | switch (strat) { |
| 1007 | .sema => |sema| try sema.resolveTypeLayout(ty), | 986 | .sema => |sema| try sema.resolveTypeLayout(ty), |
| 1008 | .lazy => if (!struct_obj.haveLayout()) return .{ .val = (try mod.intern(.{ .int = .{ | 987 | .lazy => if (struct_type.backingIntType(ip).* == .none) return .{ |
| 1009 | .ty = .comptime_int_type, | 988 | .val = (try mod.intern(.{ .int = .{ |
| 1010 | .storage = .{ .lazy_align = ty.toIntern() }, | 989 | .ty = .comptime_int_type, |
| 1011 | } })).toValue() }, | 990 | .storage = .{ .lazy_align = ty.toIntern() }, |
| 991 | } })).toValue(), | ||
| 992 | }, | ||
| 1012 | .eager => {}, | 993 | .eager => {}, |
| 1013 | } | 994 | } |
| 1014 | assert(struct_obj.haveLayout()); | 995 | assert(struct_type.backingIntType(ip).* != .none); |
| 1015 | return AbiAlignmentAdvanced{ .scalar = struct_obj.backing_int_ty.abiAlignment(mod) }; | 996 | return .{ .scalar = struct_type.backingIntType(ip).toType().abiAlignment(mod) }; |
| 1016 | } | 997 | } |
| 1017 | 998 | ||
| 1018 | const fields = ty.structFields(mod); | 999 | const flags = struct_type.flagsPtr(ip).*; |
| 1019 | var big_align: u32 = 0; | 1000 | if (flags.layout_resolved) |
| 1020 | for (fields.values()) |field| { | 1001 | return .{ .scalar = flags.alignment }; |
| 1021 | if (!(field.ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { | ||
| 1022 | error.NeedLazy => return .{ .val = (try mod.intern(.{ .int = .{ | ||
| 1023 | .ty = .comptime_int_type, | ||
| 1024 | .storage = .{ .lazy_align = ty.toIntern() }, | ||
| 1025 | } })).toValue() }, | ||
| 1026 | else => |e| return e, | ||
| 1027 | })) continue; | ||
| 1028 | 1002 | ||
| 1029 | const field_align = @as(u32, @intCast(field.abi_align.toByteUnitsOptional() orelse | 1003 | switch (strat) { |
| 1030 | switch (try field.ty.abiAlignmentAdvanced(mod, strat)) { | 1004 | .eager => unreachable, // struct layout not resolved |
| 1031 | .scalar => |a| a, | 1005 | .sema => |sema| { |
| 1032 | .val => switch (strat) { | 1006 | if (flags.field_types_wip) { |
| 1033 | .eager => unreachable, // struct layout not resolved | 1007 | // We'll guess "pointer-aligned", if the struct has an |
| 1034 | .sema => unreachable, // handled above | 1008 | // underaligned pointer field then some allocations |
| 1035 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ | 1009 | // might require explicit alignment. |
| 1036 | .ty = .comptime_int_type, | 1010 | return .{ .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)) }; |
| 1037 | .storage = .{ .lazy_align = ty.toIntern() }, | ||
| 1038 | } })).toValue() }, | ||
| 1039 | }, | ||
| 1040 | })); | ||
| 1041 | big_align = @max(big_align, field_align); | ||
| 1042 | |||
| 1043 | // This logic is duplicated in Module.Struct.Field.alignment. | ||
| 1044 | if (struct_obj.layout == .Extern or target.ofmt == .c) { | ||
| 1045 | if (field.ty.isAbiInt(mod) and field.ty.intInfo(mod).bits >= 128) { | ||
| 1046 | // The C ABI requires 128 bit integer fields of structs | ||
| 1047 | // to be 16-bytes aligned. | ||
| 1048 | big_align = @max(big_align, 16); | ||
| 1049 | } | 1011 | } |
| 1050 | } | 1012 | try sema.resolveTypeLayout(ty); |
| 1013 | return .{ .scalar = struct_type.flagsPtr(ip).alignment }; | ||
| 1014 | }, | ||
| 1015 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ | ||
| 1016 | .ty = .comptime_int_type, | ||
| 1017 | .storage = .{ .lazy_align = ty.toIntern() }, | ||
| 1018 | } })).toValue() }, | ||
| 1051 | } | 1019 | } |
| 1052 | return AbiAlignmentAdvanced{ .scalar = big_align }; | ||
| 1053 | }, | 1020 | }, |
| 1054 | .anon_struct_type => |tuple| { | 1021 | .anon_struct_type => |tuple| { |
| 1055 | var big_align: u32 = 0; | 1022 | var big_align: Alignment = .none; |
| 1056 | for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| { | 1023 | for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| { |
| 1057 | if (val != .none) continue; // comptime field | 1024 | if (val != .none) continue; // comptime field |
| 1058 | if (!(field_ty.toType().hasRuntimeBits(mod))) continue; | 1025 | if (!(field_ty.toType().hasRuntimeBits(mod))) continue; |
| 1059 | 1026 | ||
| 1060 | switch (try field_ty.toType().abiAlignmentAdvanced(mod, strat)) { | 1027 | switch (try field_ty.toType().abiAlignmentAdvanced(mod, strat)) { |
| 1061 | .scalar => |field_align| big_align = @max(big_align, field_align), | 1028 | .scalar => |field_align| big_align = big_align.max(field_align), |
| 1062 | .val => switch (strat) { | 1029 | .val => switch (strat) { |
| 1063 | .eager => unreachable, // field type alignment not resolved | 1030 | .eager => unreachable, // field type alignment not resolved |
| 1064 | .sema => unreachable, // passed to abiAlignmentAdvanced above | 1031 | .sema => unreachable, // passed to abiAlignmentAdvanced above |
| ... | @@ -1069,7 +1036,7 @@ pub const Type = struct { | ... | @@ -1069,7 +1036,7 @@ pub const Type = struct { |
| 1069 | }, | 1036 | }, |
| 1070 | } | 1037 | } |
| 1071 | } | 1038 | } |
| 1072 | return AbiAlignmentAdvanced{ .scalar = big_align }; | 1039 | return .{ .scalar = big_align }; |
| 1073 | }, | 1040 | }, |
| 1074 | 1041 | ||
| 1075 | .union_type => |union_type| { | 1042 | .union_type => |union_type| { |
| ... | @@ -1078,7 +1045,7 @@ pub const Type = struct { | ... | @@ -1078,7 +1045,7 @@ pub const Type = struct { |
| 1078 | // We'll guess "pointer-aligned", if the union has an | 1045 | // We'll guess "pointer-aligned", if the union has an |
| 1079 | // underaligned pointer field then some allocations | 1046 | // underaligned pointer field then some allocations |
| 1080 | // might require explicit alignment. | 1047 | // might require explicit alignment. |
| 1081 | return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }; | 1048 | return .{ .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)) }; |
| 1082 | } | 1049 | } |
| 1083 | _ = try sema.resolveTypeFields(ty); | 1050 | _ = try sema.resolveTypeFields(ty); |
| 1084 | } | 1051 | } |
| ... | @@ -1095,13 +1062,13 @@ pub const Type = struct { | ... | @@ -1095,13 +1062,13 @@ pub const Type = struct { |
| 1095 | if (union_obj.hasTag(ip)) { | 1062 | if (union_obj.hasTag(ip)) { |
| 1096 | return abiAlignmentAdvanced(union_obj.enum_tag_ty.toType(), mod, strat); | 1063 | return abiAlignmentAdvanced(union_obj.enum_tag_ty.toType(), mod, strat); |
| 1097 | } else { | 1064 | } else { |
| 1098 | return AbiAlignmentAdvanced{ | 1065 | return .{ |
| 1099 | .scalar = @intFromBool(union_obj.flagsPtr(ip).layout == .Extern), | 1066 | .scalar = Alignment.fromByteUnits(@intFromBool(union_obj.flagsPtr(ip).layout == .Extern)), |
| 1100 | }; | 1067 | }; |
| 1101 | } | 1068 | } |
| 1102 | } | 1069 | } |
| 1103 | 1070 | ||
| 1104 | var max_align: u32 = 0; | 1071 | var max_align: Alignment = .none; |
| 1105 | if (union_obj.hasTag(ip)) max_align = union_obj.enum_tag_ty.toType().abiAlignment(mod); | 1072 | if (union_obj.hasTag(ip)) max_align = union_obj.enum_tag_ty.toType().abiAlignment(mod); |
| 1106 | for (0..union_obj.field_names.len) |field_index| { | 1073 | for (0..union_obj.field_names.len) |field_index| { |
| 1107 | const field_ty = union_obj.field_types.get(ip)[field_index].toType(); | 1074 | const field_ty = union_obj.field_types.get(ip)[field_index].toType(); |
| ... | @@ -1117,8 +1084,9 @@ pub const Type = struct { | ... | @@ -1117,8 +1084,9 @@ pub const Type = struct { |
| 1117 | else => |e| return e, | 1084 | else => |e| return e, |
| 1118 | })) continue; | 1085 | })) continue; |
| 1119 | 1086 | ||
| 1120 | const field_align_bytes: u32 = @intCast(field_align.toByteUnitsOptional() orelse | 1087 | const field_align_bytes: Alignment = if (field_align != .none) |
| 1121 | switch (try field_ty.abiAlignmentAdvanced(mod, strat)) { | 1088 | field_align |
| 1089 | else switch (try field_ty.abiAlignmentAdvanced(mod, strat)) { | ||
| 1122 | .scalar => |a| a, | 1090 | .scalar => |a| a, |
| 1123 | .val => switch (strat) { | 1091 | .val => switch (strat) { |
| 1124 | .eager => unreachable, // struct layout not resolved | 1092 | .eager => unreachable, // struct layout not resolved |
| ... | @@ -1128,13 +1096,15 @@ pub const Type = struct { | ... | @@ -1128,13 +1096,15 @@ pub const Type = struct { |
| 1128 | .storage = .{ .lazy_align = ty.toIntern() }, | 1096 | .storage = .{ .lazy_align = ty.toIntern() }, |
| 1129 | } })).toValue() }, | 1097 | } })).toValue() }, |
| 1130 | }, | 1098 | }, |
| 1131 | }); | 1099 | }; |
| 1132 | max_align = @max(max_align, field_align_bytes); | 1100 | max_align = max_align.max(field_align_bytes); |
| 1133 | } | 1101 | } |
| 1134 | return AbiAlignmentAdvanced{ .scalar = max_align }; | 1102 | return .{ .scalar = max_align }; |
| 1103 | }, | ||
| 1104 | .opaque_type => return .{ .scalar = .@"1" }, | ||
| 1105 | .enum_type => |enum_type| return .{ | ||
| 1106 | .scalar = enum_type.tag_ty.toType().abiAlignment(mod), | ||
| 1135 | }, | 1107 | }, |
| 1136 | .opaque_type => return AbiAlignmentAdvanced{ .scalar = 1 }, | ||
| 1137 | .enum_type => |enum_type| return AbiAlignmentAdvanced{ .scalar = enum_type.tag_ty.toType().abiAlignment(mod) }, | ||
| 1138 | 1108 | ||
| 1139 | // values, not types | 1109 | // values, not types |
| 1140 | .undef, | 1110 | .undef, |
| ... | @@ -1179,20 +1149,15 @@ pub const Type = struct { | ... | @@ -1179,20 +1149,15 @@ pub const Type = struct { |
| 1179 | } })).toValue() }, | 1149 | } })).toValue() }, |
| 1180 | else => |e| return e, | 1150 | else => |e| return e, |
| 1181 | })) { | 1151 | })) { |
| 1182 | return AbiAlignmentAdvanced{ .scalar = code_align }; | 1152 | return .{ .scalar = code_align }; |
| 1183 | } | 1153 | } |
| 1184 | return AbiAlignmentAdvanced{ .scalar = @max( | 1154 | return .{ .scalar = code_align.max( |
| 1185 | code_align, | ||
| 1186 | (try payload_ty.abiAlignmentAdvanced(mod, strat)).scalar, | 1155 | (try payload_ty.abiAlignmentAdvanced(mod, strat)).scalar, |
| 1187 | ) }; | 1156 | ) }; |
| 1188 | }, | 1157 | }, |
| 1189 | .lazy => { | 1158 | .lazy => { |
| 1190 | switch (try payload_ty.abiAlignmentAdvanced(mod, strat)) { | 1159 | switch (try payload_ty.abiAlignmentAdvanced(mod, strat)) { |
| 1191 | .scalar => |payload_align| { | 1160 | .scalar => |payload_align| return .{ .scalar = code_align.max(payload_align) }, |
| 1192 | return AbiAlignmentAdvanced{ | ||
| 1193 | .scalar = @max(code_align, payload_align), | ||
| 1194 | }; | ||
| 1195 | }, | ||
| 1196 | .val => {}, | 1161 | .val => {}, |
| 1197 | } | 1162 | } |
| 1198 | return .{ .val = (try mod.intern(.{ .int = .{ | 1163 | return .{ .val = (try mod.intern(.{ .int = .{ |
| ... | @@ -1212,9 +1177,11 @@ pub const Type = struct { | ... | @@ -1212,9 +1177,11 @@ pub const Type = struct { |
| 1212 | const child_type = ty.optionalChild(mod); | 1177 | const child_type = ty.optionalChild(mod); |
| 1213 | 1178 | ||
| 1214 | switch (child_type.zigTypeTag(mod)) { | 1179 | switch (child_type.zigTypeTag(mod)) { |
| 1215 | .Pointer => return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, | 1180 | .Pointer => return .{ |
| 1181 | .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)), | ||
| 1182 | }, | ||
| 1216 | .ErrorSet => return abiAlignmentAdvanced(Type.anyerror, mod, strat), | 1183 | .ErrorSet => return abiAlignmentAdvanced(Type.anyerror, mod, strat), |
| 1217 | .NoReturn => return AbiAlignmentAdvanced{ .scalar = 0 }, | 1184 | .NoReturn => return .{ .scalar = .none }, |
| 1218 | else => {}, | 1185 | else => {}, |
| 1219 | } | 1186 | } |
| 1220 | 1187 | ||
| ... | @@ -1227,12 +1194,12 @@ pub const Type = struct { | ... | @@ -1227,12 +1194,12 @@ pub const Type = struct { |
| 1227 | } })).toValue() }, | 1194 | } })).toValue() }, |
| 1228 | else => |e| return e, | 1195 | else => |e| return e, |
| 1229 | })) { | 1196 | })) { |
| 1230 | return AbiAlignmentAdvanced{ .scalar = 1 }; | 1197 | return .{ .scalar = .@"1" }; |
| 1231 | } | 1198 | } |
| 1232 | return child_type.abiAlignmentAdvanced(mod, strat); | 1199 | return child_type.abiAlignmentAdvanced(mod, strat); |
| 1233 | }, | 1200 | }, |
| 1234 | .lazy => switch (try child_type.abiAlignmentAdvanced(mod, strat)) { | 1201 | .lazy => switch (try child_type.abiAlignmentAdvanced(mod, strat)) { |
| 1235 | .scalar => |x| return AbiAlignmentAdvanced{ .scalar = @max(x, 1) }, | 1202 | .scalar => |x| return .{ .scalar = x.max(.@"1") }, |
| 1236 | .val => return .{ .val = (try mod.intern(.{ .int = .{ | 1203 | .val => return .{ .val = (try mod.intern(.{ .int = .{ |
| 1237 | .ty = .comptime_int_type, | 1204 | .ty = .comptime_int_type, |
| 1238 | .storage = .{ .lazy_align = ty.toIntern() }, | 1205 | .storage = .{ .lazy_align = ty.toIntern() }, |
| ... | @@ -1310,8 +1277,7 @@ pub const Type = struct { | ... | @@ -1310,8 +1277,7 @@ pub const Type = struct { |
| 1310 | .storage = .{ .lazy_size = ty.toIntern() }, | 1277 | .storage = .{ .lazy_size = ty.toIntern() }, |
| 1311 | } })).toValue() }, | 1278 | } })).toValue() }, |
| 1312 | }; | 1279 | }; |
| 1313 | const elem_bits_u64 = try vector_type.child.toType().bitSizeAdvanced(mod, opt_sema); | 1280 | const elem_bits = try vector_type.child.toType().bitSizeAdvanced(mod, opt_sema); |
| 1314 | const elem_bits = @as(u32, @intCast(elem_bits_u64)); | ||
| 1315 | const total_bits = elem_bits * vector_type.len; | 1281 | const total_bits = elem_bits * vector_type.len; |
| 1316 | const total_bytes = (total_bits + 7) / 8; | 1282 | const total_bytes = (total_bits + 7) / 8; |
| 1317 | const alignment = switch (try ty.abiAlignmentAdvanced(mod, strat)) { | 1283 | const alignment = switch (try ty.abiAlignmentAdvanced(mod, strat)) { |
| ... | @@ -1321,8 +1287,7 @@ pub const Type = struct { | ... | @@ -1321,8 +1287,7 @@ pub const Type = struct { |
| 1321 | .storage = .{ .lazy_size = ty.toIntern() }, | 1287 | .storage = .{ .lazy_size = ty.toIntern() }, |
| 1322 | } })).toValue() }, | 1288 | } })).toValue() }, |
| 1323 | }; | 1289 | }; |
| 1324 | const result = std.mem.alignForward(u32, total_bytes, alignment); | 1290 | return AbiSizeAdvanced{ .scalar = alignment.forward(total_bytes) }; |
| 1325 | return AbiSizeAdvanced{ .scalar = result }; | ||
| 1326 | }, | 1291 | }, |
| 1327 | 1292 | ||
| 1328 | .opt_type => return ty.abiSizeAdvancedOptional(mod, strat), | 1293 | .opt_type => return ty.abiSizeAdvancedOptional(mod, strat), |
| ... | @@ -1360,16 +1325,16 @@ pub const Type = struct { | ... | @@ -1360,16 +1325,16 @@ pub const Type = struct { |
| 1360 | }; | 1325 | }; |
| 1361 | 1326 | ||
| 1362 | var size: u64 = 0; | 1327 | var size: u64 = 0; |
| 1363 | if (code_align > payload_align) { | 1328 | if (code_align.compare(.gt, payload_align)) { |
| 1364 | size += code_size; | 1329 | size += code_size; |
| 1365 | size = std.mem.alignForward(u64, size, payload_align); | 1330 | size = payload_align.forward(size); |
| 1366 | size += payload_size; | 1331 | size += payload_size; |
| 1367 | size = std.mem.alignForward(u64, size, code_align); | 1332 | size = code_align.forward(size); |
| 1368 | } else { | 1333 | } else { |
| 1369 | size += payload_size; | 1334 | size += payload_size; |
| 1370 | size = std.mem.alignForward(u64, size, code_align); | 1335 | size = code_align.forward(size); |
| 1371 | size += code_size; | 1336 | size += code_size; |
| 1372 | size = std.mem.alignForward(u64, size, payload_align); | 1337 | size = payload_align.forward(size); |
| 1373 | } | 1338 | } |
| 1374 | return AbiSizeAdvanced{ .scalar = size }; | 1339 | return AbiSizeAdvanced{ .scalar = size }; |
| 1375 | }, | 1340 | }, |
| ... | @@ -1435,41 +1400,43 @@ pub const Type = struct { | ... | @@ -1435,41 +1400,43 @@ pub const Type = struct { |
| 1435 | .noreturn => unreachable, | 1400 | .noreturn => unreachable, |
| 1436 | .generic_poison => unreachable, | 1401 | .generic_poison => unreachable, |
| 1437 | }, | 1402 | }, |
| 1438 | .struct_type => |struct_type| switch (ty.containerLayout(mod)) { | 1403 | .struct_type => |struct_type| { |
| 1439 | .Packed => { | 1404 | switch (strat) { |
| 1440 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse | 1405 | .sema => |sema| try sema.resolveTypeLayout(ty), |
| 1441 | return AbiSizeAdvanced{ .scalar = 0 }; | 1406 | .lazy => switch (struct_type.layout) { |
| 1442 | 1407 | .Packed => { | |
| 1443 | switch (strat) { | 1408 | if (struct_type.backingIntType(ip).* == .none) return .{ |
| 1444 | .sema => |sema| try sema.resolveTypeLayout(ty), | 1409 | .val = (try mod.intern(.{ .int = .{ |
| 1445 | .lazy => if (!struct_obj.haveLayout()) return .{ .val = (try mod.intern(.{ .int = .{ | 1410 | .ty = .comptime_int_type, |
| 1446 | .ty = .comptime_int_type, | 1411 | .storage = .{ .lazy_size = ty.toIntern() }, |
| 1447 | .storage = .{ .lazy_size = ty.toIntern() }, | 1412 | } })).toValue(), |
| 1448 | } })).toValue() }, | 1413 | }; |
| 1449 | .eager => {}, | ||
| 1450 | } | ||
| 1451 | assert(struct_obj.haveLayout()); | ||
| 1452 | return AbiSizeAdvanced{ .scalar = struct_obj.backing_int_ty.abiSize(mod) }; | ||
| 1453 | }, | ||
| 1454 | else => { | ||
| 1455 | switch (strat) { | ||
| 1456 | .sema => |sema| try sema.resolveTypeLayout(ty), | ||
| 1457 | .lazy => { | ||
| 1458 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse | ||
| 1459 | return AbiSizeAdvanced{ .scalar = 0 }; | ||
| 1460 | if (!struct_obj.haveLayout()) return .{ .val = (try mod.intern(.{ .int = .{ | ||
| 1461 | .ty = .comptime_int_type, | ||
| 1462 | .storage = .{ .lazy_size = ty.toIntern() }, | ||
| 1463 | } })).toValue() }; | ||
| 1464 | }, | 1414 | }, |
| 1465 | .eager => {}, | 1415 | .Auto, .Extern => { |
| 1466 | } | 1416 | if (!struct_type.haveLayout(ip)) return .{ |
| 1467 | const field_count = ty.structFieldCount(mod); | 1417 | .val = (try mod.intern(.{ .int = .{ |
| 1468 | if (field_count == 0) { | 1418 | .ty = .comptime_int_type, |
| 1469 | return AbiSizeAdvanced{ .scalar = 0 }; | 1419 | .storage = .{ .lazy_size = ty.toIntern() }, |
| 1470 | } | 1420 | } })).toValue(), |
| 1471 | return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, mod) }; | 1421 | }; |
| 1472 | }, | 1422 | }, |
| 1423 | }, | ||
| 1424 | .eager => {}, | ||
| 1425 | } | ||
| 1426 | switch (struct_type.layout) { | ||
| 1427 | .Packed => { | ||
| 1428 | return .{ | ||
| 1429 | .scalar = struct_type.backingIntType(ip).toType().abiSize(mod), | ||
| 1430 | }; | ||
| 1431 | }, | ||
| 1432 | .Auto, .Extern => { | ||
| 1433 | const field_count = ty.structFieldCount(mod); | ||
| 1434 | if (field_count == 0) { | ||
| 1435 | return .{ .scalar = 0 }; | ||
| 1436 | } | ||
| 1437 | return .{ .scalar = ty.structFieldOffset(field_count, mod) }; | ||
| 1438 | }, | ||
| 1439 | } | ||
| 1473 | }, | 1440 | }, |
| 1474 | .anon_struct_type => |tuple| { | 1441 | .anon_struct_type => |tuple| { |
| 1475 | switch (strat) { | 1442 | switch (strat) { |
| ... | @@ -1565,20 +1532,19 @@ pub const Type = struct { | ... | @@ -1565,20 +1532,19 @@ pub const Type = struct { |
| 1565 | // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal | 1532 | // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal |
| 1566 | // to the child type's ABI alignment. | 1533 | // to the child type's ABI alignment. |
| 1567 | return AbiSizeAdvanced{ | 1534 | return AbiSizeAdvanced{ |
| 1568 | .scalar = child_ty.abiAlignment(mod) + payload_size, | 1535 | .scalar = child_ty.abiAlignment(mod).toByteUnits(0) + payload_size, |
| 1569 | }; | 1536 | }; |
| 1570 | } | 1537 | } |
| 1571 | 1538 | ||
| 1572 | fn intAbiSize(bits: u16, target: Target) u64 { | 1539 | fn intAbiSize(bits: u16, target: Target) u64 { |
| 1573 | const alignment = intAbiAlignment(bits, target); | 1540 | return intAbiAlignment(bits, target).forward(@as(u16, @intCast((@as(u17, bits) + 7) / 8))); |
| 1574 | return std.mem.alignForward(u64, @as(u16, @intCast((@as(u17, bits) + 7) / 8)), alignment); | ||
| 1575 | } | 1541 | } |
| 1576 | 1542 | ||
| 1577 | fn intAbiAlignment(bits: u16, target: Target) u32 { | 1543 | fn intAbiAlignment(bits: u16, target: Target) Alignment { |
| 1578 | return @min( | 1544 | return Alignment.fromByteUnits(@min( |
| 1579 | std.math.ceilPowerOfTwoPromote(u16, @as(u16, @intCast((@as(u17, bits) + 7) / 8))), | 1545 | std.math.ceilPowerOfTwoPromote(u16, @as(u16, @intCast((@as(u17, bits) + 7) / 8))), |
| 1580 | target.maxIntAlignment(), | 1546 | target.maxIntAlignment(), |
| 1581 | ); | 1547 | )); |
| 1582 | } | 1548 | } |
| 1583 | 1549 | ||
| 1584 | pub fn bitSize(ty: Type, mod: *Module) u64 { | 1550 | pub fn bitSize(ty: Type, mod: *Module) u64 { |
| ... | @@ -1610,7 +1576,7 @@ pub const Type = struct { | ... | @@ -1610,7 +1576,7 @@ pub const Type = struct { |
| 1610 | const len = array_type.len + @intFromBool(array_type.sentinel != .none); | 1576 | const len = array_type.len + @intFromBool(array_type.sentinel != .none); |
| 1611 | if (len == 0) return 0; | 1577 | if (len == 0) return 0; |
| 1612 | const elem_ty = array_type.child.toType(); | 1578 | const elem_ty = array_type.child.toType(); |
| 1613 | const elem_size = @max(elem_ty.abiAlignment(mod), elem_ty.abiSize(mod)); | 1579 | const elem_size = @max(elem_ty.abiAlignment(mod).toByteUnits(0), elem_ty.abiSize(mod)); |
| 1614 | if (elem_size == 0) return 0; | 1580 | if (elem_size == 0) return 0; |
| 1615 | const elem_bit_size = try bitSizeAdvanced(elem_ty, mod, opt_sema); | 1581 | const elem_bit_size = try bitSizeAdvanced(elem_ty, mod, opt_sema); |
| 1616 | return (len - 1) * 8 * elem_size + elem_bit_size; | 1582 | return (len - 1) * 8 * elem_size + elem_bit_size; |
| ... | @@ -1675,26 +1641,24 @@ pub const Type = struct { | ... | @@ -1675,26 +1641,24 @@ pub const Type = struct { |
| 1675 | .enum_literal => unreachable, | 1641 | .enum_literal => unreachable, |
| 1676 | .generic_poison => unreachable, | 1642 | .generic_poison => unreachable, |
| 1677 | 1643 | ||
| 1678 | .atomic_order => unreachable, // missing call to resolveTypeFields | 1644 | .atomic_order => unreachable, |
| 1679 | .atomic_rmw_op => unreachable, // missing call to resolveTypeFields | 1645 | .atomic_rmw_op => unreachable, |
| 1680 | .calling_convention => unreachable, // missing call to resolveTypeFields | 1646 | .calling_convention => unreachable, |
| 1681 | .address_space => unreachable, // missing call to resolveTypeFields | 1647 | .address_space => unreachable, |
| 1682 | .float_mode => unreachable, // missing call to resolveTypeFields | 1648 | .float_mode => unreachable, |
| 1683 | .reduce_op => unreachable, // missing call to resolveTypeFields | 1649 | .reduce_op => unreachable, |
| 1684 | .call_modifier => unreachable, // missing call to resolveTypeFields | 1650 | .call_modifier => unreachable, |
| 1685 | .prefetch_options => unreachable, // missing call to resolveTypeFields | 1651 | .prefetch_options => unreachable, |
| 1686 | .export_options => unreachable, // missing call to resolveTypeFields | 1652 | .export_options => unreachable, |
| 1687 | .extern_options => unreachable, // missing call to resolveTypeFields | 1653 | .extern_options => unreachable, |
| 1688 | .type_info => unreachable, // missing call to resolveTypeFields | 1654 | .type_info => unreachable, |
| 1689 | }, | 1655 | }, |
| 1690 | .struct_type => |struct_type| { | 1656 | .struct_type => |struct_type| { |
| 1691 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return 0; | 1657 | if (struct_type.layout == .Packed) { |
| 1692 | if (struct_obj.layout != .Packed) { | 1658 | if (opt_sema) |sema| _ = try sema.resolveTypeLayout(ty); |
| 1693 | return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8; | 1659 | return try struct_type.backingIntType(ip).*.toType().bitSizeAdvanced(mod, opt_sema); |
| 1694 | } | 1660 | } |
| 1695 | if (opt_sema) |sema| _ = try sema.resolveTypeLayout(ty); | 1661 | return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8; |
| 1696 | assert(struct_obj.haveLayout()); | ||
| 1697 | return try struct_obj.backing_int_ty.bitSizeAdvanced(mod, opt_sema); | ||
| 1698 | }, | 1662 | }, |
| 1699 | 1663 | ||
| 1700 | .anon_struct_type => { | 1664 | .anon_struct_type => { |
| ... | @@ -1749,13 +1713,7 @@ pub const Type = struct { | ... | @@ -1749,13 +1713,7 @@ pub const Type = struct { |
| 1749 | pub fn layoutIsResolved(ty: Type, mod: *Module) bool { | 1713 | pub fn layoutIsResolved(ty: Type, mod: *Module) bool { |
| 1750 | const ip = &mod.intern_pool; | 1714 | const ip = &mod.intern_pool; |
| 1751 | return switch (ip.indexToKey(ty.toIntern())) { | 1715 | return switch (ip.indexToKey(ty.toIntern())) { |
| 1752 | .struct_type => |struct_type| { | 1716 | .struct_type => |struct_type| struct_type.haveLayout(ip), |
| 1753 | if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| { | ||
| 1754 | return struct_obj.haveLayout(); | ||
| 1755 | } else { | ||
| 1756 | return true; | ||
| 1757 | } | ||
| 1758 | }, | ||
| 1759 | .union_type => |union_type| union_type.haveLayout(ip), | 1717 | .union_type => |union_type| union_type.haveLayout(ip), |
| 1760 | .array_type => |array_type| { | 1718 | .array_type => |array_type| { |
| 1761 | if ((array_type.len + @intFromBool(array_type.sentinel != .none)) == 0) return true; | 1719 | if ((array_type.len + @intFromBool(array_type.sentinel != .none)) == 0) return true; |
| ... | @@ -2020,10 +1978,7 @@ pub const Type = struct { | ... | @@ -2020,10 +1978,7 @@ pub const Type = struct { |
| 2020 | pub fn containerLayout(ty: Type, mod: *Module) std.builtin.Type.ContainerLayout { | 1978 | pub fn containerLayout(ty: Type, mod: *Module) std.builtin.Type.ContainerLayout { |
| 2021 | const ip = &mod.intern_pool; | 1979 | const ip = &mod.intern_pool; |
| 2022 | return switch (ip.indexToKey(ty.toIntern())) { | 1980 | return switch (ip.indexToKey(ty.toIntern())) { |
| 2023 | .struct_type => |struct_type| { | 1981 | .struct_type => |struct_type| struct_type.layout, |
| 2024 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return .Auto; | ||
| 2025 | return struct_obj.layout; | ||
| 2026 | }, | ||
| 2027 | .anon_struct_type => .Auto, | 1982 | .anon_struct_type => .Auto, |
| 2028 | .union_type => |union_type| union_type.flagsPtr(ip).layout, | 1983 | .union_type => |union_type| union_type.flagsPtr(ip).layout, |
| 2029 | else => unreachable, | 1984 | else => unreachable, |
| ... | @@ -2136,10 +2091,6 @@ pub const Type = struct { | ... | @@ -2136,10 +2091,6 @@ pub const Type = struct { |
| 2136 | return switch (ip.indexToKey(ty.toIntern())) { | 2091 | return switch (ip.indexToKey(ty.toIntern())) { |
| 2137 | .vector_type => |vector_type| vector_type.len, | 2092 | .vector_type => |vector_type| vector_type.len, |
| 2138 | .array_type => |array_type| array_type.len, | 2093 | .array_type => |array_type| array_type.len, |
| 2139 | .struct_type => |struct_type| { | ||
| 2140 | const struct_obj = ip.structPtrUnwrapConst(struct_type.index) orelse return 0; | ||
| 2141 | return struct_obj.fields.count(); | ||
| 2142 | }, | ||
| 2143 | .anon_struct_type => |tuple| tuple.types.len, | 2094 | .anon_struct_type => |tuple| tuple.types.len, |
| 2144 | 2095 | ||
| 2145 | else => unreachable, | 2096 | else => unreachable, |
| ... | @@ -2214,6 +2165,7 @@ pub const Type = struct { | ... | @@ -2214,6 +2165,7 @@ pub const Type = struct { |
| 2214 | 2165 | ||
| 2215 | /// Asserts the type is an integer, enum, error set, or vector of one of them. | 2166 | /// Asserts the type is an integer, enum, error set, or vector of one of them. |
| 2216 | pub fn intInfo(starting_ty: Type, mod: *Module) InternPool.Key.IntType { | 2167 | pub fn intInfo(starting_ty: Type, mod: *Module) InternPool.Key.IntType { |
| 2168 | const ip = &mod.intern_pool; | ||
| 2217 | const target = mod.getTarget(); | 2169 | const target = mod.getTarget(); |
| 2218 | var ty = starting_ty; | 2170 | var ty = starting_ty; |
| 2219 | 2171 | ||
| ... | @@ -2233,13 +2185,9 @@ pub const Type = struct { | ... | @@ -2233,13 +2185,9 @@ pub const Type = struct { |
| 2233 | .c_ulong_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulong) }, | 2185 | .c_ulong_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulong) }, |
| 2234 | .c_longlong_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.longlong) }, | 2186 | .c_longlong_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.longlong) }, |
| 2235 | .c_ulonglong_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulonglong) }, | 2187 | .c_ulonglong_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulonglong) }, |
| 2236 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { | 2188 | else => switch (ip.indexToKey(ty.toIntern())) { |
| 2237 | .int_type => |int_type| return int_type, | 2189 | .int_type => |int_type| return int_type, |
| 2238 | .struct_type => |struct_type| { | 2190 | .struct_type => |t| ty = t.backingIntType(ip).*.toType(), |
| 2239 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | ||
| 2240 | assert(struct_obj.layout == .Packed); | ||
| 2241 | ty = struct_obj.backing_int_ty; | ||
| 2242 | }, | ||
| 2243 | .enum_type => |enum_type| ty = enum_type.tag_ty.toType(), | 2191 | .enum_type => |enum_type| ty = enum_type.tag_ty.toType(), |
| 2244 | .vector_type => |vector_type| ty = vector_type.child.toType(), | 2192 | .vector_type => |vector_type| ty = vector_type.child.toType(), |
| 2245 | 2193 | ||
| ... | @@ -2503,33 +2451,28 @@ pub const Type = struct { | ... | @@ -2503,33 +2451,28 @@ pub const Type = struct { |
| 2503 | .generic_poison => unreachable, | 2451 | .generic_poison => unreachable, |
| 2504 | }, | 2452 | }, |
| 2505 | .struct_type => |struct_type| { | 2453 | .struct_type => |struct_type| { |
| 2506 | if (mod.structPtrUnwrap(struct_type.index)) |s| { | 2454 | assert(struct_type.haveFieldTypes(ip)); |
| 2507 | assert(s.haveFieldTypes()); | 2455 | if (struct_type.knownNonOpv(ip)) |
| 2508 | const field_vals = try mod.gpa.alloc(InternPool.Index, s.fields.count()); | 2456 | return null; |
| 2509 | defer mod.gpa.free(field_vals); | 2457 | const field_vals = try mod.gpa.alloc(InternPool.Index, struct_type.field_types.len); |
| 2510 | for (field_vals, s.fields.values()) |*field_val, field| { | 2458 | defer mod.gpa.free(field_vals); |
| 2511 | if (field.is_comptime) { | 2459 | for (field_vals, 0..) |*field_val, i_usize| { |
| 2512 | field_val.* = field.default_val; | 2460 | const i: u32 = @intCast(i_usize); |
| 2513 | continue; | 2461 | if (struct_type.fieldIsComptime(ip, i)) { |
| 2514 | } | 2462 | field_val.* = struct_type.field_inits.get(ip)[i]; |
| 2515 | if (try field.ty.onePossibleValue(mod)) |field_opv| { | 2463 | continue; |
| 2516 | field_val.* = try field_opv.intern(field.ty, mod); | ||
| 2517 | } else return null; | ||
| 2518 | } | 2464 | } |
| 2519 | 2465 | const field_ty = struct_type.field_types.get(ip)[i].toType(); | |
| 2520 | // In this case the struct has no runtime-known fields and | 2466 | if (try field_ty.onePossibleValue(mod)) |field_opv| { |
| 2521 | // therefore has one possible value. | 2467 | field_val.* = try field_opv.intern(field_ty, mod); |
| 2522 | return (try mod.intern(.{ .aggregate = .{ | 2468 | } else return null; |
| 2523 | .ty = ty.toIntern(), | ||
| 2524 | .storage = .{ .elems = field_vals }, | ||
| 2525 | } })).toValue(); | ||
| 2526 | } | 2469 | } |
| 2527 | 2470 | ||
| 2528 | // In this case the struct has no fields at all and | 2471 | // In this case the struct has no runtime-known fields and |
| 2529 | // therefore has one possible value. | 2472 | // therefore has one possible value. |
| 2530 | return (try mod.intern(.{ .aggregate = .{ | 2473 | return (try mod.intern(.{ .aggregate = .{ |
| 2531 | .ty = ty.toIntern(), | 2474 | .ty = ty.toIntern(), |
| 2532 | .storage = .{ .elems = &.{} }, | 2475 | .storage = .{ .elems = field_vals }, |
| 2533 | } })).toValue(); | 2476 | } })).toValue(); |
| 2534 | }, | 2477 | }, |
| 2535 | 2478 | ||
| ... | @@ -2715,18 +2658,20 @@ pub const Type = struct { | ... | @@ -2715,18 +2658,20 @@ pub const Type = struct { |
| 2715 | => true, | 2658 | => true, |
| 2716 | }, | 2659 | }, |
| 2717 | .struct_type => |struct_type| { | 2660 | .struct_type => |struct_type| { |
| 2661 | // packed structs cannot be comptime-only because they have a well-defined | ||
| 2662 | // memory layout and every field has a well-defined bit pattern. | ||
| 2663 | if (struct_type.layout == .Packed) | ||
| 2664 | return false; | ||
| 2665 | |||
| 2718 | // A struct with no fields is not comptime-only. | 2666 | // A struct with no fields is not comptime-only. |
| 2719 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false; | 2667 | return switch (struct_type.flagsPtr(ip).requires_comptime) { |
| 2720 | switch (struct_obj.requires_comptime) { | 2668 | // Return false to avoid incorrect dependency loops. |
| 2721 | .wip, .unknown => { | 2669 | // This will be handled correctly once merged with |
| 2722 | // Return false to avoid incorrect dependency loops. | 2670 | // `Sema.typeRequiresComptime`. |
| 2723 | // This will be handled correctly once merged with | 2671 | .wip, .unknown => false, |
| 2724 | // `Sema.typeRequiresComptime`. | 2672 | .no => false, |
| 2725 | return false; | 2673 | .yes => true, |
| 2726 | }, | 2674 | }; |
| 2727 | .no => return false, | ||
| 2728 | .yes => return true, | ||
| 2729 | } | ||
| 2730 | }, | 2675 | }, |
| 2731 | 2676 | ||
| 2732 | .anon_struct_type => |tuple| { | 2677 | .anon_struct_type => |tuple| { |
| ... | @@ -2982,37 +2927,19 @@ pub const Type = struct { | ... | @@ -2982,37 +2927,19 @@ pub const Type = struct { |
| 2982 | return enum_type.tagValueIndex(ip, int_tag); | 2927 | return enum_type.tagValueIndex(ip, int_tag); |
| 2983 | } | 2928 | } |
| 2984 | 2929 | ||
| 2985 | pub fn structFields(ty: Type, mod: *Module) Module.Struct.Fields { | ||
| 2986 | switch (mod.intern_pool.indexToKey(ty.toIntern())) { | ||
| 2987 | .struct_type => |struct_type| { | ||
| 2988 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return .{}; | ||
| 2989 | assert(struct_obj.haveFieldTypes()); | ||
| 2990 | return struct_obj.fields; | ||
| 2991 | }, | ||
| 2992 | else => unreachable, | ||
| 2993 | } | ||
| 2994 | } | ||
| 2995 | |||
| 2996 | pub fn structFieldName(ty: Type, field_index: usize, mod: *Module) InternPool.NullTerminatedString { | 2930 | pub fn structFieldName(ty: Type, field_index: usize, mod: *Module) InternPool.NullTerminatedString { |
| 2997 | const ip = &mod.intern_pool; | 2931 | const ip = &mod.intern_pool; |
| 2998 | return switch (ip.indexToKey(ty.toIntern())) { | 2932 | return switch (ip.indexToKey(ty.toIntern())) { |
| 2999 | .struct_type => |struct_type| { | 2933 | .struct_type => |struct_type| struct_type.field_names.get(ip)[field_index], |
| 3000 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | ||
| 3001 | assert(struct_obj.haveFieldTypes()); | ||
| 3002 | return struct_obj.fields.keys()[field_index]; | ||
| 3003 | }, | ||
| 3004 | .anon_struct_type => |anon_struct| anon_struct.names.get(ip)[field_index], | 2934 | .anon_struct_type => |anon_struct| anon_struct.names.get(ip)[field_index], |
| 3005 | else => unreachable, | 2935 | else => unreachable, |
| 3006 | }; | 2936 | }; |
| 3007 | } | 2937 | } |
| 3008 | 2938 | ||
| 3009 | pub fn structFieldCount(ty: Type, mod: *Module) usize { | 2939 | pub fn structFieldCount(ty: Type, mod: *Module) usize { |
| 3010 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | 2940 | const ip = &mod.intern_pool; |
| 3011 | .struct_type => |struct_type| { | 2941 | return switch (ip.indexToKey(ty.toIntern())) { |
| 3012 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return 0; | 2942 | .struct_type => |struct_type| struct_type.field_types.len, |
| 3013 | assert(struct_obj.haveFieldTypes()); | ||
| 3014 | return struct_obj.fields.count(); | ||
| 3015 | }, | ||
| 3016 | .anon_struct_type => |anon_struct| anon_struct.types.len, | 2943 | .anon_struct_type => |anon_struct| anon_struct.types.len, |
| 3017 | else => unreachable, | 2944 | else => unreachable, |
| 3018 | }; | 2945 | }; |
| ... | @@ -3022,11 +2949,7 @@ pub const Type = struct { | ... | @@ -3022,11 +2949,7 @@ pub const Type = struct { |
| 3022 | pub fn structFieldType(ty: Type, index: usize, mod: *Module) Type { | 2949 | pub fn structFieldType(ty: Type, index: usize, mod: *Module) Type { |
| 3023 | const ip = &mod.intern_pool; | 2950 | const ip = &mod.intern_pool; |
| 3024 | return switch (ip.indexToKey(ty.toIntern())) { | 2951 | return switch (ip.indexToKey(ty.toIntern())) { |
| 3025 | .struct_type => |struct_type| { | 2952 | .struct_type => |struct_type| struct_type.field_types.get(ip)[index].toType(), |
| 3026 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | ||
| 3027 | assert(struct_obj.haveFieldTypes()); | ||
| 3028 | return struct_obj.fields.values()[index].ty; | ||
| 3029 | }, | ||
| 3030 | .union_type => |union_type| { | 2953 | .union_type => |union_type| { |
| 3031 | const union_obj = ip.loadUnionType(union_type); | 2954 | const union_obj = ip.loadUnionType(union_type); |
| 3032 | return union_obj.field_types.get(ip)[index].toType(); | 2955 | return union_obj.field_types.get(ip)[index].toType(); |
| ... | @@ -3036,13 +2959,14 @@ pub const Type = struct { | ... | @@ -3036,13 +2959,14 @@ pub const Type = struct { |
| 3036 | }; | 2959 | }; |
| 3037 | } | 2960 | } |
| 3038 | 2961 | ||
| 3039 | pub fn structFieldAlign(ty: Type, index: usize, mod: *Module) u32 { | 2962 | pub fn structFieldAlign(ty: Type, index: usize, mod: *Module) Alignment { |
| 3040 | const ip = &mod.intern_pool; | 2963 | const ip = &mod.intern_pool; |
| 3041 | switch (ip.indexToKey(ty.toIntern())) { | 2964 | switch (ip.indexToKey(ty.toIntern())) { |
| 3042 | .struct_type => |struct_type| { | 2965 | .struct_type => |struct_type| { |
| 3043 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | 2966 | assert(struct_type.layout != .Packed); |
| 3044 | assert(struct_obj.layout != .Packed); | 2967 | const explicit_align = struct_type.field_aligns.get(ip)[index]; |
| 3045 | return struct_obj.fields.values()[index].alignment(mod, struct_obj.layout); | 2968 | const field_ty = struct_type.field_types.get(ip)[index].toType(); |
| 2969 | return mod.structFieldAlignment(explicit_align, field_ty, struct_type.layout); | ||
| 3046 | }, | 2970 | }, |
| 3047 | .anon_struct_type => |anon_struct| { | 2971 | .anon_struct_type => |anon_struct| { |
| 3048 | return anon_struct.types.get(ip)[index].toType().abiAlignment(mod); | 2972 | return anon_struct.types.get(ip)[index].toType().abiAlignment(mod); |
| ... | @@ -3059,8 +2983,7 @@ pub const Type = struct { | ... | @@ -3059,8 +2983,7 @@ pub const Type = struct { |
| 3059 | const ip = &mod.intern_pool; | 2983 | const ip = &mod.intern_pool; |
| 3060 | switch (ip.indexToKey(ty.toIntern())) { | 2984 | switch (ip.indexToKey(ty.toIntern())) { |
| 3061 | .struct_type => |struct_type| { | 2985 | .struct_type => |struct_type| { |
| 3062 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | 2986 | const val = struct_type.field_inits.get(ip)[index]; |
| 3063 | const val = struct_obj.fields.values()[index].default_val; | ||
| 3064 | // TODO: avoid using `unreachable` to indicate this. | 2987 | // TODO: avoid using `unreachable` to indicate this. |
| 3065 | if (val == .none) return Value.@"unreachable"; | 2988 | if (val == .none) return Value.@"unreachable"; |
| 3066 | return val.toValue(); | 2989 | return val.toValue(); |
| ... | @@ -3079,12 +3002,10 @@ pub const Type = struct { | ... | @@ -3079,12 +3002,10 @@ pub const Type = struct { |
| 3079 | const ip = &mod.intern_pool; | 3002 | const ip = &mod.intern_pool; |
| 3080 | switch (ip.indexToKey(ty.toIntern())) { | 3003 | switch (ip.indexToKey(ty.toIntern())) { |
| 3081 | .struct_type => |struct_type| { | 3004 | .struct_type => |struct_type| { |
| 3082 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | 3005 | if (struct_type.comptime_bits.getBit(ip, index)) { |
| 3083 | const field = struct_obj.fields.values()[index]; | 3006 | return struct_type.field_inits.get(ip)[index].toValue(); |
| 3084 | if (field.is_comptime) { | ||
| 3085 | return field.default_val.toValue(); | ||
| 3086 | } else { | 3007 | } else { |
| 3087 | return field.ty.onePossibleValue(mod); | 3008 | return struct_type.field_types.get(ip)[index].toType().onePossibleValue(mod); |
| 3088 | } | 3009 | } |
| 3089 | }, | 3010 | }, |
| 3090 | .anon_struct_type => |tuple| { | 3011 | .anon_struct_type => |tuple| { |
| ... | @@ -3102,30 +3023,25 @@ pub const Type = struct { | ... | @@ -3102,30 +3023,25 @@ pub const Type = struct { |
| 3102 | pub fn structFieldIsComptime(ty: Type, index: usize, mod: *Module) bool { | 3023 | pub fn structFieldIsComptime(ty: Type, index: usize, mod: *Module) bool { |
| 3103 | const ip = &mod.intern_pool; | 3024 | const ip = &mod.intern_pool; |
| 3104 | return switch (ip.indexToKey(ty.toIntern())) { | 3025 | return switch (ip.indexToKey(ty.toIntern())) { |
| 3105 | .struct_type => |struct_type| { | 3026 | .struct_type => |struct_type| struct_type.fieldIsComptime(ip, index), |
| 3106 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | ||
| 3107 | if (struct_obj.layout == .Packed) return false; | ||
| 3108 | const field = struct_obj.fields.values()[index]; | ||
| 3109 | return field.is_comptime; | ||
| 3110 | }, | ||
| 3111 | .anon_struct_type => |anon_struct| anon_struct.values.get(ip)[index] != .none, | 3027 | .anon_struct_type => |anon_struct| anon_struct.values.get(ip)[index] != .none, |
| 3112 | else => unreachable, | 3028 | else => unreachable, |
| 3113 | }; | 3029 | }; |
| 3114 | } | 3030 | } |
| 3115 | 3031 | ||
| 3116 | pub fn packedStructFieldByteOffset(ty: Type, field_index: usize, mod: *Module) u32 { | 3032 | pub fn packedStructFieldByteOffset(ty: Type, field_index: usize, mod: *Module) u32 { |
| 3117 | const struct_type = mod.intern_pool.indexToKey(ty.toIntern()).struct_type; | 3033 | const ip = &mod.intern_pool; |
| 3118 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | 3034 | const struct_type = ip.indexToKey(ty.toIntern()).struct_type; |
| 3119 | assert(struct_obj.layout == .Packed); | 3035 | assert(struct_type.layout == .Packed); |
| 3120 | comptime assert(Type.packed_struct_layout_version == 2); | 3036 | comptime assert(Type.packed_struct_layout_version == 2); |
| 3121 | 3037 | ||
| 3122 | var bit_offset: u16 = undefined; | 3038 | var bit_offset: u16 = undefined; |
| 3123 | var elem_size_bits: u16 = undefined; | 3039 | var elem_size_bits: u16 = undefined; |
| 3124 | var running_bits: u16 = 0; | 3040 | var running_bits: u16 = 0; |
| 3125 | for (struct_obj.fields.values(), 0..) |f, i| { | 3041 | for (struct_type.field_types.get(ip), 0..) |field_ty, i| { |
| 3126 | if (!f.ty.hasRuntimeBits(mod)) continue; | 3042 | if (!field_ty.toType().hasRuntimeBits(mod)) continue; |
| 3127 | 3043 | ||
| 3128 | const field_bits = @as(u16, @intCast(f.ty.bitSize(mod))); | 3044 | const field_bits: u16 = @intCast(field_ty.toType().bitSize(mod)); |
| 3129 | if (i == field_index) { | 3045 | if (i == field_index) { |
| 3130 | bit_offset = running_bits; | 3046 | bit_offset = running_bits; |
| 3131 | elem_size_bits = field_bits; | 3047 | elem_size_bits = field_bits; |
| ... | @@ -3141,68 +3057,19 @@ pub const Type = struct { | ... | @@ -3141,68 +3057,19 @@ pub const Type = struct { |
| 3141 | offset: u64, | 3057 | offset: u64, |
| 3142 | }; | 3058 | }; |
| 3143 | 3059 | ||
| 3144 | pub const StructOffsetIterator = struct { | ||
| 3145 | field: usize = 0, | ||
| 3146 | offset: u64 = 0, | ||
| 3147 | big_align: u32 = 0, | ||
| 3148 | struct_obj: *Module.Struct, | ||
| 3149 | module: *Module, | ||
| 3150 | |||
| 3151 | pub fn next(it: *StructOffsetIterator) ?FieldOffset { | ||
| 3152 | const mod = it.module; | ||
| 3153 | var i = it.field; | ||
| 3154 | if (it.struct_obj.fields.count() <= i) | ||
| 3155 | return null; | ||
| 3156 | |||
| 3157 | if (it.struct_obj.optimized_order) |some| { | ||
| 3158 | i = some[i]; | ||
| 3159 | if (i == Module.Struct.omitted_field) return null; | ||
| 3160 | } | ||
| 3161 | const field = it.struct_obj.fields.values()[i]; | ||
| 3162 | it.field += 1; | ||
| 3163 | |||
| 3164 | if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) { | ||
| 3165 | return FieldOffset{ .field = i, .offset = it.offset }; | ||
| 3166 | } | ||
| 3167 | |||
| 3168 | const field_align = field.alignment(mod, it.struct_obj.layout); | ||
| 3169 | it.big_align = @max(it.big_align, field_align); | ||
| 3170 | const field_offset = std.mem.alignForward(u64, it.offset, field_align); | ||
| 3171 | it.offset = field_offset + field.ty.abiSize(mod); | ||
| 3172 | return FieldOffset{ .field = i, .offset = field_offset }; | ||
| 3173 | } | ||
| 3174 | }; | ||
| 3175 | |||
| 3176 | /// Get an iterator that iterates over all the struct field, returning the field and | ||
| 3177 | /// offset of that field. Asserts that the type is a non-packed struct. | ||
| 3178 | pub fn iterateStructOffsets(ty: Type, mod: *Module) StructOffsetIterator { | ||
| 3179 | const struct_type = mod.intern_pool.indexToKey(ty.toIntern()).struct_type; | ||
| 3180 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | ||
| 3181 | assert(struct_obj.haveLayout()); | ||
| 3182 | assert(struct_obj.layout != .Packed); | ||
| 3183 | return .{ .struct_obj = struct_obj, .module = mod }; | ||
| 3184 | } | ||
| 3185 | |||
| 3186 | /// Supports structs and unions. | 3060 | /// Supports structs and unions. |
| 3187 | pub fn structFieldOffset(ty: Type, index: usize, mod: *Module) u64 { | 3061 | pub fn structFieldOffset(ty: Type, index: usize, mod: *Module) u64 { |
| 3188 | const ip = &mod.intern_pool; | 3062 | const ip = &mod.intern_pool; |
| 3189 | switch (ip.indexToKey(ty.toIntern())) { | 3063 | switch (ip.indexToKey(ty.toIntern())) { |
| 3190 | .struct_type => |struct_type| { | 3064 | .struct_type => |struct_type| { |
| 3191 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | 3065 | assert(struct_type.haveLayout(ip)); |
| 3192 | assert(struct_obj.haveLayout()); | 3066 | assert(struct_type.layout != .Packed); |
| 3193 | assert(struct_obj.layout != .Packed); | 3067 | return struct_type.offsets.get(ip)[index]; |
| 3194 | var it = ty.iterateStructOffsets(mod); | ||
| 3195 | while (it.next()) |field_offset| { | ||
| 3196 | if (index == field_offset.field) | ||
| 3197 | return field_offset.offset; | ||
| 3198 | } | ||
| 3199 | |||
| 3200 | return std.mem.alignForward(u64, it.offset, @max(it.big_align, 1)); | ||
| 3201 | }, | 3068 | }, |
| 3202 | 3069 | ||
| 3203 | .anon_struct_type => |tuple| { | 3070 | .anon_struct_type => |tuple| { |
| 3204 | var offset: u64 = 0; | 3071 | var offset: u64 = 0; |
| 3205 | var big_align: u32 = 0; | 3072 | var big_align: Alignment = .none; |
| 3206 | 3073 | ||
| 3207 | for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, field_val, i| { | 3074 | for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, field_val, i| { |
| 3208 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) { | 3075 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) { |
| ... | @@ -3212,12 +3079,12 @@ pub const Type = struct { | ... | @@ -3212,12 +3079,12 @@ pub const Type = struct { |
| 3212 | } | 3079 | } |
| 3213 | 3080 | ||
| 3214 | const field_align = field_ty.toType().abiAlignment(mod); | 3081 | const field_align = field_ty.toType().abiAlignment(mod); |
| 3215 | big_align = @max(big_align, field_align); | 3082 | big_align = big_align.max(field_align); |
| 3216 | offset = std.mem.alignForward(u64, offset, field_align); | 3083 | offset = field_align.forward(offset); |
| 3217 | if (i == index) return offset; | 3084 | if (i == index) return offset; |
| 3218 | offset += field_ty.toType().abiSize(mod); | 3085 | offset += field_ty.toType().abiSize(mod); |
| 3219 | } | 3086 | } |
| 3220 | offset = std.mem.alignForward(u64, offset, @max(big_align, 1)); | 3087 | offset = big_align.max(.@"1").forward(offset); |
| 3221 | return offset; | 3088 | return offset; |
| 3222 | }, | 3089 | }, |
| 3223 | 3090 | ||
| ... | @@ -3226,9 +3093,9 @@ pub const Type = struct { | ... | @@ -3226,9 +3093,9 @@ pub const Type = struct { |
| 3226 | return 0; | 3093 | return 0; |
| 3227 | const union_obj = ip.loadUnionType(union_type); | 3094 | const union_obj = ip.loadUnionType(union_type); |
| 3228 | const layout = mod.getUnionLayout(union_obj); | 3095 | const layout = mod.getUnionLayout(union_obj); |
| 3229 | if (layout.tag_align >= layout.payload_align) { | 3096 | if (layout.tag_align.compare(.gte, layout.payload_align)) { |
| 3230 | // {Tag, Payload} | 3097 | // {Tag, Payload} |
| 3231 | return std.mem.alignForward(u64, layout.tag_size, layout.payload_align); | 3098 | return layout.payload_align.forward(layout.tag_size); |
| 3232 | } else { | 3099 | } else { |
| 3233 | // {Payload, Tag} | 3100 | // {Payload, Tag} |
| 3234 | return 0; | 3101 | return 0; |
| ... | @@ -3246,8 +3113,7 @@ pub const Type = struct { | ... | @@ -3246,8 +3113,7 @@ pub const Type = struct { |
| 3246 | pub fn declSrcLocOrNull(ty: Type, mod: *Module) ?Module.SrcLoc { | 3113 | pub fn declSrcLocOrNull(ty: Type, mod: *Module) ?Module.SrcLoc { |
| 3247 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | 3114 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 3248 | .struct_type => |struct_type| { | 3115 | .struct_type => |struct_type| { |
| 3249 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | 3116 | return mod.declPtr(struct_type.decl.unwrap() orelse return null).srcLoc(mod); |
| 3250 | return struct_obj.srcLoc(mod); | ||
| 3251 | }, | 3117 | }, |
| 3252 | .union_type => |union_type| { | 3118 | .union_type => |union_type| { |
| 3253 | return mod.declPtr(union_type.decl).srcLoc(mod); | 3119 | return mod.declPtr(union_type.decl).srcLoc(mod); |
| ... | @@ -3264,10 +3130,7 @@ pub const Type = struct { | ... | @@ -3264,10 +3130,7 @@ pub const Type = struct { |
| 3264 | 3130 | ||
| 3265 | pub fn getOwnerDeclOrNull(ty: Type, mod: *Module) ?Module.Decl.Index { | 3131 | pub fn getOwnerDeclOrNull(ty: Type, mod: *Module) ?Module.Decl.Index { |
| 3266 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | 3132 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 3267 | .struct_type => |struct_type| { | 3133 | .struct_type => |struct_type| struct_type.decl.unwrap(), |
| 3268 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return null; | ||
| 3269 | return struct_obj.owner_decl; | ||
| 3270 | }, | ||
| 3271 | .union_type => |union_type| union_type.decl, | 3134 | .union_type => |union_type| union_type.decl, |
| 3272 | .opaque_type => |opaque_type| opaque_type.decl, | 3135 | .opaque_type => |opaque_type| opaque_type.decl, |
| 3273 | .enum_type => |enum_type| enum_type.decl, | 3136 | .enum_type => |enum_type| enum_type.decl, |
| ... | @@ -3280,10 +3143,12 @@ pub const Type = struct { | ... | @@ -3280,10 +3143,12 @@ pub const Type = struct { |
| 3280 | } | 3143 | } |
| 3281 | 3144 | ||
| 3282 | pub fn isTuple(ty: Type, mod: *Module) bool { | 3145 | pub fn isTuple(ty: Type, mod: *Module) bool { |
| 3283 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | 3146 | const ip = &mod.intern_pool; |
| 3147 | return switch (ip.indexToKey(ty.toIntern())) { | ||
| 3284 | .struct_type => |struct_type| { | 3148 | .struct_type => |struct_type| { |
| 3285 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false; | 3149 | if (struct_type.layout == .Packed) return false; |
| 3286 | return struct_obj.is_tuple; | 3150 | if (struct_type.decl == .none) return false; |
| 3151 | return struct_type.flagsPtr(ip).is_tuple; | ||
| 3287 | }, | 3152 | }, |
| 3288 | .anon_struct_type => |anon_struct| anon_struct.names.len == 0, | 3153 | .anon_struct_type => |anon_struct| anon_struct.names.len == 0, |
| 3289 | else => false, | 3154 | else => false, |
| ... | @@ -3299,10 +3164,12 @@ pub const Type = struct { | ... | @@ -3299,10 +3164,12 @@ pub const Type = struct { |
| 3299 | } | 3164 | } |
| 3300 | 3165 | ||
| 3301 | pub fn isTupleOrAnonStruct(ty: Type, mod: *Module) bool { | 3166 | pub fn isTupleOrAnonStruct(ty: Type, mod: *Module) bool { |
| 3302 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | 3167 | const ip = &mod.intern_pool; |
| 3168 | return switch (ip.indexToKey(ty.toIntern())) { | ||
| 3303 | .struct_type => |struct_type| { | 3169 | .struct_type => |struct_type| { |
| 3304 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false; | 3170 | if (struct_type.layout == .Packed) return false; |
| 3305 | return struct_obj.is_tuple; | 3171 | if (struct_type.decl == .none) return false; |
| 3172 | return struct_type.flagsPtr(ip).is_tuple; | ||
| 3306 | }, | 3173 | }, |
| 3307 | .anon_struct_type => true, | 3174 | .anon_struct_type => true, |
| 3308 | else => false, | 3175 | else => false, |
| ... | @@ -3391,3 +3258,7 @@ pub const Type = struct { | ... | @@ -3391,3 +3258,7 @@ pub const Type = struct { |
| 3391 | /// to packed struct layout to find out all the places in the codebase you need to edit! | 3258 | /// to packed struct layout to find out all the places in the codebase you need to edit! |
| 3392 | pub const packed_struct_layout_version = 2; | 3259 | pub const packed_struct_layout_version = 2; |
| 3393 | }; | 3260 | }; |
| 3261 | |||
| 3262 | fn cTypeAlign(target: Target, c_type: Target.CType) Alignment { | ||
| 3263 | return Alignment.fromByteUnits(target.c_type_alignment(c_type)); | ||
| 3264 | } |
src/value.zig+112-102| ... | @@ -462,7 +462,7 @@ pub const Value = struct { | ... | @@ -462,7 +462,7 @@ pub const Value = struct { |
| 462 | if (opt_sema) |sema| try sema.resolveTypeLayout(ty.toType()); | 462 | if (opt_sema) |sema| try sema.resolveTypeLayout(ty.toType()); |
| 463 | const x = switch (int.storage) { | 463 | const x = switch (int.storage) { |
| 464 | else => unreachable, | 464 | else => unreachable, |
| 465 | .lazy_align => ty.toType().abiAlignment(mod), | 465 | .lazy_align => ty.toType().abiAlignment(mod).toByteUnits(0), |
| 466 | .lazy_size => ty.toType().abiSize(mod), | 466 | .lazy_size => ty.toType().abiSize(mod), |
| 467 | }; | 467 | }; |
| 468 | return BigIntMutable.init(&space.limbs, x).toConst(); | 468 | return BigIntMutable.init(&space.limbs, x).toConst(); |
| ... | @@ -523,9 +523,9 @@ pub const Value = struct { | ... | @@ -523,9 +523,9 @@ pub const Value = struct { |
| 523 | .u64 => |x| x, | 523 | .u64 => |x| x, |
| 524 | .i64 => |x| std.math.cast(u64, x), | 524 | .i64 => |x| std.math.cast(u64, x), |
| 525 | .lazy_align => |ty| if (opt_sema) |sema| | 525 | .lazy_align => |ty| if (opt_sema) |sema| |
| 526 | (try ty.toType().abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar | 526 | (try ty.toType().abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar.toByteUnits(0) |
| 527 | else | 527 | else |
| 528 | ty.toType().abiAlignment(mod), | 528 | ty.toType().abiAlignment(mod).toByteUnits(0), |
| 529 | .lazy_size => |ty| if (opt_sema) |sema| | 529 | .lazy_size => |ty| if (opt_sema) |sema| |
| 530 | (try ty.toType().abiSizeAdvanced(mod, .{ .sema = sema })).scalar | 530 | (try ty.toType().abiSizeAdvanced(mod, .{ .sema = sema })).scalar |
| 531 | else | 531 | else |
| ... | @@ -569,9 +569,9 @@ pub const Value = struct { | ... | @@ -569,9 +569,9 @@ pub const Value = struct { |
| 569 | .int => |int| switch (int.storage) { | 569 | .int => |int| switch (int.storage) { |
| 570 | .big_int => |big_int| big_int.to(i64) catch unreachable, | 570 | .big_int => |big_int| big_int.to(i64) catch unreachable, |
| 571 | .i64 => |x| x, | 571 | .i64 => |x| x, |
| 572 | .u64 => |x| @as(i64, @intCast(x)), | 572 | .u64 => |x| @intCast(x), |
| 573 | .lazy_align => |ty| @as(i64, @intCast(ty.toType().abiAlignment(mod))), | 573 | .lazy_align => |ty| @intCast(ty.toType().abiAlignment(mod).toByteUnits(0)), |
| 574 | .lazy_size => |ty| @as(i64, @intCast(ty.toType().abiSize(mod))), | 574 | .lazy_size => |ty| @intCast(ty.toType().abiSize(mod)), |
| 575 | }, | 575 | }, |
| 576 | else => unreachable, | 576 | else => unreachable, |
| 577 | }, | 577 | }, |
| ... | @@ -612,10 +612,11 @@ pub const Value = struct { | ... | @@ -612,10 +612,11 @@ pub const Value = struct { |
| 612 | const target = mod.getTarget(); | 612 | const target = mod.getTarget(); |
| 613 | const endian = target.cpu.arch.endian(); | 613 | const endian = target.cpu.arch.endian(); |
| 614 | if (val.isUndef(mod)) { | 614 | if (val.isUndef(mod)) { |
| 615 | const size = @as(usize, @intCast(ty.abiSize(mod))); | 615 | const size: usize = @intCast(ty.abiSize(mod)); |
| 616 | @memset(buffer[0..size], 0xaa); | 616 | @memset(buffer[0..size], 0xaa); |
| 617 | return; | 617 | return; |
| 618 | } | 618 | } |
| 619 | const ip = &mod.intern_pool; | ||
| 619 | switch (ty.zigTypeTag(mod)) { | 620 | switch (ty.zigTypeTag(mod)) { |
| 620 | .Void => {}, | 621 | .Void => {}, |
| 621 | .Bool => { | 622 | .Bool => { |
| ... | @@ -656,40 +657,44 @@ pub const Value = struct { | ... | @@ -656,40 +657,44 @@ pub const Value = struct { |
| 656 | const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; | 657 | const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; |
| 657 | return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0); | 658 | return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0); |
| 658 | }, | 659 | }, |
| 659 | .Struct => switch (ty.containerLayout(mod)) { | 660 | .Struct => { |
| 660 | .Auto => return error.IllDefinedMemoryLayout, | 661 | const struct_type = mod.typeToStruct(ty) orelse return error.IllDefinedMemoryLayout; |
| 661 | .Extern => for (ty.structFields(mod).values(), 0..) |field, i| { | 662 | switch (struct_type.layout) { |
| 662 | const off = @as(usize, @intCast(ty.structFieldOffset(i, mod))); | 663 | .Auto => return error.IllDefinedMemoryLayout, |
| 663 | const field_val = switch (val.ip_index) { | 664 | .Extern => for (0..struct_type.field_types.len) |i| { |
| 664 | .none => switch (val.tag()) { | 665 | const off: usize = @intCast(ty.structFieldOffset(i, mod)); |
| 665 | .bytes => { | 666 | const field_val = switch (val.ip_index) { |
| 666 | buffer[off] = val.castTag(.bytes).?.data[i]; | 667 | .none => switch (val.tag()) { |
| 667 | continue; | 668 | .bytes => { |
| 668 | }, | 669 | buffer[off] = val.castTag(.bytes).?.data[i]; |
| 669 | .aggregate => val.castTag(.aggregate).?.data[i], | 670 | continue; |
| 670 | .repeated => val.castTag(.repeated).?.data, | 671 | }, |
| 671 | else => unreachable, | 672 | .aggregate => val.castTag(.aggregate).?.data[i], |
| 672 | }, | 673 | .repeated => val.castTag(.repeated).?.data, |
| 673 | else => switch (mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage) { | 674 | else => unreachable, |
| 674 | .bytes => |bytes| { | ||
| 675 | buffer[off] = bytes[i]; | ||
| 676 | continue; | ||
| 677 | }, | 675 | }, |
| 678 | .elems => |elems| elems[i], | 676 | else => switch (ip.indexToKey(val.toIntern()).aggregate.storage) { |
| 679 | .repeated_elem => |elem| elem, | 677 | .bytes => |bytes| { |
| 680 | }.toValue(), | 678 | buffer[off] = bytes[i]; |
| 681 | }; | 679 | continue; |
| 682 | try writeToMemory(field_val, field.ty, mod, buffer[off..]); | 680 | }, |
| 683 | }, | 681 | .elems => |elems| elems[i], |
| 684 | .Packed => { | 682 | .repeated_elem => |elem| elem, |
| 685 | const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; | 683 | }.toValue(), |
| 686 | return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0); | 684 | }; |
| 687 | }, | 685 | const field_ty = struct_type.field_types.get(ip)[i].toType(); |
| 686 | try writeToMemory(field_val, field_ty, mod, buffer[off..]); | ||
| 687 | }, | ||
| 688 | .Packed => { | ||
| 689 | const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; | ||
| 690 | return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0); | ||
| 691 | }, | ||
| 692 | } | ||
| 688 | }, | 693 | }, |
| 689 | .ErrorSet => { | 694 | .ErrorSet => { |
| 690 | // TODO revisit this when we have the concept of the error tag type | 695 | // TODO revisit this when we have the concept of the error tag type |
| 691 | const Int = u16; | 696 | const Int = u16; |
| 692 | const name = switch (mod.intern_pool.indexToKey(val.toIntern())) { | 697 | const name = switch (ip.indexToKey(val.toIntern())) { |
| 693 | .err => |err| err.name, | 698 | .err => |err| err.name, |
| 694 | .error_union => |error_union| error_union.val.err_name, | 699 | .error_union => |error_union| error_union.val.err_name, |
| 695 | else => unreachable, | 700 | else => unreachable, |
| ... | @@ -790,24 +795,24 @@ pub const Value = struct { | ... | @@ -790,24 +795,24 @@ pub const Value = struct { |
| 790 | bits += elem_bit_size; | 795 | bits += elem_bit_size; |
| 791 | } | 796 | } |
| 792 | }, | 797 | }, |
| 793 | .Struct => switch (ty.containerLayout(mod)) { | 798 | .Struct => { |
| 794 | .Auto => unreachable, // Sema is supposed to have emitted a compile error already | 799 | const struct_type = ip.indexToKey(ty.toIntern()).struct_type; |
| 795 | .Extern => unreachable, // Handled in non-packed writeToMemory | 800 | // Sema is supposed to have emitted a compile error already in the case of Auto, |
| 796 | .Packed => { | 801 | // and Extern is handled in non-packed writeToMemory. |
| 797 | var bits: u16 = 0; | 802 | assert(struct_type.layout == .Packed); |
| 798 | const fields = ty.structFields(mod).values(); | 803 | var bits: u16 = 0; |
| 799 | const storage = ip.indexToKey(val.toIntern()).aggregate.storage; | 804 | const storage = ip.indexToKey(val.toIntern()).aggregate.storage; |
| 800 | for (fields, 0..) |field, i| { | 805 | for (0..struct_type.field_types.len) |i| { |
| 801 | const field_bits = @as(u16, @intCast(field.ty.bitSize(mod))); | 806 | const field_ty = struct_type.field_types.get(ip)[i].toType(); |
| 802 | const field_val = switch (storage) { | 807 | const field_bits: u16 = @intCast(field_ty.bitSize(mod)); |
| 803 | .bytes => unreachable, | 808 | const field_val = switch (storage) { |
| 804 | .elems => |elems| elems[i], | 809 | .bytes => unreachable, |
| 805 | .repeated_elem => |elem| elem, | 810 | .elems => |elems| elems[i], |
| 806 | }; | 811 | .repeated_elem => |elem| elem, |
| 807 | try field_val.toValue().writeToPackedMemory(field.ty, mod, buffer, bit_offset + bits); | 812 | }; |
| 808 | bits += field_bits; | 813 | try field_val.toValue().writeToPackedMemory(field_ty, mod, buffer, bit_offset + bits); |
| 809 | } | 814 | bits += field_bits; |
| 810 | }, | 815 | } |
| 811 | }, | 816 | }, |
| 812 | .Union => { | 817 | .Union => { |
| 813 | const union_obj = mod.typeToUnion(ty).?; | 818 | const union_obj = mod.typeToUnion(ty).?; |
| ... | @@ -852,6 +857,7 @@ pub const Value = struct { | ... | @@ -852,6 +857,7 @@ pub const Value = struct { |
| 852 | buffer: []const u8, | 857 | buffer: []const u8, |
| 853 | arena: Allocator, | 858 | arena: Allocator, |
| 854 | ) Allocator.Error!Value { | 859 | ) Allocator.Error!Value { |
| 860 | const ip = &mod.intern_pool; | ||
| 855 | const target = mod.getTarget(); | 861 | const target = mod.getTarget(); |
| 856 | const endian = target.cpu.arch.endian(); | 862 | const endian = target.cpu.arch.endian(); |
| 857 | switch (ty.zigTypeTag(mod)) { | 863 | switch (ty.zigTypeTag(mod)) { |
| ... | @@ -926,25 +932,29 @@ pub const Value = struct { | ... | @@ -926,25 +932,29 @@ pub const Value = struct { |
| 926 | const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; | 932 | const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; |
| 927 | return readFromPackedMemory(ty, mod, buffer[0..byte_count], 0, arena); | 933 | return readFromPackedMemory(ty, mod, buffer[0..byte_count], 0, arena); |
| 928 | }, | 934 | }, |
| 929 | .Struct => switch (ty.containerLayout(mod)) { | 935 | .Struct => { |
| 930 | .Auto => unreachable, // Sema is supposed to have emitted a compile error already | 936 | const struct_type = mod.typeToStruct(ty).?; |
| 931 | .Extern => { | 937 | switch (struct_type.layout) { |
| 932 | const fields = ty.structFields(mod).values(); | 938 | .Auto => unreachable, // Sema is supposed to have emitted a compile error already |
| 933 | const field_vals = try arena.alloc(InternPool.Index, fields.len); | 939 | .Extern => { |
| 934 | for (field_vals, fields, 0..) |*field_val, field, i| { | 940 | const field_types = struct_type.field_types; |
| 935 | const off = @as(usize, @intCast(ty.structFieldOffset(i, mod))); | 941 | const field_vals = try arena.alloc(InternPool.Index, field_types.len); |
| 936 | const sz = @as(usize, @intCast(field.ty.abiSize(mod))); | 942 | for (field_vals, 0..) |*field_val, i| { |
| 937 | field_val.* = try (try readFromMemory(field.ty, mod, buffer[off..(off + sz)], arena)).intern(field.ty, mod); | 943 | const field_ty = field_types.get(ip)[i].toType(); |
| 938 | } | 944 | const off: usize = @intCast(ty.structFieldOffset(i, mod)); |
| 939 | return (try mod.intern(.{ .aggregate = .{ | 945 | const sz: usize = @intCast(field_ty.abiSize(mod)); |
| 940 | .ty = ty.toIntern(), | 946 | field_val.* = try (try readFromMemory(field_ty, mod, buffer[off..(off + sz)], arena)).intern(field_ty, mod); |
| 941 | .storage = .{ .elems = field_vals }, | 947 | } |
| 942 | } })).toValue(); | 948 | return (try mod.intern(.{ .aggregate = .{ |
| 943 | }, | 949 | .ty = ty.toIntern(), |
| 944 | .Packed => { | 950 | .storage = .{ .elems = field_vals }, |
| 945 | const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; | 951 | } })).toValue(); |
| 946 | return readFromPackedMemory(ty, mod, buffer[0..byte_count], 0, arena); | 952 | }, |
| 947 | }, | 953 | .Packed => { |
| 954 | const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; | ||
| 955 | return readFromPackedMemory(ty, mod, buffer[0..byte_count], 0, arena); | ||
| 956 | }, | ||
| 957 | } | ||
| 948 | }, | 958 | }, |
| 949 | .ErrorSet => { | 959 | .ErrorSet => { |
| 950 | // TODO revisit this when we have the concept of the error tag type | 960 | // TODO revisit this when we have the concept of the error tag type |
| ... | @@ -992,6 +1002,7 @@ pub const Value = struct { | ... | @@ -992,6 +1002,7 @@ pub const Value = struct { |
| 992 | bit_offset: usize, | 1002 | bit_offset: usize, |
| 993 | arena: Allocator, | 1003 | arena: Allocator, |
| 994 | ) Allocator.Error!Value { | 1004 | ) Allocator.Error!Value { |
| 1005 | const ip = &mod.intern_pool; | ||
| 995 | const target = mod.getTarget(); | 1006 | const target = mod.getTarget(); |
| 996 | const endian = target.cpu.arch.endian(); | 1007 | const endian = target.cpu.arch.endian(); |
| 997 | switch (ty.zigTypeTag(mod)) { | 1008 | switch (ty.zigTypeTag(mod)) { |
| ... | @@ -1070,23 +1081,22 @@ pub const Value = struct { | ... | @@ -1070,23 +1081,22 @@ pub const Value = struct { |
| 1070 | .storage = .{ .elems = elems }, | 1081 | .storage = .{ .elems = elems }, |
| 1071 | } })).toValue(); | 1082 | } })).toValue(); |
| 1072 | }, | 1083 | }, |
| 1073 | .Struct => switch (ty.containerLayout(mod)) { | 1084 | .Struct => { |
| 1074 | .Auto => unreachable, // Sema is supposed to have emitted a compile error already | 1085 | // Sema is supposed to have emitted a compile error already for Auto layout structs, |
| 1075 | .Extern => unreachable, // Handled by non-packed readFromMemory | 1086 | // and Extern is handled by non-packed readFromMemory. |
| 1076 | .Packed => { | 1087 | const struct_type = mod.typeToPackedStruct(ty).?; |
| 1077 | var bits: u16 = 0; | 1088 | var bits: u16 = 0; |
| 1078 | const fields = ty.structFields(mod).values(); | 1089 | const field_vals = try arena.alloc(InternPool.Index, struct_type.field_types.len); |
| 1079 | const field_vals = try arena.alloc(InternPool.Index, fields.len); | 1090 | for (field_vals, 0..) |*field_val, i| { |
| 1080 | for (fields, 0..) |field, i| { | 1091 | const field_ty = struct_type.field_types.get(ip)[i].toType(); |
| 1081 | const field_bits = @as(u16, @intCast(field.ty.bitSize(mod))); | 1092 | const field_bits: u16 = @intCast(field_ty.bitSize(mod)); |
| 1082 | field_vals[i] = try (try readFromPackedMemory(field.ty, mod, buffer, bit_offset + bits, arena)).intern(field.ty, mod); | 1093 | field_val.* = try (try readFromPackedMemory(field_ty, mod, buffer, bit_offset + bits, arena)).intern(field_ty, mod); |
| 1083 | bits += field_bits; | 1094 | bits += field_bits; |
| 1084 | } | 1095 | } |
| 1085 | return (try mod.intern(.{ .aggregate = .{ | 1096 | return (try mod.intern(.{ .aggregate = .{ |
| 1086 | .ty = ty.toIntern(), | 1097 | .ty = ty.toIntern(), |
| 1087 | .storage = .{ .elems = field_vals }, | 1098 | .storage = .{ .elems = field_vals }, |
| 1088 | } })).toValue(); | 1099 | } })).toValue(); |
| 1089 | }, | ||
| 1090 | }, | 1100 | }, |
| 1091 | .Pointer => { | 1101 | .Pointer => { |
| 1092 | assert(!ty.isSlice(mod)); // No well defined layout. | 1102 | assert(!ty.isSlice(mod)); // No well defined layout. |
| ... | @@ -1105,18 +1115,18 @@ pub const Value = struct { | ... | @@ -1105,18 +1115,18 @@ pub const Value = struct { |
| 1105 | pub fn toFloat(val: Value, comptime T: type, mod: *Module) T { | 1115 | pub fn toFloat(val: Value, comptime T: type, mod: *Module) T { |
| 1106 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { | 1116 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 1107 | .int => |int| switch (int.storage) { | 1117 | .int => |int| switch (int.storage) { |
| 1108 | .big_int => |big_int| @as(T, @floatCast(bigIntToFloat(big_int.limbs, big_int.positive))), | 1118 | .big_int => |big_int| @floatCast(bigIntToFloat(big_int.limbs, big_int.positive)), |
| 1109 | inline .u64, .i64 => |x| { | 1119 | inline .u64, .i64 => |x| { |
| 1110 | if (T == f80) { | 1120 | if (T == f80) { |
| 1111 | @panic("TODO we can't lower this properly on non-x86 llvm backend yet"); | 1121 | @panic("TODO we can't lower this properly on non-x86 llvm backend yet"); |
| 1112 | } | 1122 | } |
| 1113 | return @as(T, @floatFromInt(x)); | 1123 | return @floatFromInt(x); |
| 1114 | }, | 1124 | }, |
| 1115 | .lazy_align => |ty| @as(T, @floatFromInt(ty.toType().abiAlignment(mod))), | 1125 | .lazy_align => |ty| @floatFromInt(ty.toType().abiAlignment(mod).toByteUnits(0)), |
| 1116 | .lazy_size => |ty| @as(T, @floatFromInt(ty.toType().abiSize(mod))), | 1126 | .lazy_size => |ty| @floatFromInt(ty.toType().abiSize(mod)), |
| 1117 | }, | 1127 | }, |
| 1118 | .float => |float| switch (float.storage) { | 1128 | .float => |float| switch (float.storage) { |
| 1119 | inline else => |x| @as(T, @floatCast(x)), | 1129 | inline else => |x| @floatCast(x), |
| 1120 | }, | 1130 | }, |
| 1121 | else => unreachable, | 1131 | else => unreachable, |
| 1122 | }; | 1132 | }; |
| ... | @@ -1875,9 +1885,9 @@ pub const Value = struct { | ... | @@ -1875,9 +1885,9 @@ pub const Value = struct { |
| 1875 | }, | 1885 | }, |
| 1876 | inline .u64, .i64 => |x| floatFromIntInner(x, float_ty, mod), | 1886 | inline .u64, .i64 => |x| floatFromIntInner(x, float_ty, mod), |
| 1877 | .lazy_align => |ty| if (opt_sema) |sema| { | 1887 | .lazy_align => |ty| if (opt_sema) |sema| { |
| 1878 | return floatFromIntInner((try ty.toType().abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod); | 1888 | return floatFromIntInner((try ty.toType().abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar.toByteUnits(0), float_ty, mod); |
| 1879 | } else { | 1889 | } else { |
| 1880 | return floatFromIntInner(ty.toType().abiAlignment(mod), float_ty, mod); | 1890 | return floatFromIntInner(ty.toType().abiAlignment(mod).toByteUnits(0), float_ty, mod); |
| 1881 | }, | 1891 | }, |
| 1882 | .lazy_size => |ty| if (opt_sema) |sema| { | 1892 | .lazy_size => |ty| if (opt_sema) |sema| { |
| 1883 | return floatFromIntInner((try ty.toType().abiSizeAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod); | 1893 | return floatFromIntInner((try ty.toType().abiSizeAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod); |
| ... | @@ -1892,11 +1902,11 @@ pub const Value = struct { | ... | @@ -1892,11 +1902,11 @@ pub const Value = struct { |
| 1892 | fn floatFromIntInner(x: anytype, dest_ty: Type, mod: *Module) !Value { | 1902 | fn floatFromIntInner(x: anytype, dest_ty: Type, mod: *Module) !Value { |
| 1893 | const target = mod.getTarget(); | 1903 | const target = mod.getTarget(); |
| 1894 | const storage: InternPool.Key.Float.Storage = switch (dest_ty.floatBits(target)) { | 1904 | const storage: InternPool.Key.Float.Storage = switch (dest_ty.floatBits(target)) { |
| 1895 | 16 => .{ .f16 = @as(f16, @floatFromInt(x)) }, | 1905 | 16 => .{ .f16 = @floatFromInt(x) }, |
| 1896 | 32 => .{ .f32 = @as(f32, @floatFromInt(x)) }, | 1906 | 32 => .{ .f32 = @floatFromInt(x) }, |
| 1897 | 64 => .{ .f64 = @as(f64, @floatFromInt(x)) }, | 1907 | 64 => .{ .f64 = @floatFromInt(x) }, |
| 1898 | 80 => .{ .f80 = @as(f80, @floatFromInt(x)) }, | 1908 | 80 => .{ .f80 = @floatFromInt(x) }, |
| 1899 | 128 => .{ .f128 = @as(f128, @floatFromInt(x)) }, | 1909 | 128 => .{ .f128 = @floatFromInt(x) }, |
| 1900 | else => unreachable, | 1910 | else => unreachable, |
| 1901 | }; | 1911 | }; |
| 1902 | return (try mod.intern(.{ .float = .{ | 1912 | return (try mod.intern(.{ .float = .{ |