authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-08-24 20:43:43-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-21 14:48:40-07:00
logaccd5701c251c2741479fe08e56c8271c444f021
tree78871f150609687a9210063e90f8f4eb53997c38
parent0345d7866347c9066b0646f9e46be9a068dcfaa3

compiler: move struct types into InternPool proper

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.Index3//! * Module.Namespace has a pointer to Module.File
4//! * type_opaque via Module.Namespace.Index and Module.Decl.Index4//! * Module.Decl has a pointer to Module.CaptureScope
55
6/// Maps `Key` to `Index`. `Key` objects are not stored anywhere; they are6/// 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`.
40namespaces_free_list: std.ArrayListUnmanaged(Module.Namespace.Index) = .{},40namespaces_free_list: std.ArrayListUnmanaged(Module.Namespace.Index) = .{},
4141
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.
45allocated_structs: std.SegmentedList(Module.Struct, 0) = .{},
46/// When a Struct object is freed from `allocated_structs`, it is pushed into this stack.
47structs_free_list: std.ArrayListUnmanaged(Module.Struct.Index) = .{},
48
49/// Some types such as enums, structs, and unions need to store mappings from field names42/// 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 underlying43/// 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.
53maps: std.ArrayListUnmanaged(FieldMap) = .{},47maps: std.ArrayListUnmanaged(FieldMap) = .{},
5448
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 };
367361
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 };
374621
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)),
8971144
898 .int => |int| {1145 .int => |int| {
...@@ -969,11 +1216,11 @@ pub const Key = union(enum) {...@@ -969,11 +1216,11 @@ pub const Key = union(enum) {
9691216
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};
14351682
1683pub const RequiresComptime = enum(u2) { no, yes, unknown, wip };
1684
1436// Unlike `Tag.TypeUnion` which is an encoding, and `Key.UnionType` which is a1685// 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 info1686// 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 };
14761725
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.OptionalIndex2494 /// 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 no2497 /// 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};
26432977
2644/// State that is mutable during semantic analysis. This data is not used for2978/// 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) {
27643098
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.
2766pub const Alignment = enum(u6) {3100pub 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 _,
27693109
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 }
27763116
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 }
27833123
...@@ -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 }
27943134
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 }
27993153
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 is3195 /// 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};
28153219
2816/// Used for non-sentineled arrays that have length fitting in u32, as well as3220/// 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);
30673471
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);
30733474
...@@ -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 },
31503551
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 else3557 .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 } },
31673585
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) },
31713591
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 },
34823902
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}
36054030
4031fn extraStructType(ip: *const InternPool, extra_index: u32) Key.StructType {
4032 _ = ip;
4033 _ = extra_index;
4034 @panic("TODO");
4035}
4036
4037fn 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
3606fn extraFuncType(ip: *const InternPool, extra_index: u32) Key.FuncType {4069fn 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 },
38794343
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() instead4345 .anon_struct_type => unreachable, // use getAnonStructType() instead
3894
3895 .union_type => unreachable, // use getUnionType() instead4346 .union_type => unreachable, // use getUnionType() instead
38964347
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}
46375085
5086pub 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
5097pub 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
4638pub const AnonStructTypeInit = struct {5108pub 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;
49995469
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();
50025472
5003 try addStringsToMap(ip, gpa, names_map, names);5473 addStringsToMap(ip, names_map, names);
50045474
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 }
53165776
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);
53725829
5373 const names_map = try ip.addMap(gpa);5830 const names_map = try ip.addMap(gpa, enum_type.fields_len);
53745831
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);
54145871
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 };
54205877
...@@ -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
54845941
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);
54895946
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);
55195976
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 {
55536010
5554fn addStringsToMap(6011fn 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}
55676023
5568fn addIndexesToMap(6024fn 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}
55816036
5582fn addMap(ip: *InternPool, gpa: Allocator) Allocator.Error!MapIndex {6037fn 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}
55876044
...@@ -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)),
56386096
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}
62086666
6209pub 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
6217pub 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
6228pub fn indexToFuncType(ip: *const InternPool, val: Index) ?Key.FuncType {6667pub 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);
63446780
6345 // TODO: map overhead size is not taken into account6781 // 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;
63476783
6348 std.debug.print(6784 std.debug.print(
6349 \\InternPool size: {d} bytes6785 \\InternPool size: {d} bytes
6350 \\ {d} items: {d} bytes6786 \\ {d} items: {d} bytes
6351 \\ {d} extra: {d} bytes6787 \\ {d} extra: {d} bytes
6352 \\ {d} limbs: {d} bytes6788 \\ {d} limbs: {d} bytes
6353 \\ {d} structs: {d} bytes
6354 \\ {d} decls: {d} bytes6789 \\ {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}
66797137
6680pub fn structPtr(ip: *InternPool, index: Module.Struct.Index) *Module.Struct {
6681 return ip.allocated_structs.at(@intFromEnum(index));
6682}
6683
6684pub fn structPtrConst(ip: *const InternPool, index: Module.Struct.Index) *const Module.Struct {
6685 return ip.allocated_structs.at(@intFromEnum(index));
6686}
6687
6688pub fn structPtrUnwrapConst(ip: *const InternPool, index: Module.Struct.OptionalIndex) ?*const Module.Struct {
6689 return structPtrConst(ip, index.unwrap() orelse return null);
6690}
6691
6692pub fn declPtr(ip: *InternPool, index: Module.Decl.Index) *Module.Decl {7138pub 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}
67037149
6704pub 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
6718pub 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
6726pub fn createDecl(7150pub 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 {
70567482
7057pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 {7483pub 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 {
70667492
7067pub fn aggregateTypeLenIncludingSentinel(ip: *const InternPool, ty: Index) u64 {7493pub 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,
73067734
...@@ -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 reuse7957 // 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
7962pub fn anonStructFieldTypes(ip: *const InternPool, i: Index) []const Index {
7963 return ip.indexToKey(i).anon_struct_type.types;
7964}
7965
7966pub 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.
7971pub 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.
7979pub 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
105105
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 mutation108/// * comptime pointer mutation
111/// This memory lives until the Module is destroyed.109/// This memory lives until the Module is destroyed.
112tmp_hack_arena: std.heap.ArenaAllocator,110tmp_hack_arena: std.heap.ArenaAllocator,
...@@ -678,14 +676,10 @@ pub const Decl = struct {...@@ -678,14 +676,10 @@ pub const Decl = struct {
678676
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;
684682 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 }
690684
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 }
797791
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};
803798
...@@ -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};
808803
809pub const PropertyBoolean = enum { no, yes, unknown, wip };
810
811/// Represents the data that a struct declaration provides.
812pub 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
1021pub const DeclAdapter = struct {804pub const DeclAdapter = struct {
1022 mod: *Module,805 mod: *Module,
1023806
...@@ -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}
28952678
2896pub fn structPtr(mod: *Module, index: Struct.Index) *Struct {
2897 return mod.intern_pool.structPtr(index);
2898}
2899
2900pub fn namespacePtrUnwrap(mod: *Module, index: Namespace.OptionalIndex) ?*Namespace {2679pub 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}
29032682
2904/// This one accepts an index from the InternPool and asserts that it is not
2905/// the anonymous empty struct type.
2906pub 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.
2911pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool {2684pub 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 {
33513124
3352 if (!decl.owns_tv) continue;3125 if (!decl.owns_tv) continue;
33533126
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 }
33603133
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");
38723645
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();
38943647
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;
39113663
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();
39433669
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 }
39543673
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 };
39603676
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 else3681 .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();
39723692
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}
39813735
...@@ -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 {
40573811
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 had3816 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}
52434997
5244pub fn createStruct(mod: *Module, initialization: Struct) Allocator.Error!Struct.Index {
5245 return mod.intern_pool.createStruct(mod.gpa, initialization);
5246}
5247
5248pub fn destroyStruct(mod: *Module, index: Struct.Index) void {
5249 return mod.intern_pool.destroyStruct(mod.gpa, index);
5250}
5251
5252pub fn allocateNewDecl(4998pub 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 the5956 // 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 calling5957 // 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 }
62185964
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.
6642pub fn typeToStruct(mod: *Module, ty: Type) ?*Struct {6388pub 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
6396pub 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}
66476403
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.
6649pub fn typeToUnion(mod: *Module, ty: Type) ?InternPool.UnionType {6405pub 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}
66576413
6658pub fn typeToFunc(mod: *Module, ty: Type) ?InternPool.Key.FuncType {6414pub 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]
67416497
6742pub const UnionLayout = struct {6498pub 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;
67656521
6766 const field_align = u.fieldAlign(ip, @intCast(i)).toByteUnitsOptional() orelse6522 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's6553 // 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}
68356593
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 u646595pub fn unionAbiAlignment(mod: *Module, u: InternPool.UnionType) Alignment {
6838pub 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;
68456602
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 u646612pub fn unionFieldNormalAlignment(mod: *Module, u: InternPool.UnionType, field_index: u32) Alignment {
6856pub 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.
6630pub 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.
6653pub 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
6669pub 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);
22232223
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}
25112509
2512fn validateAlign(2510fn 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}
25252524
2526pub fn resolveAlign(2525pub fn resolveAlign(
...@@ -2801,26 +2800,26 @@ fn coerceResultPtr(...@@ -2801,26 +2800,26 @@ fn coerceResultPtr(
2801 }2800 }
2802}2801}
28032802
2804pub fn analyzeStructDecl(2803pub 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);
28152815
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 }
28392838
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}
28422854
2843fn zirStructDecl(2855fn 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);
28762888
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 compilation2897 // TODO: figure out InternPool removals for incremental compilation
2901 //errdefer mod.intern_pool.remove(struct_ty);2898 //errdefer ip.remove(struct_ty);
29022899
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();
29062903
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;
31973193
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 else3245 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 }
47244720
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 }
48544851
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(
5255fn failWithBadStructFieldAccess(5253fn 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;
52645262 const decl = mod.declPtr(struct_type.decl.unwrap().?);
5265 const fqn = try struct_obj.getFullyQualifiedName(mod);5263 const fqn = try decl.getFullyQualifiedName(mod);
52665264
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
1746117457
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 };
1746617462
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 };
1757917575
17580 try sema.resolveTypeLayout(ty); // Getting alignment requires type layout17576 try sema.resolveTypeLayout(ty); // Getting alignment requires type layout
17581 const layout = ty.containerLayout(mod);
1758217577
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
1765017645 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 dupe17650 // 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 };
1767917673
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 null17675 const default_val_ptr = try sema.optRefValue(block, field_ty, opt_default_val);
17682 else17676 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 );
1768617681
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
1773317728
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 } });
1774317736
...@@ -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 };
1775617749
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;
1893118925
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;
1929719290
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 }
1931419308
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) orelse19847 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 );
2017920174
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 ).?);
2019320190
...@@ -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 ).?);
2021020208
...@@ -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 ).?);
2024820254
...@@ -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 ).?);
2033520344
...@@ -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 ).?);
2035520365
...@@ -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 ).?);
2036920381
...@@ -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 ).?);
2039320406
...@@ -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 ).?);
2042420442
...@@ -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 ).?);
2045220474
...@@ -20496,11 +20518,13 @@ fn zirReify(...@@ -20496,11 +20518,13 @@ fn zirReify(
2049620518
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 ).?);
2050620530
...@@ -20515,7 +20539,7 @@ fn zirReify(...@@ -20515,7 +20539,7 @@ fn zirReify(
20515 });20539 });
20516 }20540 }
2051720541
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 }
2053020554
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 ).?);
2055220577
...@@ -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 ).?);
2061020639
...@@ -20644,14 +20673,17 @@ fn zirReify(...@@ -20644,14 +20673,17 @@ fn zirReify(
2064420673
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 ).?);
2065720689
...@@ -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 ).?);
2083420872
...@@ -20844,15 +20882,9 @@ fn zirReify(...@@ -20844,15 +20882,9 @@ fn zirReify(
20844 }20882 }
2084520883
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) orelse20889 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 ).?);
2087620911
...@@ -20931,6 +20966,8 @@ fn reifyStruct(...@@ -20931,6 +20966,8 @@ fn reifyStruct(
20931 .Auto => {},20966 .Auto => {},
20932 };20967 };
2093320968
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 an20972 // 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 }
2094820985
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 compilation20996 // 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;
2097620999
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();
2098021002
20981 // Fields21003 // 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 ).?);
2100321027
...@@ -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 }
2104121064
...@@ -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 }
2105321076
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 };
2106121082
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 }
2110821129
21109 if (layout == .Packed) {21130 if (layout == .Packed) {
21110 struct_obj.status = .layout_wip;21131 for (0..struct_type.field_types.len) |index| {
2111121132 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 }
2112221142
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 }
2112721147
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 }
2113821157
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}
2147821499
21479fn ptrFromIntVal(sema: *Sema, block: *Block, operand_src: LazySrcLoc, operand_val: Value, ptr_ty: Type, ptr_align: u32) !Value {21500fn 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)});
2148621514
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 }
2179721825
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 }
2193021969
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 });
2228622329
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 }
2230122345
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;
2455724594
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;
2523925276
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 });
2524625284
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) orelse26339 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];
2630526342
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);
2653026568
26531 try sema.resolveTypeFields(struct_ty);26569 try sema.resolveTypeFields(struct_ty);
26532 try sema.resolveStructLayout(struct_ty);26570 try sema.resolveStructLayout(struct_ty);
2653326571
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 }
2654526583
26546 const struct_obj = mod.typeToStruct(struct_ty).?;26584 const struct_type = mod.typeToStruct(struct_ty).?;
2654726585
26548 const field_index_big = struct_obj.fields.getIndex(field_name) orelse26586 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);
2655126588
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 }
2656926607
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);
2657426612
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(
2658326621
26584 const target = mod.getTarget();26622 const target = mod.getTarget();
2658526623
26586 const parent_align = struct_ptr_ty_info.flags.alignment.toByteUnitsOptional() orelse26624 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());
2658826628
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);
2659126631
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;
2659526636
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;
2660226643
...@@ -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 }
2660926650
26610 ptr_ty_data.flags.alignment = Alignment.fromByteUnits(parent_align);26651 ptr_ty_data.flags.alignment = parent_align;
2661126652
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 stores26654 // 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 not26658 // 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 it26659 // 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 and26661 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, in26675 // 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 alignment26683 // 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 }
2664526691
26646 const ptr_field_ty = try mod.ptrType(ptr_ty_data);26692 const ptr_field_ty = try mod.ptrType(ptr_ty_data);
2664726693
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);
2668226729
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];
2669326735
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 }
2669726741
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 }
2670526751
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,
2827228321
...@@ -28312,6 +28361,11 @@ const InMemoryCoercionResult = union(enum) {...@@ -28312,6 +28361,11 @@ const InMemoryCoercionResult = union(enum) {
28312 wanted: u64,28361 wanted: u64,
28313 };28362 };
2831428363
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 or29187 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() orelse29190 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);
2913829194
29139 const dest_align = dest_info.flags.alignment.toByteUnitsOptional() orelse29195 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);
2914129199
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;
3038030438
30381 const inst_align = inst_info.flags.alignment.toByteUnitsOptional() orelse30439 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);
3038330443
30384 const dest_align = dest_info.flags.alignment.toByteUnitsOptional() orelse30444 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);
3038630448
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 else30660 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 else30666 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 }
3087130933
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);
3087630938
...@@ -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 else30953 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 };
3091030969
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;
3093030990
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 location30993 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 }
3095031010
...@@ -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 else31066 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 };
3101731071
...@@ -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", .{});
3102031074
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 };
3103131085
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);
3103331087
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 };
3104331097
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(
3106331117
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 };
3106931123
...@@ -33181,12 +33235,17 @@ fn resolvePeerTypesInner(...@@ -33181,12 +33235,17 @@ fn resolvePeerTypesInner(
33181 }33235 }
3318233236
33183 // Note that the align can be always non-zero; Module.ptrType will canonicalize it33237 // 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() orelse33239 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() orelse33243
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 } };
3326133320
33262 // Note that the align can be always non-zero; Type.ptr will canonicalize it33321 // 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() orelse33323 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() orelse33327
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 );
3326933333
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}
3419234256
34193fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {34257fn 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 }
3421434304
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 }
3422634314
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 }
3423034319
34231 struct_obj.status = .have_layout;34320 const RuntimeOrder = InternPool.Key.StructType.RuntimeOrder;
34232 _ = try sema.typeRequiresComptime(ty);
3423334321
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 }
3424334324
34244 if (struct_obj.layout == .Auto and !struct_obj.is_tuple and34325 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)];
3424834329 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 }
3425534337
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);
3425934341 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 anything34348 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}
3427734353
34278fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!void {34354fn 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;
3428034357
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 }
3428534363
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);
3428834366
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);
3429334371
...@@ -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 };
3434834426
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}
3438834468
...@@ -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);
3453334613
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).?;
3453734617
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 }
3454234620
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 to34622 // 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;
3454934624
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}
3456034630
34561fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void {34631fn 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 {
3459134661
34592pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void {34662pub 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();
3459434666
34595 switch (ty.toIntern()) {34667 switch (ty_ip) {
34596 .var_args_param_type => unreachable,34668 .var_args_param_type => unreachable,
3459734669
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,
3467534747
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
3471634783
34717fn resolveTypeFieldsStruct(34784fn 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 }
3475234819
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}
3475734825
34758fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Key.UnionType) CompileError!void {34826fn 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}
3493835006
34939fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void {35007fn 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;
3497935054
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;
3498735062 return;
34988 const decl = mod.declPtr(decl_index);35063 },
3498935064 };
34990 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
34991 defer analysis_arena.deinit();
3499235065
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);
3502335096
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;
3503535107
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;
3505835130
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_comment35138 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;
3507435148
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 s35151 const field_name = try ip.getOrPutString(gpa, field_name_zir);
35078 else35152 if (struct_type.addFieldName(ip, field_name)) |other_index| {
35079 try std.fmt.allocPrint(sema.arena, "{d}", .{field_i}));35153 const msg = msg: {
3508035154 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);
3508735157
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 };
3510335166
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 }
3515435218
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;
3515735220
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);
3519435258
35195 try sema.explainWhyTypeIsNotExtern(msg, ty_src, field.ty, .struct_field);35259 try sema.explainWhyTypeIsNotExtern(msg, ty_src, field_ty, .struct_field);
3519635260
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);
3520935274
35210 try sema.explainWhyTypeIsNotPacked(msg, ty_src, field.ty);35275 try sema.explainWhyTypeIsNotPacked(msg, ty_src, field_ty);
3521135276
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 }
3521735284
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 }
3523435302
35235 extra_index += zir_field.init_body_len;35303 extra_index += zir_field.init_body_len;
35236 }35304 }
3523735305
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.
3523935308
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}
3528135349
35282fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.UnionType) CompileError!void {35350fn 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 {
3608136151
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 }
3610536154
36106 // In this case the struct has no runtime-known fields and36155 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 }
3611336163
36114 // In this case the struct has no fields at all and36164 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 },
3612136196
...@@ -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;
3658436663
36585 try sema.resolveTypeFieldsStruct(ty, struct_obj);36664 try sema.resolveTypeFieldsStruct(ty.toIntern(), struct_type);
36665
36666 struct_type.flagsPtr(ip).requires_comptime = .wip;
3658636667
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}
3667536757
36676fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!u32 {36758fn 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}
3667936761
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 u6436764fn unionFieldAlignment(sema: *Sema, u: InternPool.UnionType, field_index: u32) !Alignment {
36683fn 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}
3669136773
36692/// Keep implementation in sync with `Module.Struct.Field.alignment`.36774/// Keep implementation in sync with `Module.structFieldAlignment`.
36693fn structFieldAlignment(sema: *Sema, field: Module.Struct.Field, layout: std.builtin.Type.ContainerLayout) !u32 {36775fn 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 // extern36789 // 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) orelse36844 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}
3676536848
...@@ -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 {
3738137458
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 {
3739137468
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 on37483 // 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(", ");
433433
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;
23const leb128 = std.leb;23const leb128 = std.leb;
24const log = std.log.scoped(.codegen);24const log = std.log.scoped(.codegen);
25const build_options = @import("build_options");25const build_options = @import("build_options");
26const Alignment = InternPool.Alignment;
2627
27const CodeGenError = codegen.CodeGenError;28const CodeGenError = codegen.CodeGenError;
28const Result = codegen.Result;29const 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 register507 // (or w0 when pointer size is 32 bits). As this register
507 // might get overwritten along the way, save the address508 // 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);
512511
513 const stack_offset = try self.allocMem(ptr_bytes, ptr_bytes, null);512 const stack_offset = try self.allocMem(8, .@"8", null);
514513
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 {
998fn allocMem(997fn 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);
10061005
1007 // In order to efficiently load and store stack items that fit1006 // In order to efficiently load and store stack items that fit
1008 // into registers, we bump up the alignment to the next power of1007 // 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_align1010 abi_align
1012 else1011 else
1013 std.math.ceilPowerOfTwoAssert(u32, abi_size);1012 Alignment.fromNonzeroByteUnits(std.math.ceilPowerOfTwoAssert(u64, abi_size));
10141013
1015 // TODO find a free slot instead of always appending1014 // 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);
10191018
...@@ -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);
15171516
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 }
32873283
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));
32913287
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 {
3376fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {3372fn 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 {
3400fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {3396fn 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);
42784274
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)));
59425938 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 {
62546247
6255 // We round up NCRN only for non-Apple platforms which allow the 16-byte aligned6248 // 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 number6251 // 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 provided6266 // 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 {
63126305
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);
63176310
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;
23const leb128 = std.leb;23const leb128 = std.leb;
24const log = std.log.scoped(.codegen);24const log = std.log.scoped(.codegen);
25const build_options = @import("build_options");25const build_options = @import("build_options");
26const Alignment = InternPool.Alignment;
2627
27const Result = codegen.Result;28const Result = codegen.Result;
28const CodeGenError = codegen.CodeGenError;29const 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 in509 // The address of where to store the return value is in
509 // r0. As this register might get overwritten along the510 // 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);
512513
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 {
986fn allocMem(987fn 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);
994995
995 // TODO find a free slot instead of always appending996 // 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);
9991000
...@@ -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);
14921493
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);
42574258
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)));
58985899
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 }
62026203
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);
62066207
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);
62216222
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 {
62526253
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);
62576258
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 {
6666
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 or68 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;
23const log = std.log.scoped(.codegen);23const log = std.log.scoped(.codegen);
24const build_options = @import("build_options");24const build_options = @import("build_options");
25const codegen = @import("../../codegen.zig");25const codegen = @import("../../codegen.zig");
26const Alignment = InternPool.Alignment;
2627
27const CodeGenError = codegen.CodeGenError;28const CodeGenError = codegen.CodeGenError;
28const Result = codegen.Result;29const Result = codegen.Result;
...@@ -53,7 +54,7 @@ ret_mcv: MCValue,...@@ -53,7 +54,7 @@ ret_mcv: MCValue,
53fn_type: Type,54fn_type: Type,
54arg_index: usize,55arg_index: usize,
55src_loc: Module.SrcLoc,56src_loc: Module.SrcLoc,
56stack_align: u32,57stack_align: Alignment,
5758
58/// MIR Instructions59/// MIR Instructions
59mir_instructions: std.MultiArrayList(Mir.Inst) = .{},60mir_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}
790791
791fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 {792fn 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 appending794 // 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;
827826
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,
26062605
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 }
26722671
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;
24const Result = @import("../../codegen.zig").Result;24const Result = @import("../../codegen.zig").Result;
25const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;25const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
26const Endian = std.builtin.Endian;26const Endian = std.builtin.Endian;
27const Alignment = InternPool.Alignment;
2728
28const build_options = @import("build_options");29const build_options = @import("build_options");
2930
...@@ -62,7 +63,7 @@ ret_mcv: MCValue,...@@ -62,7 +63,7 @@ ret_mcv: MCValue,
62fn_type: Type,63fn_type: Type,
63arg_index: usize,64arg_index: usize,
64src_loc: Module.SrcLoc,65src_loc: Module.SrcLoc,
65stack_align: u32,66stack_align: Alignment,
6667
67/// MIR Instructions68/// MIR Instructions
68mir_instructions: std.MultiArrayList(Mir.Inst) = .{},69mir_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,
231232
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 {
424425
425 // Backpatch stack offset426 // 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)));
883884 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);
24412439 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}
27842779
2785fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 {2780fn 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 appending2782 // 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;
28302823
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 }
45224515
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";
45254518
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");
25const Mir = @import("Mir.zig");25const Mir = @import("Mir.zig");
26const Emit = @import("Emit.zig");26const Emit = @import("Emit.zig");
27const abi = @import("abi.zig");27const abi = @import("abi.zig");
28const Alignment = InternPool.Alignment;
28const errUnionPayloadOffset = codegen.errUnionPayloadOffset;29const errUnionPayloadOffset = codegen.errUnionPayloadOffset;
29const errUnionErrorOffset = codegen.errUnionErrorOffset;30const errUnionErrorOffset = codegen.errUnionErrorOffset;
3031
...@@ -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.md710/// 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.
712stack_alignment: u32 = 16,713stack_alignment: Alignment = .@"16",
713714
714// For each individual Wasm valtype we store a seperate free list which715// 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 type992/// Using a given `Type`, returns the corresponding type
992fn typeToValtype(ty: Type, mod: *Module) wasm.Valtype {993fn 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 u16998 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 stack1008 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 function1287 // 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 size1289 // 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 pointer1292 // 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 aligment1294 // 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 alignment1296 // 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 offsets1298 // 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);
15291531
1530 if (abi_align > func.stack_alignment) {1532 func.stack_alignment = func.stack_alignment.max(abi_align);
1531 func.stack_alignment = abi_align;
1532 }
15331533
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;
15361536
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 }
15661564
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;
15691567
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 opcodes2390 // 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 memory2447 // 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}
24572456
...@@ -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
25262525
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 );
25312533
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;
30273029
3028 // tag is stored first so calculate offset from where payload starts3030 // 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}
31053107
3108/// This function is intended to assert that `isByRef` returns `false` for `ty`.
3109/// However such an assertion fails on the behavior tests currently.
3106fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {3110fn 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 integer3248 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 {
32693277
3270fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue {3278fn 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(
37573765
3758fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {3766fn 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;
37623771
...@@ -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 }
40594068
...@@ -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;
50675079
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 {
50995111
5100fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {5112fn 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();
51565169
5157 // ensure the result is zero'd5170 // 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 else5174 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 {
51645177
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;
51695182
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 else5185 else
5173 WValue{ .imm64 = current_bit };5186 WValue{ .imm64 = current_bit };
51745187
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);
51785191
5179 // load our current result on stack so we can perform all transformations5192 // 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 05197 // 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;
52005213
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);
52055218
...@@ -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 {
54205433
5421 // when the tag alignment is smaller than the payload, the field will be stored5434 // 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 stored5453 // 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-scalar35 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-natural37 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");
27const Mir = @import("Mir.zig");27const Mir = @import("Mir.zig");
28const Module = @import("../../Module.zig");28const Module = @import("../../Module.zig");
29const InternPool = @import("../../InternPool.zig");29const InternPool = @import("../../InternPool.zig");
30const Alignment = InternPool.Alignment;
30const Target = std.Target;31const Target = std.Target;
31const Type = @import("../../type.zig").Type;32const Type = @import("../../type.zig").Type;
32const TypedValue = @import("../../TypedValue.zig");33const TypedValue = @import("../../TypedValue.zig");
...@@ -607,19 +608,21 @@ const InstTracking = struct {...@@ -607,19 +608,21 @@ const InstTracking = struct {
607608
608const FrameAlloc = struct {609const 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,
612613
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};
625628
...@@ -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 );
712715
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 );
742751
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);
21942203
2195 // Create list of registers to save in the prologue.2204 // Create list of registers to save in the prologue.
2196 // TODO handle register classes2205 // 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)]);
22212230
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}
22282237
2229fn getFrameAddrAlignment(self: *Self, frame_addr: FrameAddr) u32 {2238fn 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}
22332242
2234fn getFrameAddrSize(self: *Self, frame_addr: FrameAddr) u32 {2243fn 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);
22422251
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);
22452254
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);
22512260
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}
22722281
...@@ -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);
42684277
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 operand4279 // 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 else4323 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 else4335 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 else5614 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 }
80968108
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 }
1108411086
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 else11583 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 });
1158411586
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 011588 0
11587 else11589 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,
1182711829
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";
1187611878
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 }
1195811960
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";
1197211974
11973 // Return values11975 // 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 }
1201212014
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}
1201612018
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 classified211 // "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 {
222223
223 var result_i: usize = 0; // out of 8224 var result_i: usize = 0; // out of 8
224 var byte_i: usize = 0; // out of 8225 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;
342341
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;
533const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;533const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
534const Type = @import("../../type.zig").Type;534const Type = @import("../../type.zig").Type;
535const Value = @import("../../value.zig").Value;535const Value = @import("../../value.zig").Value;
536
537fn _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;
22const TypedValue = @import("TypedValue.zig");22const TypedValue = @import("TypedValue.zig");
23const Value = @import("value.zig").Value;23const Value = @import("value.zig").Value;
24const Zir = @import("Zir.zig");24const Zir = @import("Zir.zig");
25const Alignment = InternPool.Alignment;
2526
26pub const Result = union(enum) {27pub 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 }
142144
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);
274276
275 // error value first when its type is larger than the error union's payload277 // 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 }
279281
...@@ -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;
296298
297 if (padding > 0) {299 if (padding > 0) {
...@@ -300,11 +302,11 @@ pub fn generateSymbol(...@@ -300,11 +302,11 @@ pub fn generateSymbol(
300 }302 }
301303
302 // Payload size is larger than error set, so emit our error set last304 // 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;
309311
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)) orelse481 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;
487486
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(
499496
500 // pointer may point to a decl which must be marked used497 // 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)) orelse500 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);
522520 const offsets = struct_type.offsets.get(ip);
523 var it = typed_value.ty.iterateStructOffsets(mod);
524521
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| {
527524 const field_ty = field_types[field_index];
528 if (!field_ty.hasRuntimeBits(mod)) continue;525 if (!field_ty.toType().hasRuntimeBits(mod)) continue;
529526
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 };
538535
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);
541541
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 }
550550
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 }
566573
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 }
597604
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 }
855862
...@@ -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}
10451052
...@@ -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;
17const Air = @import("../Air.zig");17const Air = @import("../Air.zig");
18const Liveness = @import("../Liveness.zig");18const Liveness = @import("../Liveness.zig");
19const InternPool = @import("../InternPool.zig");19const InternPool = @import("../InternPool.zig");
20const Alignment = InternPool.Alignment;
2021
21const BigIntLimb = std.math.big.Limb;22const BigIntLimb = std.math.big.Limb;
22const BigInt = std.math.big.int;23const BigInt = std.math.big.int;
...@@ -292,7 +293,7 @@ pub const Function = struct {...@@ -292,7 +293,7 @@ pub const Function = struct {
292293
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 }
330331
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 }
336337
337 /// Only allocates the local; does not print anything. Will attempt to re-use locals, so should338 /// 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 }
13111360
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;
13171365
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() } };
13281375 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);
13351382 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 {
13381385 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;
13411387
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;
13451390
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;
13481401
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 }
13611406
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 } }),
13671412 .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(')');
14091415
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 } });
24612457
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 });
24732469
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();
27182714
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");
27222718
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 {
33533349
3354 try reap(f, inst, &.{ty_op.operand});3350 try reap(f, inst, &.{ty_op.operand});
33553351
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 else3354 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 }
36273623
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 else3626 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 else5423 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);
54325428
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));
54345430
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);
54375433
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,
285285
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 {
13601366
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;
13631370
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 },
14891496
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 {
17221729
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 );
10821082
...@@ -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 }
13201320
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);
14081409
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();
14271428
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();
14421443
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;
14571458
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);
14621463
...@@ -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() orelse1486 @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;
15331534
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);
15371538
...@@ -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;
15481549
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);
15521553
...@@ -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 {
20552056
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;
20602061
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 bits2068 ptr_size * 8, // size in bits
2068 ptr_align * 8, // align in bits2069 ptr_align.toByteUnits(0) * 8, // align in bits
2069 0, // offset in bits2070 0, // offset in bits
2070 0, // flags2071 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 bits2079 len_size * 8, // size in bits
2079 len_align * 8, // align in bits2080 len_align.toByteUnits(0) * 8, // align in bits
2080 len_offset * 8, // offset in bits2081 len_offset * 8, // offset in bits
2081 0, // flags2082 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 bits2092 ty.abiSize(mod) * 8, // size in bits
2092 ty.abiAlignment(mod) * 8, // align in bits2093 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
2093 0, // flags2094 0, // flags
2094 null, // derived from2095 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 {
21742175
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 {
22232224
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;
22282229
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 bits2236 payload_size * 8, // size in bits
2236 payload_align * 8, // align in bits2237 payload_align.toByteUnits(0) * 8, // align in bits
2237 0, // offset in bits2238 0, // offset in bits
2238 0, // flags2239 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 bits2247 non_null_size * 8, // size in bits
2247 non_null_align * 8, // align in bits2248 non_null_align.toByteUnits(0) * 8, // align in bits
2248 non_null_offset * 8, // offset in bits2249 non_null_offset * 8, // offset in bits
2249 0, // flags2250 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 bits2260 ty.abiSize(mod) * 8, // size in bits
2260 ty.abiAlignment(mod) * 8, // align in bits2261 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
2261 0, // flags2262 0, // flags
2262 null, // derived from2263 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 }
23202321
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 bits2328 error_size * 8, // size in bits
2328 error_align * 8, // align in bits2329 error_align.toByteUnits(0) * 8, // align in bits
2329 error_offset * 8, // offset in bits2330 error_offset * 8, // offset in bits
2330 0, // flags2331 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 bits2339 payload_size * 8, // size in bits
2339 payload_align * 8, // align in bits2340 payload_align.toByteUnits(0) * 8, // align in bits
2340 payload_offset * 8, // offset in bits2341 payload_offset * 8, // offset in bits
2341 0, // flags2342 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 bits2351 ty.abiSize(mod) * 8, // size in bits
2351 ty.abiAlignment(mod) * 8, // align in bits2352 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
2352 0, // flags2353 0, // flags
2353 null, // derived from2354 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);
23762377
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 {
24172418
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;
24222423
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, // file2433 null, // file
2433 0, // line2434 0, // line
2434 field_size * 8, // size in bits2435 field_size * 8, // size in bits
2435 field_align * 8, // align in bits2436 field_align.toByteUnits(0) * 8, // align in bits
2436 field_offset * 8, // offset in bits2437 field_offset * 8, // offset in bits
2437 0, // flags2438 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, // file2446 null, // file
2446 0, // line2447 0, // line
2447 ty.abiSize(mod) * 8, // size in bits2448 ty.abiSize(mod) * 8, // size in bits
2448 ty.abiAlignment(mod) * 8, // align in bits2449 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
2449 0, // flags2450 0, // flags
2450 null, // derived from2451 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 to2465 // This can happen if a struct type makes it all the way to
2467 // flush() without ever being instantiated or referenced (even2466 // flush() without ever being instantiated or referenced (even
2468 // via pointer). The only reason we are hearing about it now is2467 // 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 }
24942493
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);
24972497
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);
25002500
2501 try di_fields.ensureUnusedCapacity(gpa, fields.count());2501 try di_fields.ensureUnusedCapacity(gpa, field_types.len);
25022502
2503 comptime assert(struct_layout_version == 2);2503 comptime assert(struct_layout_version == 2);
2504 var offset: u64 = 0;2504 var offset: u64 = 0;
25052505 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;
25132516
2514 const field_name = ip.stringToSlice(fields.keys()[field_and_index.index]);2517 const field_name = ip.stringToSlice(field_names[field_index]);
25152518
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, // file2522 null, // file
2520 0, // line2523 0, // line
2521 field_size * 8, // size in bits2524 field_size * 8, // size in bits
2522 field_align * 8, // align in bits2525 field_align.toByteUnits(0) * 8, // align in bits
2523 field_offset * 8, // offset in bits2526 field_offset * 8, // offset in bits
2524 0, // flags2527 0, // flags
2525 try o.lowerDebugType(field.ty, .full),2528 try o.lowerDebugType(field_ty, .full),
2526 ));2529 ));
2527 }2530 }
25282531
...@@ -2532,7 +2535,7 @@ pub const Object = struct {...@@ -2532,7 +2535,7 @@ pub const Object = struct {
2532 null, // file2535 null, // file
2533 0, // line2536 0, // line
2534 ty.abiSize(mod) * 8, // size in bits2537 ty.abiSize(mod) * 8, // size in bits
2535 ty.abiAlignment(mod) * 8, // align in bits2538 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
2536 0, // flags2539 0, // flags
2537 null, // derived from2540 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, // file2591 null, // file
2589 0, // line2592 0, // line
2590 ty.abiSize(mod) * 8, // size in bits2593 ty.abiSize(mod) * 8, // size in bits
2591 ty.abiAlignment(mod) * 8, // align in bits2594 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
2592 0, // flags2595 0, // flags
2593 null, // derived from2596 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, // file2627 null, // file
2625 0, // line2628 0, // line
2626 field_size * 8, // size in bits2629 field_size * 8, // size in bits
2627 field_align * 8, // align in bits2630 field_align.toByteUnits(0) * 8, // align in bits
2628 0, // offset in bits2631 0, // offset in bits
2629 0, // flags2632 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, // file2647 null, // file
2645 0, // line2648 0, // line
2646 ty.abiSize(mod) * 8, // size in bits2649 ty.abiSize(mod) * 8, // size in bits
2647 ty.abiAlignment(mod) * 8, // align in bits2650 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
2648 0, // flags2651 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 {
26612664
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 }
26712674
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, // file2678 null, // file
2676 0, // line2679 0, // line
2677 layout.tag_size * 8,2680 layout.tag_size * 8,
2678 layout.tag_align * 8, // align in bits2681 layout.tag_align.toByteUnits(0) * 8,
2679 tag_offset * 8, // offset in bits2682 tag_offset * 8, // offset in bits
2680 0, // flags2683 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, // file2690 null, // file
2688 0, // line2691 0, // line
2689 layout.payload_size * 8, // size in bits2692 layout.payload_size * 8, // size in bits
2690 layout.payload_align * 8, // align in bits2693 layout.payload_align.toByteUnits(0) * 8,
2691 payload_offset * 8, // offset in bits2694 payload_offset * 8, // offset in bits
2692 0, // flags2695 0, // flags
2693 union_di_ty,2696 union_di_ty,
2694 );2697 );
26952698
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 else2702 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, // file2708 null, // file
2706 0, // line2709 0, // line
2707 ty.abiSize(mod) * 8, // size in bits2710 ty.abiSize(mod) * 8, // size in bits
2708 ty.abiAlignment(mod) * 8, // align in bits2711 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
2709 0, // flags2712 0, // flags
2710 null, // derived from2713 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 }
29272930
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);
29302933
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 {
32483250
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.*;
32783280
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 }
32863286
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 calls3291 gop.value_ptr.* = ty; // must be done before any recursive calls
32923292
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 be3295 // 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);
33013299
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;
33063304
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);
33163319
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));
33273330
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 {
33533356
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;
33573360
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;
33643367
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);
33693372
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;
34493452
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 {
36873690
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;
39223925
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);
39273930
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;
39753977
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);
40224028
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 }
40334039
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;
40414047
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 {
41744180
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);
41834190
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 pointer4194 // 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 }
41914198
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);
42004208
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) or4211 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);
42194227
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);
42274235
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 {
42414249
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 one4264 // 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() orelse4421 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);
49314939
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);
49794987
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));
49965004
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 allocate5010 // 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() orelse5140 @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 having5185 // 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 callsite5186 // 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 {
52665274
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();
52705278
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 means5280 // 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;
53365344
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);
53395347
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);
53605368
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);
53635371
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;
59996007
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 }
60036011
...@@ -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 }
61036111
...@@ -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;
62306236
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);
68396845
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, "");
72657269
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).?;
76917695
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).?;
80498053
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 completely8354 // 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 }
83758379
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 }
83808384
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();
84638463
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 }
84688468
...@@ -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 }
84818481
...@@ -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 );
86528652
...@@ -8685,7 +8685,7 @@ pub const FuncGen = struct {...@@ -8685,7 +8685,7 @@ pub const FuncGen = struct {
86858685
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();
86898689
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 {
89118912
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 {
89988997
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 store9025 // 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;
96379635
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 else9641 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 }
96549652
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 0xaa9656 // 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);
96609660
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 {
96949692
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);
96999697
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 set9769 // 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 }
98289826
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 }
98479845
...@@ -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 );
99849982
...@@ -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, "");
1002510023
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;
1005110049
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);
1005510053
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;
1017010166
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;
1017610174
...@@ -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);
1020210200
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);
1020610204
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;
1024510243
...@@ -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;
1033810336
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();
1034110339
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
1071810716
10719fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type {10717fn 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 {
1098210985
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 {
1113711146
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;
1116111164
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}
1136311374
11364fn errUnionPayloadOffset(payload_ty: Type, mod: *Module) u1 {11375fn 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}
1136711378
11368fn errUnionErrorOffset(payload_ty: Type, mod: *Module) u1 {11379fn 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}
1137111382
11372/// Returns true for asm constraint (e.g. "=*m", "=r") if it accepts a memory location11383/// 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 }
799799
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;
803807
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());
813817
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();
839843
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);
842846
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){};
11811185
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?
11851189
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 };
13561360
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 }
13611364
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();
13671370
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 }
13761378
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));
13781380
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);
15021504
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;
26042606
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 }
26092611
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 };
11201120
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.?;
11981198
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();
12021202
...@@ -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 };
12421242
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);
12451245
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));
13231323
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));
13261326
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.string345 // 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);
349348
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 }
354353
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.member361 // 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.ref4367 // 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.udata371 // 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 have419 // 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 generated420 // 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);
504502
505 // DW.AT.structure_type503 // 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();
410410
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 }
429429
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 GOT432 // 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 }
445445
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 }
466466
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 requires470 // 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 }
491491
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 GOT496 // 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 }
514514
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 GOT519 // 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 }
537537
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 }
557557
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 0561 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 }
579579
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 0583 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 }
601601
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 }
621621
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 }
640640
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 }
660660
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 }
680680
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 }
700700
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 {
723723
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 }
744744
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 }
769769
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 }
794794
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 }
819819
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(
26662666
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;
26712671
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;
28712871
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();
28752875
...@@ -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;
29232923
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;
30003000
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,
11size: u64 = 0,11size: u64 = 0,
1212
13/// Alignment of this atom as a power of two.13/// Alignment of this atom as a power of two.
14alignment: u8 = 0,14alignment: Alignment = .@"1",
1515
16/// Index of the input section.16/// Index of the input section.
17input_section_index: Index = 0,17input_section_index: Index = 0,
...@@ -42,6 +42,8 @@ fde_end: u32 = 0,...@@ -42,6 +42,8 @@ fde_end: u32 = 0,
42prev_index: Index = 0,42prev_index: Index = 0,
43next_index: Index = 0,43next_index: Index = 0,
4444
45pub const Alignment = @import("../../InternPool.zig").Alignment;
46
45pub fn name(self: Atom, elf_file: *Elf) []const u8 {47pub 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);
116117
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 node142 // 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 up143 // 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().?);
196197
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 before199 // 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}
225226
226pub fn grow(self: *Atom, elf_file: *Elf) !void {227pub 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}
232231
233pub fn free(self: *Atom, elf_file: *Elf) void {232pub 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}
190190
...@@ -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);
575575
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;
870const File = @import("file.zig").File;870const File = @import("file.zig").File;
871const StringTable = @import("../strtab.zig").StringTable;871const StringTable = @import("../strtab.zig").StringTable;
872const Symbol = @import("Symbol.zig");872const Symbol = @import("Symbol.zig");
873const 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 {
14251425
1426const CreateAtomOpts = struct {1426const CreateAtomOpts = struct {
1427 size: u64 = 0,1427 size: u64 = 0,
1428 alignment: u32 = 0,1428 alignment: Alignment = .@"1",
1429};1429};
14301430
1431pub fn createAtom(self: *MachO, sym_index: u32, opts: CreateAtomOpts) !Atom.Index {1431pub 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 {
14731473
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);
14991499
...@@ -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 {
1521fn createThreadLocalDescriptorAtom(self: *MachO, sym_name: []const u8, target: SymbolWithLoc) !Atom.Index {1521fn 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}
20322032
2033fn growAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignment: u64) !u64 {2033fn 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.?;
23522352
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();
23562356
...@@ -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;
26182618
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);
26212621
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}
32063206
3207fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignment: u64) !u64 {3207fn 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();
32103210
...@@ -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 node3252 // 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 up3253 // 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 };
32863286
...@@ -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 }
32973297
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;
33033301
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
33383336
3339pub fn writeSegmentHeaders(self: *MachO, writer: anytype) !void {3337pub 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");
5526const Type = @import("../type.zig").Type;5524const Type = @import("../type.zig").Type;
5527const TypedValue = @import("../TypedValue.zig");5525const TypedValue = @import("../TypedValue.zig");
5528const Value = @import("../value.zig").Value;5526const Value = @import("../value.zig").Value;
5527const Alignment = Atom.Alignment;
55295528
5530pub const DebugSymbols = @import("MachO/DebugSymbols.zig");5529pub const DebugSymbols = @import("MachO/DebugSymbols.zig");
5531pub const Bind = @import("MachO/dyld_info/bind.zig").Bind(*const MachO, SymbolWithLoc);5530pub 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,
2828
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.
31alignment: u32 = 0,31alignment: Alignment = .@"1",
3232
33/// Points to the previous and next neighbours33/// Points to the previous and next neighbours
34/// TODO use the same trick as with symbols: reserve index 0 as null atom34/// TODO use the same trick as with symbols: reserve index 0 as null atom
35next_index: ?Index = null,35next_index: ?Index = null,
36prev_index: ?Index = null,36prev_index: ?Index = null,
3737
38pub const Alignment = @import("../../InternPool.zig").Alignment;
39
38pub const Index = u32;40pub const Index = u32;
3941
40pub const Binding = struct {42pub 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;
384384
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 else494 else
495 sect.addr + sect.size - addr;495 sect.addr + sect.size - addr;
496496
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 else499 else
500 sect.@"align";500 sect.@"align");
501501
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");
1115const Platform = @import("load_commands.zig").Platform;1118const Platform = @import("load_commands.zig").Platform;
1116const SymbolWithLoc = MachO.SymbolWithLoc;1119const SymbolWithLoc = MachO.SymbolWithLoc;
1117const UnwindInfo = @import("UnwindInfo.zig");1120const UnwindInfo = @import("UnwindInfo.zig");
1121const 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 {
104104
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);
108108
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 {
112112
113 macho_file.logAtom(group_end, log);113 macho_file.logAtom(group_end, log);
114114
115 header.@"align" = @max(header.@"align", atom.alignment);115 header.@"align" = @max(header.@"align", atom.alignment.toLog2Units());
116116
117 allocated.putAssumeCapacityNoClobber(group_end, {});117 allocated.putAssumeCapacityNoClobber(group_end, {});
118118
...@@ -196,7 +196,7 @@ fn allocateThunk(...@@ -196,7 +196,7 @@ fn allocateThunk(
196196
197 macho_file.logAtom(atom_index, log);197 macho_file.logAtom(atom_index, log);
198198
199 header.@"align" = @max(header.@"align", atom.alignment);199 header.@"align" = @max(header.@"align", atom.alignment.toLog2Units());
200200
201 if (end_atom_index == atom_index) break;201 if (end_atom_index == atom_index) break;
202202
...@@ -326,7 +326,10 @@ fn isReachable(...@@ -326,7 +326,10 @@ fn isReachable(
326326
327fn createThunkAtom(macho_file: *MachO) !Atom.Index {327fn 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 {
985985
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;
991990
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;
994993
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());
997996
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 }
10031000
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.?;
11081108
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();
11121112
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.
188synthetic_functions: std.ArrayListUnmanaged(Atom.Index) = .{},188synthetic_functions: std.ArrayListUnmanaged(Atom.Index) = .{},
189189
190pub const Alignment = types.Alignment;
191
190pub const Segment = struct {192pub 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(), {});
14921494
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 };
20512053
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);
20542056
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}
21382140
...@@ -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; // 64kb2736 const page_size = std.wasm.page_size; // 64kb
2735 // Use the user-provided stack size or else we use 1MB by default2737 // 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-convention2739 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-convention2740 const heap_alignment: Alignment = .@"16"; // wasm's heap alignment as specified by tool-convention
27392741
2740 // Always place the stack at the start by default2742 // Always place the stack at the start by default
2741 // unless the user specified the global-base flag2743 // 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;
27492751
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 02755 // 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);
27622764
2763 // set TLS-related symbols2765 // 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 }
27962798
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 }
28092811
2810 // Setup the max amount of pages2812 // 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 values2956/// Appends a new segment with default field values
2955fn appendDummySegment(wasm: *Wasm) !void {2957fn 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 };
30873089
3088 atom.alignment = 1; // debug sections are always 1-byte-aligned3090 atom.alignment = .@"1"; // debug sections are always 1-byte-aligned
3089 return atom_index;3091 return atom_index;
3090}3092}
30913093
...@@ -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 }
47354737
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-relocated19/// Contains the binary data of an atom, which can be non-relocated
20code: std.ArrayListUnmanaged(u8) = .{},20code: std.ArrayListUnmanaged(u8) = .{},
21/// For code this is 1, for data this is set to the highest value of all segments21/// For code this is 1, for data this is set to the highest value of all segments
22alignment: u32,22alignment: Wasm.Alignment,
23/// Offset into the section where the atom lives, this already accounts23/// Offset into the section where the atom lives, this already accounts
24/// for alignment.24/// for alignment.
25offset: u32,25offset: u32,
...@@ -43,7 +43,7 @@ pub const Index = u32;...@@ -43,7 +43,7 @@ pub const Index = u32;
4343
44/// Represents a default empty wasm `Atom`44/// Represents a default empty wasm `Atom`
45pub const empty: Atom = .{45pub 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");
8const std = @import("std");8const std = @import("std");
9const Wasm = @import("../Wasm.zig");9const Wasm = @import("../Wasm.zig");
10const Symbol = @import("Symbol.zig");10const Symbol = @import("Symbol.zig");
11const Alignment = types.Alignment;
1112
12const Allocator = std.mem.Allocator;13const Allocator = std.mem.Allocator;
13const leb = std.leb;14const 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's90 /// 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 }
9896
99 /// Returns the symbol kind that corresponds to the relocatable section97 /// 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 };
921919
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
984982
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 aligned984 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 }
989987
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};
111111
112pub const Alignment = @import("../../InternPool.zig").Alignment;
113
112pub const Segment = struct {114pub 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 2117 /// The required alignment of the segment, encoded as a power of 2
116 alignment: u32,118 alignment: Alignment,
117 /// Bitfield containing flags for a segment119 /// Bitfield containing flags for a segment
118 flags: u32,120 flags: u32,
119121
src/target.zig+7-6
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const std = @import("std");1const std = @import("std");
2const Type = @import("type.zig").Type;2const Type = @import("type.zig").Type;
3const AddressSpace = std.builtin.AddressSpace;3const AddressSpace = std.builtin.AddressSpace;
4const Alignment = @import("InternPool.zig").Alignment;
45
5pub const ArchOsAbi = struct {6pub 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}
596597
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.
598pub fn defaultFunctionAlignment(target: std.Target) u32 {599pub 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}
607608
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");
9const TypedValue = @import("TypedValue.zig");9const TypedValue = @import("TypedValue.zig");
10const Sema = @import("Sema.zig");10const Sema = @import("Sema.zig");
11const InternPool = @import("InternPool.zig");11const InternPool = @import("InternPool.zig");
12const Alignment = InternPool.Alignment;
1213
13/// Both types and values are canonically represented by a single 32-bit integer14/// 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 or197 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() orelse200 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});
202205
...@@ -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 }
808804
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 }
813809
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 }
838835
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 }
843840
...@@ -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 }
852849
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 };
857854
...@@ -881,36 +878,36 @@ pub const Type = struct {...@@ -881,36 +878,36 @@ pub const Type = struct {
881 };878 };
882879
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 },
903900
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()),
906903
907 // TODO revisit this when we have the concept of the error tag type904 // 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" },
909906
910 // represents machine code; not a pointer907 // 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 else911 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" },
930927
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 .{
936933 .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) },
947944 .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 },
965964
966 // TODO revisit this when we have the concept of the error tag type965 // 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" },
970969
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 },
980979
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) orelse984 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 }
1017998
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;
10281002
1029 const field_align = @as(u32, @intCast(field.abi_align.toByteUnitsOptional() orelse1003 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 resolved1007 // We'll guess "pointer-aligned", if the struct has an
1034 .sema => unreachable, // handled above1008 // 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 field1024 if (val != .none) continue; // comptime field
1058 if (!(field_ty.toType().hasRuntimeBits(mod))) continue;1025 if (!(field_ty.toType().hasRuntimeBits(mod))) continue;
10591026
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 resolved1030 .eager => unreachable, // field type alignment not resolved
1064 .sema => unreachable, // passed to abiAlignmentAdvanced above1031 .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 },
10741041
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 an1045 // We'll guess "pointer-aligned", if the union has an
1079 // underaligned pointer field then some allocations1046 // 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 }
11031070
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;
11191086
1120 const field_align_bytes: u32 = @intCast(field_align.toByteUnitsOptional() orelse1087 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 resolved1092 .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) },
11381108
1139 // values, not types1109 // 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);
12131178
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 }
12201187
...@@ -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 },
13271292
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 };
13611326
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) orelse1405 .sema => |sema| try sema.resolveTypeLayout(ty),
1441 return AbiSizeAdvanced{ .scalar = 0 };1406 .lazy => switch (struct_type.layout) {
14421407 .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 equal1532 // 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 }
15711538
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 }
15761542
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 }
15831549
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,
16771643
1678 .atomic_order => unreachable, // missing call to resolveTypeFields1644 .atomic_order => unreachable,
1679 .atomic_rmw_op => unreachable, // missing call to resolveTypeFields1645 .atomic_rmw_op => unreachable,
1680 .calling_convention => unreachable, // missing call to resolveTypeFields1646 .calling_convention => unreachable,
1681 .address_space => unreachable, // missing call to resolveTypeFields1647 .address_space => unreachable,
1682 .float_mode => unreachable, // missing call to resolveTypeFields1648 .float_mode => unreachable,
1683 .reduce_op => unreachable, // missing call to resolveTypeFields1649 .reduce_op => unreachable,
1684 .call_modifier => unreachable, // missing call to resolveTypeFields1650 .call_modifier => unreachable,
1685 .prefetch_options => unreachable, // missing call to resolveTypeFields1651 .prefetch_options => unreachable,
1686 .export_options => unreachable, // missing call to resolveTypeFields1652 .export_options => unreachable,
1687 .extern_options => unreachable, // missing call to resolveTypeFields1653 .extern_options => unreachable,
1688 .type_info => unreachable, // missing call to resolveTypeFields1654 .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 },
16991663
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,
21442095
2145 else => unreachable,2096 else => unreachable,
...@@ -2214,6 +2165,7 @@ pub const Type = struct {...@@ -2214,6 +2165,7 @@ pub const Type = struct {
22142165
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;
22192171
...@@ -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(),
22452193
...@@ -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 }
25192465 const field_ty = struct_type.field_types.get(ip)[i].toType();
2520 // In this case the struct has no runtime-known fields and2466 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 }
25272470
2528 // In this case the struct has no fields at all and2471 // 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 },
25352478
...@@ -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 with2671 .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 },
27312676
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 }
29842929
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 }
30082938
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 }
30382961
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 }
31153031
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);
31213037
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;
31273043
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 };
31433059
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 },
32023069
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;
32063073
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 }
32133080
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 },
32233090
...@@ -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 {
32643130
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 }
32813144
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 }
33003165
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
3262fn 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 })).scalar526 (try ty.toType().abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar.toByteUnits(0)
527 else527 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 })).scalar530 (try ty.toType().abiSizeAdvanced(mod, .{ .sema = sema })).scalar
531 else531 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 type695 // 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 already799 const struct_type = ip.indexToKey(ty.toIntern()).struct_type;
795 .Extern => unreachable, // Handled in non-packed writeToMemory800 // 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 already936 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 type960 // 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 already1085 // Sema is supposed to have emitted a compile error already for Auto layout structs,
1075 .Extern => unreachable, // Handled by non-packed readFromMemory1086 // 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 = .{