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 @@
11//! All interned objects have both a value and a type.
22//! This data structure is self-contained, with the following exceptions:
3//! * type_struct via Module.Struct.Index
4//! * type_opaque via Module.Namespace.Index and Module.Decl.Index
3//! * Module.Namespace has a pointer to Module.File
4//! * Module.Decl has a pointer to Module.CaptureScope
55
66/// Maps `Key` to `Index`. `Key` objects are not stored anywhere; they are
77/// constructed lazily.
......@@ -39,17 +39,11 @@ allocated_namespaces: std.SegmentedList(Module.Namespace, 0) = .{},
3939/// Same pattern as with `decls_free_list`.
4040namespaces_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
4942/// Some types such as enums, structs, and unions need to store mappings from field names
5043/// to field index, or value to field index. In such cases, they will store the underlying
5144/// field names and values directly, relying on one of these maps, stored separately,
5245/// to provide lookup.
46/// These are not serialized; it is computed upon deserialization.
5347maps: std.ArrayListUnmanaged(FieldMap) = .{},
5448
5549/// Used for finding the index inside `string_bytes`.
......@@ -365,11 +359,264 @@ pub const Key = union(enum) {
365359 namespace: Module.Namespace.Index,
366360 };
367361
368 pub const StructType = extern struct {
369 /// The `none` tag is used to represent a struct with no fields.
370 index: Module.Struct.OptionalIndex,
371 /// May be `none` if the struct has no declarations.
362 /// Although packed structs and non-packed structs are encoded differently,
363 /// this struct is used for both categories since they share some common
364 /// functionality.
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.
372370 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 }
373620 };
374621
375622 pub const AnonStructType = struct {
......@@ -870,7 +1117,6 @@ pub const Key = union(enum) {
8701117 .simple_type,
8711118 .simple_value,
8721119 .opt,
873 .struct_type,
8741120 .undef,
8751121 .err,
8761122 .enum_literal,
......@@ -893,6 +1139,7 @@ pub const Key = union(enum) {
8931139 .enum_type,
8941140 .variable,
8951141 .union_type,
1142 .struct_type,
8961143 => |x| Hash.hash(seed, asBytes(&x.decl)),
8971144
8981145 .int => |int| {
......@@ -969,11 +1216,11 @@ pub const Key = union(enum) {
9691216
9701217 if (child == .u8_type) {
9711218 switch (aggregate.storage) {
972 .bytes => |bytes| for (bytes[0..@as(usize, @intCast(len))]) |byte| {
1219 .bytes => |bytes| for (bytes[0..@intCast(len)]) |byte| {
9731220 std.hash.autoHash(&hasher, KeyTag.int);
9741221 std.hash.autoHash(&hasher, byte);
9751222 },
976 .elems => |elems| for (elems[0..@as(usize, @intCast(len))]) |elem| {
1223 .elems => |elems| for (elems[0..@intCast(len)]) |elem| {
9771224 const elem_key = ip.indexToKey(elem);
9781225 std.hash.autoHash(&hasher, @as(KeyTag, elem_key));
9791226 switch (elem_key) {
......@@ -1123,10 +1370,6 @@ pub const Key = union(enum) {
11231370 const b_info = b.opt;
11241371 return std.meta.eql(a_info, b_info);
11251372 },
1126 .struct_type => |a_info| {
1127 const b_info = b.struct_type;
1128 return std.meta.eql(a_info, b_info);
1129 },
11301373 .un => |a_info| {
11311374 const b_info = b.un;
11321375 return std.meta.eql(a_info, b_info);
......@@ -1298,6 +1541,10 @@ pub const Key = union(enum) {
12981541 const b_info = b.union_type;
12991542 return a_info.decl == b_info.decl;
13001543 },
1544 .struct_type => |a_info| {
1545 const b_info = b.struct_type;
1546 return a_info.decl == b_info.decl;
1547 },
13011548 .aggregate => |a_info| {
13021549 const b_info = b.aggregate;
13031550 if (a_info.ty != b_info.ty) return false;
......@@ -1433,6 +1680,8 @@ pub const Key = union(enum) {
14331680 }
14341681};
14351682
1683pub const RequiresComptime = enum(u2) { no, yes, unknown, wip };
1684
14361685// Unlike `Tag.TypeUnion` which is an encoding, and `Key.UnionType` which is a
14371686// minimal hashmap key, this type is a convenience type that contains info
14381687// needed by semantic analysis.
......@@ -1474,8 +1723,6 @@ pub const UnionType = struct {
14741723 }
14751724 };
14761725
1477 pub const RequiresComptime = enum(u2) { no, yes, unknown, wip };
1478
14791726 pub const Status = enum(u3) {
14801727 none,
14811728 field_types_wip,
......@@ -1814,9 +2061,11 @@ pub const Index = enum(u32) {
18142061 type_enum_nonexhaustive: DataIsExtraIndexOfEnumExplicit,
18152062 simple_type: struct { data: SimpleType },
18162063 type_opaque: struct { data: *Key.OpaqueType },
1817 type_struct: struct { data: Module.Struct.OptionalIndex },
2064 type_struct: struct { data: *Tag.TypeStruct },
18182065 type_struct_ns: struct { data: Module.Namespace.Index },
18192066 type_struct_anon: DataIsExtraIndexOfTypeStructAnon,
2067 type_struct_packed: struct { data: *Tag.TypeStructPacked },
2068 type_struct_packed_inits: struct { data: *Tag.TypeStructPacked },
18202069 type_tuple_anon: DataIsExtraIndexOfTypeStructAnon,
18212070 type_union: struct { data: *Tag.TypeUnion },
18222071 type_function: struct {
......@@ -2241,17 +2490,22 @@ pub const Tag = enum(u8) {
22412490 /// An opaque type.
22422491 /// data is index of Key.OpaqueType in extra.
22432492 type_opaque,
2244 /// A struct type.
2245 /// data is Module.Struct.OptionalIndex
2246 /// The `none` tag is used to represent `@TypeOf(.{})`.
2493 /// A non-packed struct type.
2494 /// data is 0 or extra index of `TypeStruct`.
2495 /// data == 0 represents `@TypeOf(.{})`.
22472496 type_struct,
2248 /// A struct type that has only a namespace; no fields, and there is no
2249 /// Module.Struct object allocated for it.
2497 /// A non-packed struct type that has only a namespace; no fields.
22502498 /// data is Module.Namespace.Index.
22512499 type_struct_ns,
22522500 /// An AnonStructType which stores types, names, and values for fields.
22532501 /// data is extra index of `TypeStructAnon`.
22542502 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,
22552509 /// An AnonStructType which has only types and values for fields.
22562510 /// data is extra index of `TypeStructAnon`.
22572511 type_tuple_anon,
......@@ -2461,9 +2715,10 @@ pub const Tag = enum(u8) {
24612715 .type_enum_nonexhaustive => EnumExplicit,
24622716 .simple_type => unreachable,
24632717 .type_opaque => OpaqueType,
2464 .type_struct => unreachable,
2718 .type_struct => TypeStruct,
24652719 .type_struct_ns => unreachable,
24662720 .type_struct_anon => TypeStructAnon,
2721 .type_struct_packed, .type_struct_packed_inits => TypeStructPacked,
24672722 .type_tuple_anon => TypeStructAnon,
24682723 .type_union => TypeUnion,
24692724 .type_function => TypeFunction,
......@@ -2634,11 +2889,90 @@ pub const Tag = enum(u8) {
26342889 any_aligned_fields: bool,
26352890 layout: std.builtin.Type.ContainerLayout,
26362891 status: UnionType.Status,
2637 requires_comptime: UnionType.RequiresComptime,
2892 requires_comptime: RequiresComptime,
26382893 assumed_runtime_bits: bool,
26392894 _: u21 = 0,
26402895 };
26412896 };
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 };
26422976};
26432977
26442978/// State that is mutable during semantic analysis. This data is not used for
......@@ -2764,20 +3098,26 @@ pub const SimpleValue = enum(u32) {
27643098
27653099/// Stored as a power-of-two, with one special value to indicate none.
27663100pub const Alignment = enum(u6) {
3101 @"1" = 0,
3102 @"2" = 1,
3103 @"4" = 2,
3104 @"8" = 3,
3105 @"16" = 4,
3106 @"32" = 5,
27673107 none = std.math.maxInt(u6),
27683108 _,
27693109
27703110 pub fn toByteUnitsOptional(a: Alignment) ?u64 {
27713111 return switch (a) {
27723112 .none => null,
2773 _ => @as(u64, 1) << @intFromEnum(a),
3113 else => @as(u64, 1) << @intFromEnum(a),
27743114 };
27753115 }
27763116
27773117 pub fn toByteUnits(a: Alignment, default: u64) u64 {
27783118 return switch (a) {
27793119 .none => default,
2780 _ => @as(u64, 1) << @intFromEnum(a),
3120 else => @as(u64, 1) << @intFromEnum(a),
27813121 };
27823122 }
27833123
......@@ -2792,11 +3132,65 @@ pub const Alignment = enum(u6) {
27923132 return fromByteUnits(n);
27933133 }
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
27953148 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);
27973151 return std.math.order(@intFromEnum(lhs), @intFromEnum(rhs));
27983152 }
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
28003194 /// An array of `Alignment` objects existing within the `extra` array.
28013195 /// This type exists to provide a struct with lifetime that is
28023196 /// not invalidated when items are added to the `InternPool`.
......@@ -2811,6 +3205,16 @@ pub const Alignment = enum(u6) {
28113205 return @ptrCast(bytes[0..slice.len]);
28123206 }
28133207 };
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 }
28143218};
28153219
28163220/// 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 {
30653469 ip.limbs.deinit(gpa);
30663470 ip.string_bytes.deinit(gpa);
30673471
3068 ip.structs_free_list.deinit(gpa);
3069 ip.allocated_structs.deinit(gpa);
3070
30713472 ip.decls_free_list.deinit(gpa);
30723473 ip.allocated_decls.deinit(gpa);
30733474
......@@ -3149,24 +3550,43 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
31493550 },
31503551
31513552 .type_opaque => .{ .opaque_type = ip.extraData(Key.OpaqueType, data) },
3152 .type_struct => {
3153 const struct_index: Module.Struct.OptionalIndex = @enumFromInt(data);
3154 const namespace = if (struct_index.unwrap()) |i|
3155 ip.structPtrConst(i).namespace.toOptional()
3156 else
3157 .none;
3158 return .{ .struct_type = .{
3159 .index = struct_index,
3160 .namespace = namespace,
3161 } };
3162 },
3553
3554 .type_struct => .{ .struct_type = if (data == 0) .{
3555 .extra_index = 0,
3556 .namespace = .none,
3557 .decl = .none,
3558 .zir_index = @as(u32, undefined),
3559 .layout = .Auto,
3560 .field_names = .{ .start = 0, .len = 0 },
3561 .field_types = .{ .start = 0, .len = 0 },
3562 .field_inits = .{ .start = 0, .len = 0 },
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
31633570 .type_struct_ns => .{ .struct_type = .{
3164 .index = .none,
3571 .extra_index = 0,
31653572 .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,
31663584 } },
31673585
31683586 .type_struct_anon => .{ .anon_struct_type = extraTypeStructAnon(ip, data) },
31693587 .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) },
31703590 .type_union => .{ .union_type = extraUnionType(ip, data) },
31713591
31723592 .type_enum_auto => {
......@@ -3476,10 +3896,15 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
34763896 const values = ip.extra.items[type_struct_anon.end + fields_len ..][0..fields_len];
34773897 return .{ .aggregate = .{
34783898 .ty = ty,
3479 .storage = .{ .elems = @as([]const Index, @ptrCast(values)) },
3899 .storage = .{ .elems = @ptrCast(values) },
34803900 } };
34813901 },
34823902
3903 .type_struct_packed, .type_struct_packed_inits => {
3904 // a packed struct has a 0-bit backing type
3905 @panic("TODO");
3906 },
3907
34833908 .type_enum_auto,
34843909 .type_enum_explicit,
34853910 .type_union,
......@@ -3490,7 +3915,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
34903915 },
34913916 .bytes => {
34923917 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));
34943919 return .{ .aggregate = .{
34953920 .ty = extra.ty,
34963921 .storage = .{ .bytes = ip.string_bytes.items[@intFromEnum(extra.bytes)..][0..len] },
......@@ -3498,8 +3923,8 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
34983923 },
34993924 .aggregate => {
35003925 const extra = ip.extraDataTrail(Tag.Aggregate, data);
3501 const len = @as(u32, @intCast(ip.aggregateTypeLenIncludingSentinel(extra.data.ty)));
3502 const fields = @as([]const Index, @ptrCast(ip.extra.items[extra.end..][0..len]));
3926 const len: u32 = @intCast(ip.aggregateTypeLenIncludingSentinel(extra.data.ty));
3927 const fields: []const Index = @ptrCast(ip.extra.items[extra.end..][0..len]);
35033928 return .{ .aggregate = .{
35043929 .ty = extra.data.ty,
35053930 .storage = .{ .elems = fields },
......@@ -3603,6 +4028,44 @@ fn extraTypeTupleAnon(ip: *const InternPool, extra_index: u32) Key.AnonStructTyp
36034028 };
36044029}
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
36064069fn extraFuncType(ip: *const InternPool, extra_index: u32) Key.FuncType {
36074070 const type_function = ip.extraDataTrail(Tag.TypeFunction, extra_index);
36084071 var index: usize = type_function.end;
......@@ -3831,8 +4294,9 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
38314294 .error_set_type => |error_set_type| {
38324295 assert(error_set_type.names_map == .none);
38334296 assert(std.sort.isSorted(NullTerminatedString, error_set_type.names.get(ip), {}, NullTerminatedString.indexLessThan));
3834 const names_map = try ip.addMap(gpa);
3835 try addStringsToMap(ip, gpa, names_map, error_set_type.names.get(ip));
4297 const names = error_set_type.names.get(ip);
4298 const names_map = try ip.addMap(gpa, names.len);
4299 addStringsToMap(ip, names_map, names);
38364300 const names_len = error_set_type.names.len;
38374301 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.ErrorSet).Struct.fields.len + names_len);
38384302 ip.items.appendAssumeCapacity(.{
......@@ -3877,21 +4341,8 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
38774341 });
38784342 },
38794343
3880 .struct_type => |struct_type| {
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
4344 .struct_type => unreachable, // use getStructType() instead
38934345 .anon_struct_type => unreachable, // use getAnonStructType() instead
3894
38954346 .union_type => unreachable, // use getUnionType() instead
38964347
38974348 .opaque_type => |opaque_type| {
......@@ -3994,7 +4445,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
39944445 },
39954446 .struct_type => |struct_type| {
39964447 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);
39984449 },
39994450 .union_type => |union_key| {
40004451 const union_type = ip.loadUnionType(union_key);
......@@ -4388,12 +4839,9 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
43884839 assert(ip.typeOf(elem) == child);
43894840 }
43904841 },
4391 .struct_type => |struct_type| {
4392 for (
4393 aggregate.storage.values(),
4394 ip.structPtrUnwrapConst(struct_type.index).?.fields.values(),
4395 ) |elem, field| {
4396 assert(ip.typeOf(elem) == field.ty.toIntern());
4842 .struct_type => |t| {
4843 for (aggregate.storage.values(), t.field_types.get(ip)) |elem, field_ty| {
4844 assert(ip.typeOf(elem) == field_ty);
43974845 }
43984846 },
43994847 .anon_struct_type => |anon_struct_type| {
......@@ -4635,6 +5083,28 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, ini: UnionTypeInit) Allocat
46355083 return @enumFromInt(ip.items.len - 1);
46365084}
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
46385108pub const AnonStructTypeInit = struct {
46395109 types: []const Index,
46405110 /// This may be empty, indicating this is a tuple.
......@@ -4997,10 +5467,10 @@ pub fn getErrorSetType(
49975467 });
49985468 errdefer ip.items.len -= 1;
49995469
5000 const names_map = try ip.addMap(gpa);
5470 const names_map = try ip.addMap(gpa, names.len);
50015471 errdefer _ = ip.maps.pop();
50025472
5003 try addStringsToMap(ip, gpa, names_map, names);
5473 addStringsToMap(ip, names_map, names);
50045474
50055475 return @enumFromInt(ip.items.len - 1);
50065476}
......@@ -5299,19 +5769,9 @@ pub const IncompleteEnumType = struct {
52995769 pub fn addFieldName(
53005770 self: @This(),
53015771 ip: *InternPool,
5302 gpa: Allocator,
53035772 name: NullTerminatedString,
5304 ) Allocator.Error!?u32 {
5305 const map = &ip.maps.items[@intFromEnum(self.names_map)];
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;
5773 ) ?u32 {
5774 return ip.addFieldName(self.names_map, self.names_start, name);
53155775 }
53165776
53175777 /// Returns the already-existing field with the same value, if any.
......@@ -5319,17 +5779,14 @@ pub const IncompleteEnumType = struct {
53195779 pub fn addFieldValue(
53205780 self: @This(),
53215781 ip: *InternPool,
5322 gpa: Allocator,
53235782 value: Index,
5324 ) Allocator.Error!?u32 {
5783 ) ?u32 {
53255784 assert(ip.typeOf(value) == @as(Index, @enumFromInt(ip.extra.items[self.tag_ty_index])));
53265785 const map = &ip.maps.items[@intFromEnum(self.values_map.unwrap().?)];
53275786 const field_index = map.count();
53285787 const indexes = ip.extra.items[self.values_start..][0..field_index];
5329 const adapter: Index.Adapter = .{
5330 .indexes = @as([]const Index, @ptrCast(indexes)),
5331 };
5332 const gop = try map.getOrPutAdapted(gpa, value, adapter);
5788 const adapter: Index.Adapter = .{ .indexes = @ptrCast(indexes) };
5789 const gop = map.getOrPutAssumeCapacityAdapted(value, adapter);
53335790 if (gop.found_existing) return @intCast(gop.index);
53345791 ip.extra.items[self.values_start + field_index] = @intFromEnum(value);
53355792 return null;
......@@ -5370,7 +5827,7 @@ fn getIncompleteEnumAuto(
53705827 const gop = try ip.map.getOrPutAdapted(gpa, enum_type.toKey(), adapter);
53715828 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
53755832 const extra_fields_len: u32 = @typeInfo(EnumAuto).Struct.fields.len;
53765833 try ip.extra.ensureUnusedCapacity(gpa, extra_fields_len + enum_type.fields_len);
......@@ -5390,7 +5847,7 @@ fn getIncompleteEnumAuto(
53905847 });
53915848 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), enum_type.fields_len);
53925849 return .{
5393 .index = @as(Index, @enumFromInt(ip.items.len - 1)),
5850 .index = @enumFromInt(ip.items.len - 1),
53945851 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?,
53955852 .names_map = names_map,
53965853 .names_start = extra_index + extra_fields_len,
......@@ -5412,9 +5869,9 @@ fn getIncompleteEnumExplicit(
54125869 const gop = try ip.map.getOrPutAdapted(gpa, enum_type.toKey(), adapter);
54135870 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);
54165873 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);
54185875 break :m values_map.toOptional();
54195876 };
54205877
......@@ -5441,7 +5898,7 @@ fn getIncompleteEnumExplicit(
54415898 // This is both fields and values (if present).
54425899 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), reserved_len);
54435900 return .{
5444 .index = @as(Index, @enumFromInt(ip.items.len - 1)),
5901 .index = @enumFromInt(ip.items.len - 1),
54455902 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumExplicit, "int_tag_type").?,
54465903 .names_map = names_map,
54475904 .names_start = extra_index + extra_fields_len,
......@@ -5484,8 +5941,8 @@ pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Erro
54845941
54855942 switch (ini.tag_mode) {
54865943 .auto => {
5487 const names_map = try ip.addMap(gpa);
5488 try addStringsToMap(ip, gpa, names_map, ini.names);
5944 const names_map = try ip.addMap(gpa, ini.names.len);
5945 addStringsToMap(ip, names_map, ini.names);
54895946
54905947 const fields_len: u32 = @intCast(ini.names.len);
54915948 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumAuto).Struct.fields.len +
......@@ -5514,12 +5971,12 @@ pub fn finishGetEnum(
55145971 ini: GetEnumInit,
55155972 tag: Tag,
55165973) Allocator.Error!Index {
5517 const names_map = try ip.addMap(gpa);
5518 try addStringsToMap(ip, gpa, names_map, ini.names);
5974 const names_map = try ip.addMap(gpa, ini.names.len);
5975 addStringsToMap(ip, names_map, ini.names);
55195976
55205977 const values_map: OptionalMapIndex = if (ini.values.len == 0) .none else m: {
5521 const values_map = try ip.addMap(gpa);
5522 try addIndexesToMap(ip, gpa, values_map, ini.values);
5978 const values_map = try ip.addMap(gpa, ini.values.len);
5979 addIndexesToMap(ip, values_map, ini.values);
55235980 break :m values_map.toOptional();
55245981 };
55255982 const fields_len: u32 = @intCast(ini.names.len);
......@@ -5553,35 +6010,35 @@ pub fn getAssumeExists(ip: *const InternPool, key: Key) Index {
55536010
55546011fn addStringsToMap(
55556012 ip: *InternPool,
5556 gpa: Allocator,
55576013 map_index: MapIndex,
55586014 strings: []const NullTerminatedString,
5559) Allocator.Error!void {
6015) void {
55606016 const map = &ip.maps.items[@intFromEnum(map_index)];
55616017 const adapter: NullTerminatedString.Adapter = .{ .strings = strings };
55626018 for (strings) |string| {
5563 const gop = try map.getOrPutAdapted(gpa, string, adapter);
6019 const gop = map.getOrPutAssumeCapacityAdapted(string, adapter);
55646020 assert(!gop.found_existing);
55656021 }
55666022}
55676023
55686024fn addIndexesToMap(
55696025 ip: *InternPool,
5570 gpa: Allocator,
55716026 map_index: MapIndex,
55726027 indexes: []const Index,
5573) Allocator.Error!void {
6028) void {
55746029 const map = &ip.maps.items[@intFromEnum(map_index)];
55756030 const adapter: Index.Adapter = .{ .indexes = indexes };
55766031 for (indexes) |index| {
5577 const gop = try map.getOrPutAdapted(gpa, index, adapter);
6032 const gop = map.getOrPutAssumeCapacityAdapted(index, adapter);
55786033 assert(!gop.found_existing);
55796034 }
55806035}
55816036
5582fn addMap(ip: *InternPool, gpa: Allocator) Allocator.Error!MapIndex {
6037fn addMap(ip: *InternPool, gpa: Allocator, cap: usize) Allocator.Error!MapIndex {
55836038 const ptr = try ip.maps.addOne(gpa);
6039 errdefer _ = ip.maps.pop();
55846040 ptr.* = .{};
6041 try ptr.ensureTotalCapacity(gpa, cap);
55856042 return @enumFromInt(ip.maps.items.len - 1);
55866043}
55876044
......@@ -5632,8 +6089,9 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {
56326089 Tag.TypePointer.Flags,
56336090 Tag.TypeFunction.Flags,
56346091 Tag.TypePointer.PackedOffset,
5635 Tag.Variable.Flags,
56366092 Tag.TypeUnion.Flags,
6093 Tag.TypeStruct.Flags,
6094 Tag.Variable.Flags,
56376095 => @bitCast(@field(extra, field.name)),
56386096
56396097 else => @compileError("bad field type: " ++ @typeName(field.type)),
......@@ -5705,6 +6163,7 @@ fn extraDataTrail(ip: *const InternPool, comptime T: type, index: usize) struct
57056163 Tag.TypeFunction.Flags,
57066164 Tag.TypePointer.PackedOffset,
57076165 Tag.TypeUnion.Flags,
6166 Tag.TypeStruct.Flags,
57086167 Tag.Variable.Flags,
57096168 FuncAnalysis,
57106169 => @bitCast(int32),
......@@ -6093,8 +6552,7 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
60936552 const new_elem_ty = switch (ip.indexToKey(new_ty)) {
60946553 inline .array_type, .vector_type => |seq_type| seq_type.child,
60956554 .anon_struct_type => |anon_struct_type| anon_struct_type.types.get(ip)[i],
6096 .struct_type => |struct_type| ip.structPtr(struct_type.index.unwrap().?)
6097 .fields.values()[i].ty.toIntern(),
6555 .struct_type => |struct_type| struct_type.field_types.get(ip)[i],
60986556 else => unreachable,
60996557 };
61006558 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
62066664 } });
62076665}
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
62286667pub fn indexToFuncType(ip: *const InternPool, val: Index) ?Key.FuncType {
62296668 assert(val != .none);
62306669 const tags = ip.items.items(.tag);
......@@ -6337,20 +6776,16 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
63376776 const items_size = (1 + 4) * ip.items.len;
63386777 const extra_size = 4 * ip.extra.items.len;
63396778 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));
63436779 const decls_size = ip.allocated_decls.len * @sizeOf(Module.Decl);
63446780
63456781 // 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
63486784 std.debug.print(
63496785 \\InternPool size: {d} bytes
63506786 \\ {d} items: {d} bytes
63516787 \\ {d} extra: {d} bytes
63526788 \\ {d} limbs: {d} bytes
6353 \\ {d} structs: {d} bytes
63546789 \\ {d} decls: {d} bytes
63556790 \\
63566791 , .{
......@@ -6361,8 +6796,6 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
63616796 extra_size,
63626797 ip.limbs.items.len,
63636798 limbs_size,
6364 ip.allocated_structs.len,
6365 structs_size,
63666799 ip.allocated_decls.len,
63676800 decls_size,
63686801 });
......@@ -6399,17 +6832,40 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
63996832 .type_enum_auto => @sizeOf(EnumAuto),
64006833 .type_opaque => @sizeOf(Key.OpaqueType),
64016834 .type_struct => b: {
6402 const struct_index = @as(Module.Struct.Index, @enumFromInt(data));
6403 const struct_obj = ip.structPtrConst(struct_index);
6404 break :b @sizeOf(Module.Struct) +
6405 @sizeOf(Module.Namespace) +
6406 (struct_obj.fields.count() * @sizeOf(Module.Struct.Field));
6835 const info = ip.extraData(Tag.TypeStruct, data);
6836 var ints: usize = @typeInfo(Tag.TypeStruct).Struct.fields.len;
6837 ints += info.fields_len; // types
6838 if (!info.flags.is_tuple) {
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;
64076853 },
64086854 .type_struct_ns => @sizeOf(Module.Namespace),
64096855 .type_struct_anon => b: {
64106856 const info = ip.extraData(TypeStructAnon, data);
64116857 break :b @sizeOf(TypeStructAnon) + (@sizeOf(u32) * 3 * info.fields_len);
64126858 },
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 },
64136869 .type_tuple_anon => b: {
64146870 const info = ip.extraData(TypeStructAnon, data);
64156871 break :b @sizeOf(TypeStructAnon) + (@sizeOf(u32) * 2 * info.fields_len);
......@@ -6562,6 +7018,8 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
65627018 .type_struct,
65637019 .type_struct_ns,
65647020 .type_struct_anon,
7021 .type_struct_packed,
7022 .type_struct_packed_inits,
65657023 .type_tuple_anon,
65667024 .type_union,
65677025 .type_function,
......@@ -6677,18 +7135,6 @@ pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator)
66777135 try bw.flush();
66787136}
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
66927138pub fn declPtr(ip: *InternPool, index: Module.Decl.Index) *Module.Decl {
66937139 return ip.allocated_decls.at(@intFromEnum(index));
66947140}
......@@ -6701,28 +7147,6 @@ pub fn namespacePtr(ip: *InternPool, index: Module.Namespace.Index) *Module.Name
67017147 return ip.allocated_namespaces.at(@intFromEnum(index));
67027148}
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
67267150pub fn createDecl(
67277151 ip: *InternPool,
67287152 gpa: Allocator,
......@@ -6967,6 +7391,8 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
69677391 .type_struct,
69687392 .type_struct_ns,
69697393 .type_struct_anon,
7394 .type_struct_packed,
7395 .type_struct_packed_inits,
69707396 .type_tuple_anon,
69717397 .type_union,
69727398 .type_function,
......@@ -7056,7 +7482,7 @@ pub fn toEnum(ip: *const InternPool, comptime E: type, i: Index) E {
70567482
70577483pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 {
70587484 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,
70607486 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
70617487 .array_type => |array_type| array_type.len,
70627488 .vector_type => |vector_type| vector_type.len,
......@@ -7066,7 +7492,7 @@ pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 {
70667492
70677493pub fn aggregateTypeLenIncludingSentinel(ip: *const InternPool, ty: Index) u64 {
70687494 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,
70707496 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
70717497 .array_type => |array_type| array_type.len + @intFromBool(array_type.sentinel != .none),
70727498 .vector_type => |vector_type| vector_type.len,
......@@ -7301,6 +7727,8 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois
73017727 .type_struct,
73027728 .type_struct_ns,
73037729 .type_struct_anon,
7730 .type_struct_packed,
7731 .type_struct_packed_inits,
73047732 .type_tuple_anon,
73057733 => .Struct,
73067734
......@@ -7526,6 +7954,40 @@ pub fn resolveBuiltinType(ip: *InternPool, want_index: Index, resolved_index: In
75267954 .data = @intFromEnum(SimpleValue.@"unreachable"),
75277955 });
75287956 } else {
7529 // TODO: add the index to a free-list for reuse
7957 // Here we could add the index to a free-list for reuse, but since
7958 // there is so little garbage created this way it's not worth it.
75307959 }
75317960}
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
105105
106106/// To be eliminated in a future commit by moving more data into InternPool.
107107/// Current uses that must be eliminated:
108/// * Struct comptime_args
109/// * Struct optimized_order
110108/// * comptime pointer mutation
111109/// This memory lives until the Module is destroyed.
112110tmp_hack_arena: std.heap.ArenaAllocator,
......@@ -678,14 +676,10 @@ pub const Decl = struct {
678676
679677 /// If the Decl owns its value and it is a struct, return it,
680678 /// otherwise null.
681 pub fn getOwnedStruct(decl: Decl, mod: *Module) ?*Struct {
682 return mod.structPtrUnwrap(decl.getOwnedStructIndex(mod));
683 }
684
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());
679 pub fn getOwnedStruct(decl: Decl, mod: *Module) ?InternPool.Key.StructType {
680 if (!decl.owns_tv) return null;
681 if (decl.val.ip_index == .none) return null;
682 return mod.typeToStruct(decl.val.toType());
689683 }
690684
691685 /// If the Decl owns its value and it is a union, return it,
......@@ -795,9 +789,10 @@ pub const Decl = struct {
795789 return decl.getExternDecl(mod) != .none;
796790 }
797791
798 pub fn getAlignment(decl: Decl, mod: *Module) u32 {
792 pub fn getAlignment(decl: Decl, mod: *Module) Alignment {
799793 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);
801796 }
802797};
803798
......@@ -806,218 +801,6 @@ pub const EmitH = struct {
806801 fwd_decl: ArrayListUnmanaged(u8) = .{},
807802};
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
1021804pub const DeclAdapter = struct {
1022805 mod: *Module,
1023806
......@@ -2893,20 +2676,10 @@ pub fn namespacePtr(mod: *Module, index: Namespace.Index) *Namespace {
28932676 return mod.intern_pool.namespacePtr(index);
28942677}
28952678
2896pub fn structPtr(mod: *Module, index: Struct.Index) *Struct {
2897 return mod.intern_pool.structPtr(index);
2898}
2899
29002679pub fn namespacePtrUnwrap(mod: *Module, index: Namespace.OptionalIndex) ?*Namespace {
29012680 return mod.namespacePtr(index.unwrap() orelse return null);
29022681}
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
29102683/// Returns true if and only if the Decl is the top level struct associated with a File.
29112684pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool {
29122685 const decl = mod.declPtr(decl_index);
......@@ -3351,11 +3124,11 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void {
33513124
33523125 if (!decl.owns_tv) continue;
33533126
3354 if (decl.getOwnedStruct(mod)) |struct_obj| {
3355 struct_obj.zir_index = inst_map.get(struct_obj.zir_index) orelse {
3127 if (decl.getOwnedStruct(mod)) |struct_type| {
3128 struct_type.setZirIndex(ip, inst_map.get(struct_type.zir_index) orelse {
33563129 try file.deleted_decls.append(gpa, decl_index);
33573130 continue;
3358 };
3131 });
33593132 }
33603133
33613134 if (decl.getOwnedUnion(mod)) |union_type| {
......@@ -3870,36 +3643,16 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
38703643 const new_decl = mod.declPtr(new_decl_index);
38713644 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();
38933646 file.root_decl = new_decl_index.toOptional();
38943647
38953648 new_decl.name = try file.fullyQualifiedName(mod);
3649 new_decl.name_fully_qualified = true;
38963650 new_decl.src_line = 0;
38973651 new_decl.is_pub = true;
38983652 new_decl.is_exported = false;
38993653 new_decl.has_align = false;
39003654 new_decl.has_linksection_or_addrspace = false;
39013655 new_decl.ty = Type.type;
3902 new_decl.val = struct_ty.toValue();
39033656 new_decl.alignment = .none;
39043657 new_decl.@"linksection" = .none;
39053658 new_decl.has_tv = true;
......@@ -3907,75 +3660,76 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
39073660 new_decl.alive = true; // This Decl corresponds to a File and is therefore always alive.
39083661 new_decl.analysis = .in_progress;
39093662 new_decl.generation = mod.generation;
3910 new_decl.name_fully_qualified = true;
39113663
3912 if (file.status == .success_zir) {
3913 assert(file.zir_loaded);
3914 const main_struct_inst = Zir.main_struct_inst;
3915 const struct_obj = mod.structPtr(struct_index);
3916 struct_obj.zir_index = main_struct_inst;
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();
3664 if (file.status != .success_zir) {
3665 new_decl.analysis = .file_failure;
3666 return;
3667 }
3668 assert(file.zir_loaded);
39433669
3944 if (sema.analyzeStructDecl(new_decl, main_struct_inst, struct_index)) |_| {
3945 for (comptime_mutable_decls.items) |decl_index| {
3946 const decl = mod.declPtr(decl_index);
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 }
3670 var sema_arena = std.heap.ArenaAllocator.init(gpa);
3671 defer sema_arena.deinit();
3672 const sema_arena_allocator = sema_arena.allocator();
39543673
3955 if (mod.comp.whole_cache_manifest) |whole_cache_manifest| {
3956 const source = file.getSource(gpa) catch |err| {
3957 try reportRetryableFileError(mod, file, "unable to load source: {s}", .{@errorName(err)});
3958 return error.AnalysisFail;
3959 };
3674 var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);
3675 defer comptime_mutable_decls.deinit();
39603676
3961 const resolved_path = std.fs.path.resolve(
3962 gpa,
3963 if (file.pkg.root_src_directory.path) |pkg_path|
3964 &[_][]const u8{ pkg_path, file.sub_file_path }
3965 else
3966 &[_][]const u8{file.sub_file_path},
3967 ) catch |err| {
3968 try reportRetryableFileError(mod, file, "unable to resolve path: {s}", .{@errorName(err)});
3969 return error.AnalysisFail;
3970 };
3971 errdefer gpa.free(resolved_path);
3677 var sema: Sema = .{
3678 .mod = mod,
3679 .gpa = gpa,
3680 .arena = sema_arena_allocator,
3681 .code = file.zir,
3682 .owner_decl = new_decl,
3683 .owner_decl_index = new_decl_index,
3684 .func_index = .none,
3685 .func_is_naked = false,
3686 .fn_ret_ty = Type.void,
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();
3974 defer mod.comp.whole_cache_manifest_mutex.unlock();
3975 try whole_cache_manifest.addFilePostContents(resolved_path, source.bytes, source.stat);
3976 }
3977 } else {
3978 new_decl.analysis = .file_failure;
3693 const main_struct_inst = Zir.main_struct_inst;
3694 const struct_ty = sema.getStructType(
3695 new_decl_index,
3696 new_namespace_index,
3697 main_struct_inst,
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);
39793733 }
39803734}
39813735
......@@ -4057,12 +3811,12 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
40573811
40583812 if (mod.declIsRoot(decl_index)) {
40593813 const main_struct_inst = Zir.main_struct_inst;
4060 const struct_index = decl.getOwnedStructIndex(mod).unwrap().?;
4061 const struct_obj = mod.structPtr(struct_index);
4062 // This might not have gotten set in `semaFile` if the first time had
4063 // a ZIR failure, so we set it here in case.
4064 struct_obj.zir_index = main_struct_inst;
4065 try sema.analyzeStructDecl(decl, main_struct_inst, struct_index);
3814 const struct_type = decl.getOwnedStruct(mod).?;
3815 assert(struct_type.zir_index == main_struct_inst);
3816 if (true) @panic("TODO");
3817 // why did the code used to have this? I don't see how struct_type could have
3818 // been created already without the analyzeStructDecl logic already called on it.
3819 //try sema.analyzeStructDecl(decl, main_struct_inst, struct_type);
40663820 decl.analysis = .complete;
40673821 decl.generation = mod.generation;
40683822 return false;
......@@ -5241,14 +4995,6 @@ pub fn destroyNamespace(mod: *Module, index: Namespace.Index) void {
52414995 return mod.intern_pool.destroyNamespace(mod.gpa, index);
52424996}
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
52524998pub fn allocateNewDecl(
52534999 mod: *Module,
52545000 namespace: Namespace.Index,
......@@ -6210,10 +5956,10 @@ pub fn ptrType(mod: *Module, info: InternPool.Key.PtrType) Allocator.Error!Type
62105956 // type, we change it to 0 here. If this causes an assertion trip because the
62115957 // pointee type needs to be resolved more, that needs to be done before calling
62125958 // this ptr() function.
6213 if (info.flags.alignment.toByteUnitsOptional()) |info_align| {
6214 if (have_elem_layout and info_align == info.child.toType().abiAlignment(mod)) {
6215 canon_info.flags.alignment = .none;
6216 }
5959 if (info.flags.alignment != .none and have_elem_layout and
5960 info.flags.alignment == info.child.toType().abiAlignment(mod))
5961 {
5962 canon_info.flags.alignment = .none;
62175963 }
62185964
62195965 switch (info.flags.vector_index) {
......@@ -6483,7 +6229,7 @@ pub fn intBitsForValue(mod: *Module, val: Value, sign: bool) u16 {
64836229 return @as(u16, @intCast(big.bitCountTwosComp()));
64846230 },
64856231 .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);
64876233 },
64886234 .lazy_size => |lazy_ty| {
64896235 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
66396385/// * `@TypeOf(.{})`
66406386/// * A struct which has no fields (`struct {}`).
66416387/// * Not a struct.
6642pub fn typeToStruct(mod: *Module, ty: Type) ?*Struct {
6388pub fn typeToStruct(mod: *Module, ty: Type) ?InternPool.Key.StructType {
66436389 if (ty.ip_index == .none) return null;
6644 const struct_index = mod.intern_pool.indexToStructType(ty.toIntern()).unwrap() orelse return null;
6645 return mod.structPtr(struct_index);
6390 return switch (mod.intern_pool.indexToKey(ty.ip_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 };
66466402}
66476403
66486404/// This asserts that the union's enum tag type has been resolved.
66496405pub fn typeToUnion(mod: *Module, ty: Type) ?InternPool.UnionType {
66506406 if (ty.ip_index == .none) return null;
66516407 const ip = &mod.intern_pool;
6652 switch (ip.indexToKey(ty.ip_index)) {
6653 .union_type => |k| return ip.loadUnionType(k),
6654 else => return null,
6655 }
6408 return switch (ip.indexToKey(ty.ip_index)) {
6409 .union_type => |k| ip.loadUnionType(k),
6410 else => null,
6411 };
66566412}
66576413
66586414pub 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]
67416497
67426498pub const UnionLayout = struct {
67436499 abi_size: u64,
6744 abi_align: u32,
6500 abi_align: Alignment,
67456501 most_aligned_field: u32,
67466502 most_aligned_field_size: u64,
67476503 biggest_field: u32,
67486504 payload_size: u64,
6749 payload_align: u32,
6750 tag_align: u32,
6505 payload_align: Alignment,
6506 tag_align: Alignment,
67516507 tag_size: u64,
67526508 padding: u32,
67536509};
......@@ -6759,35 +6515,37 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout {
67596515 var most_aligned_field_size: u64 = undefined;
67606516 var biggest_field: u32 = undefined;
67616517 var payload_size: u64 = 0;
6762 var payload_align: u32 = 0;
6518 var payload_align: Alignment = .@"1";
67636519 for (u.field_types.get(ip), 0..) |field_ty, i| {
67646520 if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
67656521
6766 const field_align = u.fieldAlign(ip, @intCast(i)).toByteUnitsOptional() orelse
6522 const explicit_align = u.fieldAlign(ip, @intCast(i));
6523 const field_align = if (explicit_align != .none)
6524 explicit_align
6525 else
67676526 field_ty.toType().abiAlignment(mod);
67686527 const field_size = field_ty.toType().abiSize(mod);
67696528 if (field_size > payload_size) {
67706529 payload_size = field_size;
67716530 biggest_field = @intCast(i);
67726531 }
6773 if (field_align > payload_align) {
6774 payload_align = @intCast(field_align);
6532 if (field_align.compare(.gte, payload_align)) {
6533 payload_align = field_align;
67756534 most_aligned_field = @intCast(i);
67766535 most_aligned_field_size = field_size;
67776536 }
67786537 }
6779 payload_align = @max(payload_align, 1);
67806538 const have_tag = u.flagsPtr(ip).runtime_tag.hasTag();
67816539 if (!have_tag or !u.enum_tag_ty.toType().hasRuntimeBits(mod)) {
67826540 return .{
6783 .abi_size = std.mem.alignForward(u64, payload_size, payload_align),
6541 .abi_size = payload_align.forward(payload_size),
67846542 .abi_align = payload_align,
67856543 .most_aligned_field = most_aligned_field,
67866544 .most_aligned_field_size = most_aligned_field_size,
67876545 .biggest_field = biggest_field,
67886546 .payload_size = payload_size,
67896547 .payload_align = payload_align,
6790 .tag_align = 0,
6548 .tag_align = .none,
67916549 .tag_size = 0,
67926550 .padding = 0,
67936551 };
......@@ -6795,29 +6553,29 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout {
67956553 // Put the tag before or after the payload depending on which one's
67966554 // alignment is greater.
67976555 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");
67996557 var size: u64 = 0;
68006558 var padding: u32 = undefined;
6801 if (tag_align >= payload_align) {
6559 if (tag_align.compare(.gte, payload_align)) {
68026560 // {Tag, Payload}
68036561 size += tag_size;
6804 size = std.mem.alignForward(u64, size, payload_align);
6562 size = payload_align.forward(size);
68056563 size += payload_size;
68066564 const prev_size = size;
6807 size = std.mem.alignForward(u64, size, tag_align);
6808 padding = @as(u32, @intCast(size - prev_size));
6565 size = tag_align.forward(size);
6566 padding = @intCast(size - prev_size);
68096567 } else {
68106568 // {Payload, Tag}
68116569 size += payload_size;
6812 size = std.mem.alignForward(u64, size, tag_align);
6570 size = tag_align.forward(size);
68136571 size += tag_size;
68146572 const prev_size = size;
6815 size = std.mem.alignForward(u64, size, payload_align);
6816 padding = @as(u32, @intCast(size - prev_size));
6573 size = payload_align.forward(size);
6574 padding = @intCast(size - prev_size);
68176575 }
68186576 return .{
68196577 .abi_size = size,
6820 .abi_align = @max(tag_align, payload_align),
6578 .abi_align = tag_align.max(payload_align),
68216579 .most_aligned_field = most_aligned_field,
68226580 .most_aligned_field_size = most_aligned_field_size,
68236581 .biggest_field = biggest_field,
......@@ -6834,17 +6592,16 @@ pub fn unionAbiSize(mod: *Module, u: InternPool.UnionType) u64 {
68346592}
68356593
68366594/// Returns 0 if the union is represented with 0 bits at runtime.
6837/// TODO: this returns alignment in byte units should should be a u64
6838pub fn unionAbiAlignment(mod: *Module, u: InternPool.UnionType) u32 {
6595pub fn unionAbiAlignment(mod: *Module, u: InternPool.UnionType) Alignment {
68396596 const ip = &mod.intern_pool;
68406597 const have_tag = u.flagsPtr(ip).runtime_tag.hasTag();
6841 var max_align: u32 = 0;
6598 var max_align: Alignment = .none;
68426599 if (have_tag) max_align = u.enum_tag_ty.toType().abiAlignment(mod);
68436600 for (u.field_types.get(ip), 0..) |field_ty, field_index| {
68446601 if (!field_ty.toType().hasRuntimeBits(mod)) continue;
68456602
68466603 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);
68486605 }
68496606 return max_align;
68506607}
......@@ -6852,10 +6609,10 @@ pub fn unionAbiAlignment(mod: *Module, u: InternPool.UnionType) u32 {
68526609/// Returns the field alignment, assuming the union is not packed.
68536610/// Keep implementation in sync with `Sema.unionFieldAlignment`.
68546611/// Prefer to call that function instead of this one during Sema.
6855/// TODO: this returns alignment in byte units should should be a u64
6856pub fn unionFieldNormalAlignment(mod: *Module, u: InternPool.UnionType, field_index: u32) u32 {
6612pub fn unionFieldNormalAlignment(mod: *Module, u: InternPool.UnionType, field_index: u32) Alignment {
68576613 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;
68596616 const field_ty = u.field_types.get(ip)[field_index].toType();
68606617 return field_ty.abiAlignment(mod);
68616618}
......@@ -6866,3 +6623,64 @@ pub fn unionTagFieldIndex(mod: *Module, u: InternPool.UnionType, enum_tag: Value
68666623 const enum_type = ip.indexToKey(u.enum_tag_ty).enum_type;
68676624 return enum_type.tagValueIndex(ip, enum_tag.toIntern());
68686625}
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
22212221 const msg = try sema.errMsg(block, init_src, "value stored in comptime field does not match the default value of the field", .{});
22222222 errdefer msg.destroy(sema.gpa);
22232223
2224 const struct_ty = mod.typeToStruct(container_ty) orelse break :msg msg;
2225 const default_value_src = mod.fieldSrcLoc(struct_ty.owner_decl, .{
2224 const struct_type = mod.typeToStruct(container_ty) orelse break :msg msg;
2225 const default_value_src = mod.fieldSrcLoc(struct_type.decl.unwrap().?, .{
22262226 .index = field_index,
22272227 .range = .value,
22282228 });
......@@ -2504,23 +2504,22 @@ fn analyzeAsAlign(
25042504 const alignment_big = try sema.analyzeAsInt(block, src, air_ref, align_ty, .{
25052505 .needed_comptime_reason = "alignment must be comptime-known",
25062506 });
2507 const alignment: u32 = @intCast(alignment_big); // We coerce to u29 in the prev line.
2508 try sema.validateAlign(block, src, alignment);
2509 return Alignment.fromNonzeroByteUnits(alignment);
2507 return sema.validateAlign(block, src, alignment_big);
25102508}
25112509
25122510fn validateAlign(
25132511 sema: *Sema,
25142512 block: *Block,
25152513 src: LazySrcLoc,
2516 alignment: u32,
2517) !void {
2514 alignment: u64,
2515) !Alignment {
25182516 if (alignment == 0) return sema.fail(block, src, "alignment must be >= 1", .{});
25192517 if (!std.math.isPowerOfTwo(alignment)) {
25202518 return sema.fail(block, src, "alignment value '{d}' is not a power of two", .{
25212519 alignment,
25222520 });
25232521 }
2522 return Alignment.fromNonzeroByteUnits(alignment);
25242523}
25252524
25262525pub fn resolveAlign(
......@@ -2801,26 +2800,26 @@ fn coerceResultPtr(
28012800 }
28022801}
28032802
2804pub fn analyzeStructDecl(
2803pub fn getStructType(
28052804 sema: *Sema,
2806 new_decl: *Decl,
2807 inst: Zir.Inst.Index,
2808 struct_index: Module.Struct.Index,
2809) SemaError!void {
2805 decl: Module.Decl.Index,
2806 namespace: Module.Namespace.Index,
2807 zir_index: Zir.Inst.Index,
2808) !InternPool.Index {
28102809 const mod = sema.mod;
2811 const struct_obj = mod.structPtr(struct_index);
2812 const extended = sema.code.instructions.items(.data)[inst].extended;
2810 const gpa = sema.gpa;
2811 const ip = &mod.intern_pool;
2812 const extended = sema.code.instructions.items(.data)[zir_index].extended;
28132813 assert(extended.opcode == .struct_decl);
28142814 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
28212816 var extra_index: usize = extended.operand;
28222817 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;
28242823 const decls_len = if (small.has_decls_len) blk: {
28252824 const decls_len = sema.code.extra[extra_index];
28262825 extra_index += 1;
......@@ -2837,7 +2836,20 @@ pub fn analyzeStructDecl(
28372836 }
28382837 }
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;
28412853}
28422854
28432855fn zirStructDecl(
......@@ -2847,7 +2859,7 @@ fn zirStructDecl(
28472859 inst: Zir.Inst.Index,
28482860) CompileError!Air.Inst.Ref {
28492861 const mod = sema.mod;
2850 const gpa = sema.gpa;
2862 const ip = &mod.intern_pool;
28512863 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
28522864 const src: LazySrcLoc = if (small.has_src_node) blk: {
28532865 const node_offset: i32 = @bitCast(sema.code.extra[extended.operand]);
......@@ -2874,37 +2886,21 @@ fn zirStructDecl(
28742886 const new_namespace = mod.namespacePtr(new_namespace_index);
28752887 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
28892889 const struct_ty = ty: {
2890 const ty = try mod.intern_pool.get(gpa, .{ .struct_type = .{
2891 .index = struct_index.toOptional(),
2892 .namespace = new_namespace_index.toOptional(),
2893 } });
2890 const ty = try sema.getStructType(new_decl_index, new_namespace_index, inst);
28942891 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);
28962893 break :ty sema.builtin_type_target_index;
28972894 }
28982895 break :ty ty;
28992896 };
29002897 // TODO: figure out InternPool removals for incremental compilation
2901 //errdefer mod.intern_pool.remove(struct_ty);
2898 //errdefer ip.remove(struct_ty);
29022899
29032900 new_decl.ty = Type.type;
29042901 new_decl.val = struct_ty.toValue();
29052902 new_namespace.ty = struct_ty.toType();
29062903
2907 try sema.analyzeStructDecl(new_decl, inst, struct_index);
29082904 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
29092905 try mod.finalizeAnonDecl(new_decl_index);
29102906 return decl_val;
......@@ -3196,7 +3192,7 @@ fn zirEnumDecl(
31963192 extra_index += 1;
31973193
31983194 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| {
32003196 const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy;
32013197 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy;
32023198 const msg = msg: {
......@@ -3227,7 +3223,7 @@ fn zirEnumDecl(
32273223 };
32283224 if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) break :overflow true;
32293225 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| {
32313227 const value_src = mod.fieldSrcLoc(new_decl_index, .{
32323228 .index = field_i,
32333229 .range = .value,
......@@ -3249,7 +3245,7 @@ fn zirEnumDecl(
32493245 else
32503246 try mod.intValue(int_tag_ty, 0);
32513247 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| {
32533249 const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy;
32543250 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy;
32553251 const msg = msg: {
......@@ -4723,10 +4719,11 @@ fn validateStructInit(
47234719 }
47244720
47254721 if (root_msg) |msg| {
4726 if (mod.typeToStruct(struct_ty)) |struct_obj| {
4727 const fqn = try struct_obj.getFullyQualifiedName(mod);
4722 if (mod.typeToStruct(struct_ty)) |struct_type| {
4723 const decl = mod.declPtr(struct_type.decl.unwrap().?);
4724 const fqn = try decl.getFullyQualifiedName(mod);
47284725 try mod.errNoteNonLazy(
4729 struct_obj.srcLoc(mod),
4726 decl.srcLoc(mod),
47304727 msg,
47314728 "struct '{}' declared here",
47324729 .{fqn.fmt(ip)},
......@@ -4853,10 +4850,11 @@ fn validateStructInit(
48534850 }
48544851
48554852 if (root_msg) |msg| {
4856 if (mod.typeToStruct(struct_ty)) |struct_obj| {
4857 const fqn = try struct_obj.getFullyQualifiedName(mod);
4853 if (mod.typeToStruct(struct_ty)) |struct_type| {
4854 const decl = mod.declPtr(struct_type.decl.unwrap().?);
4855 const fqn = try decl.getFullyQualifiedName(mod);
48584856 try mod.errNoteNonLazy(
4859 struct_obj.srcLoc(mod),
4857 decl.srcLoc(mod),
48604858 msg,
48614859 "struct '{}' declared here",
48624860 .{fqn.fmt(ip)},
......@@ -5255,14 +5253,14 @@ fn failWithBadMemberAccess(
52555253fn failWithBadStructFieldAccess(
52565254 sema: *Sema,
52575255 block: *Block,
5258 struct_obj: *Module.Struct,
5256 struct_type: InternPool.Key.StructType,
52595257 field_src: LazySrcLoc,
52605258 field_name: InternPool.NullTerminatedString,
52615259) CompileError {
52625260 const mod = sema.mod;
52635261 const gpa = sema.gpa;
5264
5265 const fqn = try struct_obj.getFullyQualifiedName(mod);
5262 const decl = mod.declPtr(struct_type.decl.unwrap().?);
5263 const fqn = try decl.getFullyQualifiedName(mod);
52665264
52675265 const msg = msg: {
52685266 const msg = try sema.errMsg(
......@@ -5272,7 +5270,7 @@ fn failWithBadStructFieldAccess(
52725270 .{ field_name.fmt(&mod.intern_pool), fqn.fmt(&mod.intern_pool) },
52735271 );
52745272 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", .{});
52765274 break :msg msg;
52775275 };
52785276 return sema.failWithOwnedErrorMsg(block, msg);
......@@ -12953,9 +12951,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1295312951 }
1295412952 },
1295512953 .struct_type => |struct_type| {
12956 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :hf false;
12957 assert(struct_obj.haveFieldTypes());
12958 break :hf struct_obj.fields.contains(field_name);
12954 break :hf struct_type.nameIndex(ip, field_name) != null;
1295912955 },
1296012956 .union_type => |union_type| {
1296112957 const union_obj = ip.loadUnionType(union_type);
......@@ -16907,7 +16903,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1690716903 // calling_convention: CallingConvention,
1690816904 (try mod.enumValueFieldIndex(callconv_ty, @intFromEnum(func_ty_info.cc))).toIntern(),
1690916905 // 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(),
1691116907 // is_generic: bool,
1691216908 Value.makeBool(func_ty_info.is_generic).toIntern(),
1691316909 // is_var_args: bool,
......@@ -17461,7 +17457,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1746117457
1746217458 const alignment = switch (layout) {
1746317459 .Auto, .Extern => try sema.unionFieldAlignment(union_obj, @intCast(i)),
17464 .Packed => 0,
17460 .Packed => .none,
1746517461 };
1746617462
1746717463 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
1747117467 // type: type,
1747217468 field_ty,
1747317469 // alignment: comptime_int,
17474 (try mod.intValue(Type.comptime_int, alignment)).toIntern(),
17470 (try mod.intValue(Type.comptime_int, alignment.toByteUnits(0))).toIntern(),
1747517471 };
1747617472 field_val.* = try mod.intern(.{ .aggregate = .{
1747717473 .ty = union_field_ty.toIntern(),
......@@ -17578,7 +17574,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1757817574 };
1757917575
1758017576 try sema.resolveTypeLayout(ty); // Getting alignment requires type layout
17581 const layout = ty.containerLayout(mod);
1758217577
1758317578 var struct_field_vals: []InternPool.Index = &.{};
1758417579 defer gpa.free(struct_field_vals);
......@@ -17633,7 +17628,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1763317628 // is_comptime: bool,
1763417629 Value.makeBool(is_comptime).toIntern(),
1763517630 // 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(),
1763717632 };
1763817633 struct_field_val.* = try mod.intern(.{ .aggregate = .{
1763917634 .ty = struct_field_ty.toIntern(),
......@@ -17645,14 +17640,13 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1764517640 .struct_type => |s| s,
1764617641 else => unreachable,
1764717642 };
17648 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :fv;
17649 struct_field_vals = try gpa.alloc(InternPool.Index, struct_obj.fields.count());
17650
17651 for (
17652 struct_field_vals,
17653 struct_obj.fields.keys(),
17654 struct_obj.fields.values(),
17655 ) |*field_val, name_nts, field| {
17643 struct_field_vals = try gpa.alloc(InternPool.Index, struct_type.field_types.len);
17644
17645 for (struct_field_vals, 0..) |*field_val, i| {
17646 const name_nts = struct_type.fieldName(ip, i).unwrap().?;
17647 const field_ty = struct_type.field_types.get(ip)[i].toType();
17648 const field_init = struct_type.fieldInit(ip, i);
17649 const field_is_comptime = struct_type.fieldIsComptime(ip, i);
1765617650 // TODO: write something like getCoercedInts to avoid needing to dupe
1765717651 const name = try sema.arena.dupe(u8, ip.stringToSlice(name_nts));
1765817652 const name_val = v: {
......@@ -17677,24 +17671,25 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1767717671 } });
1767817672 };
1767917673
17680 const opt_default_val = if (field.default_val == .none)
17681 null
17682 else
17683 field.default_val.toValue();
17684 const default_val_ptr = try sema.optRefValue(block, field.ty, opt_default_val);
17685 const alignment = field.alignment(mod, layout);
17674 const opt_default_val = if (field_init == .none) null else field_init.toValue();
17675 const default_val_ptr = try sema.optRefValue(block, field_ty, opt_default_val);
17676 const alignment = mod.structFieldAlignment(
17677 struct_type.field_aligns.get(ip)[i],
17678 field_ty,
17679 struct_type.layout,
17680 );
1768617681
1768717682 const struct_field_fields = .{
1768817683 // name: []const u8,
1768917684 name_val,
1769017685 // type: type,
17691 field.ty.toIntern(),
17686 field_ty.toIntern(),
1769217687 // default_value: ?*const anyopaque,
1769317688 default_val_ptr.toIntern(),
1769417689 // is_comptime: bool,
17695 Value.makeBool(field.is_comptime).toIntern(),
17690 Value.makeBool(field_is_comptime).toIntern(),
1769617691 // alignment: comptime_int,
17697 (try mod.intValue(Type.comptime_int, alignment)).toIntern(),
17692 (try mod.intValue(Type.comptime_int, alignment.toByteUnits(0))).toIntern(),
1769817693 };
1769917694 field_val.* = try mod.intern(.{ .aggregate = .{
1770017695 .ty = struct_field_ty.toIntern(),
......@@ -17733,11 +17728,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1773317728
1773417729 const backing_integer_val = try mod.intern(.{ .opt = .{
1773517730 .ty = (try mod.optionalType(.type_type)).toIntern(),
17736 .val = if (layout == .Packed) val: {
17737 const struct_obj = mod.typeToStruct(ty).?;
17738 assert(struct_obj.haveLayout());
17739 assert(struct_obj.backing_int_ty.isInt(mod));
17740 break :val struct_obj.backing_int_ty.toIntern();
17731 .val = if (mod.typeToPackedStruct(ty)) |packed_struct| val: {
17732 assert(packed_struct.backingIntType(ip).toType().isInt(mod));
17733 break :val packed_struct.backingIntType(ip).*;
1774117734 } else .none,
1774217735 } });
1774317736
......@@ -17754,6 +17747,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1775417747 break :t decl.val.toType();
1775517748 };
1775617749
17750 const layout = ty.containerLayout(mod);
17751
1775717752 const field_values = [_]InternPool.Index{
1775817753 // layout: ContainerLayout,
1775917754 (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
1892418919 },
1892518920 else => {},
1892618921 }
18927 const abi_align: u32 = @intCast((try val.getUnsignedIntAdvanced(mod, sema)).?);
18928 try sema.validateAlign(block, align_src, abi_align);
18929 break :blk Alignment.fromByteUnits(abi_align);
18922 const align_bytes = (try val.getUnsignedIntAdvanced(mod, sema)).?;
18923 break :blk try sema.validateAlign(block, align_src, align_bytes);
1893018924 } else .none;
1893118925
1893218926 const address_space: std.builtin.AddressSpace = if (inst_data.flags.has_addrspace) blk: {
......@@ -19291,12 +19285,12 @@ fn finishStructInit(
1929119285 }
1929219286 },
1929319287 .struct_type => |struct_type| {
19294 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
19295 for (struct_obj.fields.values(), 0..) |field, i| {
19288 for (0..struct_type.field_types.len) |i| {
1929619289 if (field_inits[i] != .none) continue;
1929719290
19298 if (field.default_val == .none) {
19299 const field_name = struct_obj.fields.keys()[i];
19291 const field_init = struct_type.field_inits.get(ip)[i];
19292 if (field_init == .none) {
19293 const field_name = struct_type.field_names.get(ip)[i];
1930019294 const template = "missing struct field: {}";
1930119295 const args = .{field_name.fmt(ip)};
1930219296 if (root_msg) |msg| {
......@@ -19305,7 +19299,7 @@ fn finishStructInit(
1930519299 root_msg = try sema.errMsg(block, init_src, template, args);
1930619300 }
1930719301 } else {
19308 field_inits[i] = Air.internedToRef(field.default_val);
19302 field_inits[i] = Air.internedToRef(field_init);
1930919303 }
1931019304 }
1931119305 },
......@@ -19313,10 +19307,11 @@ fn finishStructInit(
1931319307 }
1931419308
1931519309 if (root_msg) |msg| {
19316 if (mod.typeToStruct(struct_ty)) |struct_obj| {
19317 const fqn = try struct_obj.getFullyQualifiedName(mod);
19310 if (mod.typeToStruct(struct_ty)) |struct_type| {
19311 const decl = mod.declPtr(struct_type.decl.unwrap().?);
19312 const fqn = try decl.getFullyQualifiedName(mod);
1931819313 try mod.errNoteNonLazy(
19319 struct_obj.srcLoc(mod),
19314 decl.srcLoc(mod),
1932019315 msg,
1932119316 "struct '{}' declared here",
1932219317 .{fqn.fmt(ip)},
......@@ -19848,10 +19843,10 @@ fn fieldType(
1984819843 return Air.internedToRef(anon_struct.types.get(ip)[field_index]);
1984919844 },
1985019845 .struct_type => |struct_type| {
19851 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
19852 const field = struct_obj.fields.get(field_name) orelse
19853 return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);
19854 return Air.internedToRef(field.ty.toIntern());
19846 const field_index = struct_type.nameIndex(ip, field_name) orelse
19847 return sema.failWithBadStructFieldAccess(block, struct_type, field_src, field_name);
19848 const field_ty = struct_type.field_types.get(ip)[field_index];
19849 return Air.internedToRef(field_ty);
1985519850 },
1985619851 else => unreachable,
1985719852 },
......@@ -20167,14 +20162,14 @@ fn zirReify(
2016720162 .AnyFrame => return sema.failWithUseOfAsync(block, src),
2016820163 .EnumLiteral => return .enum_literal_type,
2016920164 .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;
2017120166 const signedness_val = try union_val.val.toValue().fieldValue(
2017220167 mod,
20173 fields.getIndex(try ip.getOrPutString(gpa, "signedness")).?,
20168 struct_type.nameIndex(ip, try ip.getOrPutString(gpa, "signedness")).?,
2017420169 );
2017520170 const bits_val = try union_val.val.toValue().fieldValue(
2017620171 mod,
20177 fields.getIndex(try ip.getOrPutString(gpa, "bits")).?,
20172 struct_type.nameIndex(ip, try ip.getOrPutString(gpa, "bits")).?,
2017820173 );
2017920174
2018020175 const signedness = mod.toEnum(std.builtin.Signedness, signedness_val);
......@@ -20183,11 +20178,13 @@ fn zirReify(
2018320178 return Air.internedToRef(ty.toIntern());
2018420179 },
2018520180 .Vector => {
20186 const fields = ip.typeOf(union_val.val).toType().structFields(mod);
20187 const len_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20181 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20182 const len_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20183 ip,
2018820184 try ip.getOrPutString(gpa, "len"),
2018920185 ).?);
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,
2019120188 try ip.getOrPutString(gpa, "child"),
2019220189 ).?);
2019320190
......@@ -20203,8 +20200,9 @@ fn zirReify(
2020320200 return Air.internedToRef(ty.toIntern());
2020420201 },
2020520202 .Float => {
20206 const fields = ip.typeOf(union_val.val).toType().structFields(mod);
20207 const bits_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20203 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20204 const bits_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20205 ip,
2020820206 try ip.getOrPutString(gpa, "bits"),
2020920207 ).?);
2021020208
......@@ -20220,29 +20218,37 @@ fn zirReify(
2022020218 return Air.internedToRef(ty.toIntern());
2022120219 },
2022220220 .Pointer => {
20223 const fields = ip.typeOf(union_val.val).toType().structFields(mod);
20224 const size_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20221 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20222 const size_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20223 ip,
2022520224 try ip.getOrPutString(gpa, "size"),
2022620225 ).?);
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,
2022820228 try ip.getOrPutString(gpa, "is_const"),
2022920229 ).?);
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,
2023120232 try ip.getOrPutString(gpa, "is_volatile"),
2023220233 ).?);
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,
2023420236 try ip.getOrPutString(gpa, "alignment"),
2023520237 ).?);
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,
2023720240 try ip.getOrPutString(gpa, "address_space"),
2023820241 ).?);
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,
2024020244 try ip.getOrPutString(gpa, "child"),
2024120245 ).?);
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,
2024320248 try ip.getOrPutString(gpa, "is_allowzero"),
2024420249 ).?);
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,
2024620252 try ip.getOrPutString(gpa, "sentinel"),
2024720253 ).?);
2024820254
......@@ -20322,14 +20328,17 @@ fn zirReify(
2032220328 return Air.internedToRef(ty.toIntern());
2032320329 },
2032420330 .Array => {
20325 const fields = ip.typeOf(union_val.val).toType().structFields(mod);
20326 const len_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20331 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20332 const len_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20333 ip,
2032720334 try ip.getOrPutString(gpa, "len"),
2032820335 ).?);
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,
2033020338 try ip.getOrPutString(gpa, "child"),
2033120339 ).?);
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,
2033320342 try ip.getOrPutString(gpa, "sentinel"),
2033420343 ).?);
2033520344
......@@ -20348,8 +20357,9 @@ fn zirReify(
2034820357 return Air.internedToRef(ty.toIntern());
2034920358 },
2035020359 .Optional => {
20351 const fields = ip.typeOf(union_val.val).toType().structFields(mod);
20352 const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20360 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20361 const child_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20362 ip,
2035320363 try ip.getOrPutString(gpa, "child"),
2035420364 ).?);
2035520365
......@@ -20359,11 +20369,13 @@ fn zirReify(
2035920369 return Air.internedToRef(ty.toIntern());
2036020370 },
2036120371 .ErrorUnion => {
20362 const fields = ip.typeOf(union_val.val).toType().structFields(mod);
20363 const error_set_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20372 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20373 const error_set_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20374 ip,
2036420375 try ip.getOrPutString(gpa, "error_set"),
2036520376 ).?);
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,
2036720379 try ip.getOrPutString(gpa, "payload"),
2036820380 ).?);
2036920381
......@@ -20386,8 +20398,9 @@ fn zirReify(
2038620398 try names.ensureUnusedCapacity(sema.arena, len);
2038720399 for (0..len) |i| {
2038820400 const elem_val = try payload_val.elemValue(mod, i);
20389 const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod);
20390 const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
20401 const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type;
20402 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
20403 ip,
2039120404 try ip.getOrPutString(gpa, "name"),
2039220405 ).?);
2039320406
......@@ -20405,20 +20418,25 @@ fn zirReify(
2040520418 return Air.internedToRef(ty.toIntern());
2040620419 },
2040720420 .Struct => {
20408 const fields = ip.typeOf(union_val.val).toType().structFields(mod);
20409 const layout_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20421 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20422 const layout_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20423 ip,
2041020424 try ip.getOrPutString(gpa, "layout"),
2041120425 ).?);
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,
2041320428 try ip.getOrPutString(gpa, "backing_integer"),
2041420429 ).?);
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,
2041620432 try ip.getOrPutString(gpa, "fields"),
2041720433 ).?);
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,
2041920436 try ip.getOrPutString(gpa, "decls"),
2042020437 ).?);
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,
2042220440 try ip.getOrPutString(gpa, "is_tuple"),
2042320441 ).?);
2042420442
......@@ -20436,17 +20454,21 @@ fn zirReify(
2043620454 return try sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_val, name_strategy, is_tuple_val.toBool());
2043720455 },
2043820456 .Enum => {
20439 const fields = ip.typeOf(union_val.val).toType().structFields(mod);
20440 const tag_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20457 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20458 const tag_type_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20459 ip,
2044120460 try ip.getOrPutString(gpa, "tag_type"),
2044220461 ).?);
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,
2044420464 try ip.getOrPutString(gpa, "fields"),
2044520465 ).?);
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,
2044720468 try ip.getOrPutString(gpa, "decls"),
2044820469 ).?);
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,
2045020472 try ip.getOrPutString(gpa, "is_exhaustive"),
2045120473 ).?);
2045220474
......@@ -20496,11 +20518,13 @@ fn zirReify(
2049620518
2049720519 for (0..fields_len) |field_i| {
2049820520 const elem_val = try fields_val.elemValue(mod, field_i);
20499 const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod);
20500 const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
20521 const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type;
20522 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
20523 ip,
2050120524 try ip.getOrPutString(gpa, "name"),
2050220525 ).?);
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,
2050420528 try ip.getOrPutString(gpa, "value"),
2050520529 ).?);
2050620530
......@@ -20515,7 +20539,7 @@ fn zirReify(
2051520539 });
2051620540 }
2051720541
20518 if (try incomplete_enum.addFieldName(ip, gpa, field_name)) |other_index| {
20542 if (incomplete_enum.addFieldName(ip, field_name)) |other_index| {
2051920543 const msg = msg: {
2052020544 const msg = try sema.errMsg(block, src, "duplicate enum field '{}'", .{
2052120545 field_name.fmt(ip),
......@@ -20528,7 +20552,7 @@ fn zirReify(
2052820552 return sema.failWithOwnedErrorMsg(block, msg);
2052920553 }
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| {
2053220556 const msg = msg: {
2053320557 const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{value_val.fmtValue(Type.comptime_int, mod)});
2053420558 errdefer msg.destroy(gpa);
......@@ -20545,8 +20569,9 @@ fn zirReify(
2054520569 return decl_val;
2054620570 },
2054720571 .Opaque => {
20548 const fields = ip.typeOf(union_val.val).toType().structFields(mod);
20549 const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20572 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20573 const decls_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20574 ip,
2055020575 try ip.getOrPutString(gpa, "decls"),
2055120576 ).?);
2055220577
......@@ -20594,17 +20619,21 @@ fn zirReify(
2059420619 return decl_val;
2059520620 },
2059620621 .Union => {
20597 const fields = ip.typeOf(union_val.val).toType().structFields(mod);
20598 const layout_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20622 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20623 const layout_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20624 ip,
2059920625 try ip.getOrPutString(gpa, "layout"),
2060020626 ).?);
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,
2060220629 try ip.getOrPutString(gpa, "tag_type"),
2060320630 ).?);
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,
2060520633 try ip.getOrPutString(gpa, "fields"),
2060620634 ).?);
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,
2060820637 try ip.getOrPutString(gpa, "decls"),
2060920638 ).?);
2061020639
......@@ -20644,14 +20673,17 @@ fn zirReify(
2064420673
2064520674 for (0..fields_len) |i| {
2064620675 const elem_val = try fields_val.elemValue(mod, i);
20647 const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod);
20648 const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
20676 const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type;
20677 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
20678 ip,
2064920679 try ip.getOrPutString(gpa, "name"),
2065020680 ).?);
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,
2065220683 try ip.getOrPutString(gpa, "type"),
2065320684 ).?);
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,
2065520687 try ip.getOrPutString(gpa, "alignment"),
2065620688 ).?);
2065720689
......@@ -20812,23 +20844,29 @@ fn zirReify(
2081220844 return decl_val;
2081320845 },
2081420846 .Fn => {
20815 const fields = ip.typeOf(union_val.val).toType().structFields(mod);
20816 const calling_convention_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20847 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20848 const calling_convention_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20849 ip,
2081720850 try ip.getOrPutString(gpa, "calling_convention"),
2081820851 ).?);
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,
2082020854 try ip.getOrPutString(gpa, "alignment"),
2082120855 ).?);
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,
2082320858 try ip.getOrPutString(gpa, "is_generic"),
2082420859 ).?);
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,
2082620862 try ip.getOrPutString(gpa, "is_var_args"),
2082720863 ).?);
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,
2082920866 try ip.getOrPutString(gpa, "return_type"),
2083020867 ).?);
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,
2083220870 try ip.getOrPutString(gpa, "params"),
2083320871 ).?);
2083420872
......@@ -20844,15 +20882,9 @@ fn zirReify(
2084420882 }
2084520883
2084620884 const alignment = alignment: {
20847 if (!try sema.intFitsInType(alignment_val, Type.u32, null)) {
20848 return sema.fail(block, src, "alignment must fit in 'u32'", .{});
20849 }
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 }
20885 const alignment = try sema.validateAlign(block, src, alignment_val.toUnsignedInt(mod));
20886 const default = target_util.defaultFunctionAlignment(target);
20887 break :alignment if (alignment == default) .none else alignment;
2085620888 };
2085720889 const return_type = return_type_val.optionalValue(mod) orelse
2085820890 return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{});
......@@ -20863,14 +20895,17 @@ fn zirReify(
2086320895 var noalias_bits: u32 = 0;
2086420896 for (param_types, 0..) |*param_type, i| {
2086520897 const elem_val = try params_val.elemValue(mod, i);
20866 const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod);
20867 const param_is_generic_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
20898 const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type;
20899 const param_is_generic_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
20900 ip,
2086820901 try ip.getOrPutString(gpa, "is_generic"),
2086920902 ).?);
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,
2087120905 try ip.getOrPutString(gpa, "is_noalias"),
2087220906 ).?);
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,
2087420909 try ip.getOrPutString(gpa, "type"),
2087520910 ).?);
2087620911
......@@ -20931,6 +20966,8 @@ fn reifyStruct(
2093120966 .Auto => {},
2093220967 };
2093320968
20969 const fields_len: u32 = @intCast(try sema.usizeCast(block, src, fields_val.sliceLen(mod)));
20970
2093420971 // Because these three things each reference each other, `undefined`
2093520972 // placeholders are used before being set after the struct type gains an
2093620973 // InternPool index.
......@@ -20946,58 +20983,45 @@ fn reifyStruct(
2094620983 mod.abortAnonDecl(new_decl_index);
2094720984 }
2094820985
20949 const new_namespace_index = try mod.createNamespace(.{
20950 .parent = block.namespace.toOptional(),
20951 .ty = undefined,
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 = .{},
20986 const ty = try ip.getStructType(gpa, .{
20987 .decl = new_decl_index,
20988 .namespace = .none,
2096020989 .zir_index = inst,
2096120990 .layout = layout,
20962 .status = .have_field_types,
2096320991 .known_non_opv = false,
20992 .fields_len = fields_len,
20993 .requires_comptime = .unknown,
2096420994 .is_tuple = is_tuple,
20965 .namespace = new_namespace_index,
2096620995 });
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 } });
2097420996 // 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
2097721000 new_decl.ty = Type.type;
20978 new_decl.val = struct_ty.toValue();
20979 new_namespace.ty = struct_ty.toType();
21001 new_decl.val = ty.toValue();
2098021002
2098121003 // Fields
20982 const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod));
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) {
21004 for (0..fields_len) |i| {
2098621005 const elem_val = try fields_val.elemValue(mod, i);
20987 const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod);
20988 const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
21006 const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type;
21007 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21008 ip,
2098921009 try ip.getOrPutString(gpa, "name"),
2099021010 ).?);
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,
2099221013 try ip.getOrPutString(gpa, "type"),
2099321014 ).?);
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,
2099521017 try ip.getOrPutString(gpa, "default_value"),
2099621018 ).?);
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,
2099821021 try ip.getOrPutString(gpa, "is_comptime"),
2099921022 ).?);
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,
2100121025 try ip.getOrPutString(gpa, "alignment"),
2100221026 ).?);
2100321027
......@@ -21033,9 +21057,8 @@ fn reifyStruct(
2103321057 );
2103421058 }
2103521059 }
21036 const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);
21037 if (gop.found_existing) {
21038 // TODO: better source location
21060 if (struct_type.addFieldName(ip, field_name)) |prev_index| {
21061 _ = prev_index; // TODO: better source location
2103921062 return sema.fail(block, src, "duplicate struct field {}", .{field_name.fmt(ip)});
2104021063 }
2104121064
......@@ -21051,13 +21074,11 @@ fn reifyStruct(
2105121074 return sema.fail(block, src, "comptime field without default initialization value", .{});
2105221075 }
2105321076
21054 gop.value_ptr.* = .{
21055 .ty = field_ty,
21056 .abi_align = Alignment.fromByteUnits(abi_align),
21057 .default_val = default_val,
21058 .is_comptime = is_comptime_val.toBool(),
21059 .offset = undefined,
21060 };
21077 struct_type.field_types.get(ip)[i] = field_ty.toIntern();
21078 struct_type.field_aligns.get(ip)[i] = Alignment.fromByteUnits(abi_align);
21079 struct_type.field_inits.get(ip)[i] = default_val;
21080 if (is_comptime_val.toBool())
21081 struct_type.setFieldComptime(ip, i);
2106121082
2106221083 if (field_ty.zigTypeTag(mod) == .Opaque) {
2106321084 const msg = msg: {
......@@ -21079,7 +21100,7 @@ fn reifyStruct(
2107921100 };
2108021101 return sema.failWithOwnedErrorMsg(block, msg);
2108121102 }
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)) {
2108321104 const msg = msg: {
2108421105 const msg = try sema.errMsg(block, src, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
2108521106 errdefer msg.destroy(gpa);
......@@ -21091,7 +21112,7 @@ fn reifyStruct(
2109121112 break :msg msg;
2109221113 };
2109321114 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))) {
2109521116 const msg = msg: {
2109621117 const msg = try sema.errMsg(block, src, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
2109721118 errdefer msg.destroy(gpa);
......@@ -21107,13 +21128,12 @@ fn reifyStruct(
2110721128 }
2110821129
2110921130 if (layout == .Packed) {
21110 struct_obj.status = .layout_wip;
21111
21112 for (struct_obj.fields.values(), 0..) |field, index| {
21113 sema.resolveTypeLayout(field.ty) catch |err| switch (err) {
21131 for (0..struct_type.field_types.len) |index| {
21132 const field_ty = struct_type.field_types.get(ip)[index].toType();
21133 sema.resolveTypeLayout(field_ty) catch |err| switch (err) {
2111421134 error.AnalysisFail => {
2111521135 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", .{});
2111721137 return err;
2111821138 },
2111921139 else => return err,
......@@ -21121,19 +21141,18 @@ fn reifyStruct(
2112121141 }
2112221142
2112321143 var fields_bit_sum: u64 = 0;
21124 for (struct_obj.fields.values()) |field| {
21125 fields_bit_sum += field.ty.bitSize(mod);
21144 for (struct_type.field_types.get(ip)) |field_ty| {
21145 fields_bit_sum += field_ty.toType().bitSize(mod);
2112621146 }
2112721147
21128 if (backing_int_val.optionalValue(mod)) |payload| {
21129 const backing_int_ty = payload.toType();
21148 if (backing_int_val.optionalValue(mod)) |backing_int_ty_val| {
21149 const backing_int_ty = backing_int_ty_val.toType();
2113021150 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();
2113221152 } 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();
2113421155 }
21135
21136 struct_obj.status = .have_layout;
2113721156 }
2113821157
2113921158 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!
2143921458 const is_non_zero = try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize);
2144021459 try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null);
2144121460 }
21442 if (ptr_align > 1) {
21443 const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, ptr_align - 1)).toIntern());
21461 if (ptr_align.compare(.gt, .@"1")) {
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());
2144421464 const remainder = try block.addBinOp(.bit_and, operand_coerced, align_minus_1);
2144521465 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
2144621466 try sema.addSafetyCheck(block, src, is_aligned, .incorrect_alignment);
......@@ -21458,8 +21478,9 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
2145821478 const is_non_zero = try block.addBinOp(.cmp_neq, elem_coerced, .zero_usize);
2145921479 try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null);
2146021480 }
21461 if (ptr_align > 1) {
21462 const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, ptr_align - 1)).toIntern());
21481 if (ptr_align.compare(.gt, .@"1")) {
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());
2146321484 const remainder = try block.addBinOp(.bit_and, elem_coerced, align_minus_1);
2146421485 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
2146521486 try sema.addSafetyCheck(block, src, is_aligned, .incorrect_alignment);
......@@ -21476,12 +21497,19 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
2147621497 return block.addAggregateInit(dest_ty, new_elems);
2147721498}
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 {
2148021508 const mod = sema.mod;
2148121509 const addr = operand_val.toUnsignedInt(mod);
2148221510 if (!ptr_ty.isAllowzeroPtr(mod) and addr == 0)
2148321511 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))
2148521513 return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{ptr_ty.fmt(sema.mod)});
2148621514
2148721515 return switch (ptr_ty.zigTypeTag(mod)) {
......@@ -21795,10 +21823,18 @@ fn ptrCastFull(
2179521823 // TODO: vector index?
2179621824 }
2179721825
21798 const src_align = src_info.flags.alignment.toByteUnitsOptional() orelse src_info.child.toType().abiAlignment(mod);
21799 const dest_align = dest_info.flags.alignment.toByteUnitsOptional() orelse dest_info.child.toType().abiAlignment(mod);
21826 const src_align = if (src_info.flags.alignment != .none)
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
2180021836 if (!flags.align_cast) {
21801 if (dest_align > src_align) {
21837 if (dest_align.compare(.gt, src_align)) {
2180221838 return sema.failWithOwnedErrorMsg(block, msg: {
2180321839 const msg = try sema.errMsg(block, src, "cast increases pointer alignment", .{});
2180421840 errdefer msg.destroy(sema.gpa);
......@@ -21891,10 +21927,13 @@ fn ptrCastFull(
2189121927 if (!dest_ty.ptrAllowsZero(mod) and ptr_val.isNull(mod)) {
2189221928 return sema.fail(block, operand_src, "null pointer casted to type '{}'", .{dest_ty.fmt(mod)});
2189321929 }
21894 if (dest_align > src_align) {
21930 if (dest_align.compare(.gt, src_align)) {
2189521931 if (try ptr_val.getUnsignedIntAdvanced(mod, null)) |addr| {
21896 if (addr % dest_align != 0) {
21897 return sema.fail(block, operand_src, "pointer address 0x{X} is not aligned to {d} bytes", .{ addr, dest_align });
21932 if (!dest_align.check(addr)) {
21933 return sema.fail(block, operand_src, "pointer address 0x{X} is not aligned to {d} bytes", .{
21934 addr,
21935 dest_align.toByteUnitsOptional().?,
21936 });
2189821937 }
2189921938 }
2190021939 }
......@@ -21928,8 +21967,12 @@ fn ptrCastFull(
2192821967 try sema.addSafetyCheck(block, src, ok, .cast_to_null);
2192921968 }
2193021969
21931 if (block.wantSafety() and dest_align > src_align and try sema.typeHasRuntimeBits(dest_info.child.toType())) {
21932 const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, dest_align - 1)).toIntern());
21970 if (block.wantSafety() and
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());
2193321976 const ptr_int = try block.addUnOp(.int_from_ptr, ptr);
2193421977 const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1);
2193521978 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
2228522328 });
2228622329
2228722330 const mod = sema.mod;
22331 const ip = &mod.intern_pool;
2228822332 try sema.resolveTypeLayout(ty);
2228922333 switch (ty.zigTypeTag(mod)) {
2229022334 .Struct => {},
......@@ -22300,7 +22344,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6
2230022344 }
2230122345
2230222346 const field_index = if (ty.isTuple(mod)) blk: {
22303 if (mod.intern_pool.stringEqlSlice(field_name, "len")) {
22347 if (ip.stringEqlSlice(field_name, "len")) {
2230422348 return sema.fail(block, src, "no offset available for 'len' field of tuple", .{});
2230522349 }
2230622350 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
2231322357 switch (ty.containerLayout(mod)) {
2231422358 .Packed => {
2231522359 var bit_sum: u64 = 0;
22316 const fields = ty.structFields(mod);
22317 for (fields.values(), 0..) |field, i| {
22360 const struct_type = ip.indexToKey(ty.toIntern()).struct_type;
22361 for (0..struct_type.field_types.len) |i| {
2231822362 if (i == field_index) {
2231922363 return bit_sum;
2232022364 }
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);
2232222367 } else unreachable;
2232322368 },
2232422369 else => return ty.structFieldOffset(field_index, mod) * 8,
......@@ -23717,8 +23762,8 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
2371723762 return sema.fail(block, src, "TODO handle packed structs/unions with @fieldParentPtr", .{});
2371823763 } else {
2371923764 ptr_ty_data.flags.alignment = blk: {
23720 if (mod.typeToStruct(parent_ty)) |struct_obj| {
23721 break :blk struct_obj.fields.values()[field_index].abi_align;
23765 if (mod.typeToStruct(parent_ty)) |struct_type| {
23766 break :blk struct_type.field_aligns.get(ip)[field_index];
2372223767 } else if (mod.typeToUnion(parent_ty)) |union_obj| {
2372323768 break :blk union_obj.fieldAlign(ip, field_index);
2372423769 } else {
......@@ -24528,13 +24573,9 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
2452824573 if (val.isGenericPoison()) {
2452924574 break :blk null;
2453024575 }
24531 const alignment: u32 = @intCast(val.toUnsignedInt(mod));
24532 try sema.validateAlign(block, align_src, alignment);
24533 if (alignment == target_util.defaultFunctionAlignment(target)) {
24534 break :blk .none;
24535 } else {
24536 break :blk Alignment.fromNonzeroByteUnits(alignment);
24537 }
24576 const alignment = try sema.validateAlign(block, align_src, val.toUnsignedInt(mod));
24577 const default = target_util.defaultFunctionAlignment(target);
24578 break :blk if (alignment == default) .none else alignment;
2453824579 } else if (extra.data.bits.has_align_ref) blk: {
2453924580 const align_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
2454024581 extra_index += 1;
......@@ -24546,13 +24587,9 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
2454624587 },
2454724588 else => |e| return e,
2454824589 };
24549 const alignment: u32 = @intCast(align_tv.val.toUnsignedInt(mod));
24550 try sema.validateAlign(block, align_src, alignment);
24551 if (alignment == target_util.defaultFunctionAlignment(target)) {
24552 break :blk .none;
24553 } else {
24554 break :blk Alignment.fromNonzeroByteUnits(alignment);
24555 }
24590 const alignment = try sema.validateAlign(block, align_src, align_tv.val.toUnsignedInt(mod));
24591 const default = target_util.defaultFunctionAlignment(target);
24592 break :blk if (alignment == default) .none else alignment;
2455624593 } else .none;
2455724594
2455824595 const @"addrspace": ?std.builtin.AddressSpace = if (extra.data.bits.has_addrspace_body) blk: {
......@@ -25237,16 +25274,17 @@ fn explainWhyTypeIsComptimeInner(
2523725274 .Struct => {
2523825275 if ((try type_set.getOrPut(sema.gpa, ty.toIntern())).found_existing) return;
2523925276
25240 if (mod.typeToStruct(ty)) |struct_obj| {
25241 for (struct_obj.fields.values(), 0..) |field, i| {
25242 const field_src_loc = mod.fieldSrcLoc(struct_obj.owner_decl, .{
25277 if (mod.typeToStruct(ty)) |struct_type| {
25278 for (0..struct_type.field_types.len) |i| {
25279 const field_ty = struct_type.field_types.get(ip)[i].toType();
25280 const field_src_loc = mod.fieldSrcLoc(struct_type.decl.unwrap().?, .{
2524325281 .index = i,
2524425282 .range = .type,
2524525283 });
2524625284
25247 if (try sema.typeRequiresComptime(field.ty)) {
25285 if (try sema.typeRequiresComptime(field_ty)) {
2524825286 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);
2525025288 }
2525125289 }
2525225290 }
......@@ -26297,13 +26335,12 @@ fn fieldCallBind(
2629726335 switch (concrete_ty.zigTypeTag(mod)) {
2629826336 .Struct => {
2629926337 try sema.resolveTypeFields(concrete_ty);
26300 if (mod.typeToStruct(concrete_ty)) |struct_obj| {
26301 const field_index_usize = struct_obj.fields.getIndex(field_name) orelse
26338 if (mod.typeToStruct(concrete_ty)) |struct_type| {
26339 const field_index = struct_type.nameIndex(ip, field_name) orelse
2630226340 break :find_field;
26303 const field_index: u32 = @intCast(field_index_usize);
26304 const field = struct_obj.fields.values()[field_index];
26341 const field_ty = struct_type.field_types.get(ip)[field_index].toType();
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);
2630726344 } else if (concrete_ty.isTuple(mod)) {
2630826345 if (ip.stringEqlSlice(field_name, "len")) {
2630926346 return .{ .direct = try mod.intRef(Type.usize, concrete_ty.structFieldCount(mod)) };
......@@ -26526,13 +26563,14 @@ fn structFieldPtr(
2652626563 initializing: bool,
2652726564) CompileError!Air.Inst.Ref {
2652826565 const mod = sema.mod;
26566 const ip = &mod.intern_pool;
2652926567 assert(struct_ty.zigTypeTag(mod) == .Struct);
2653026568
2653126569 try sema.resolveTypeFields(struct_ty);
2653226570 try sema.resolveStructLayout(struct_ty);
2653326571
2653426572 if (struct_ty.isTuple(mod)) {
26535 if (mod.intern_pool.stringEqlSlice(field_name, "len")) {
26573 if (ip.stringEqlSlice(field_name, "len")) {
2653626574 const len_inst = try mod.intRef(Type.usize, struct_ty.structFieldCount(mod));
2653726575 return sema.analyzeRef(block, src, len_inst);
2653826576 }
......@@ -26543,11 +26581,10 @@ fn structFieldPtr(
2654326581 return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing);
2654426582 }
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) orelse
26549 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name);
26550 const field_index: u32 = @intCast(field_index_big);
26586 const field_index = struct_type.nameIndex(ip, field_name) orelse
26587 return sema.failWithBadStructFieldAccess(block, struct_type, field_name_src, field_name);
2655126588
2655226589 return sema.structFieldPtrByIndex(block, src, struct_ptr, field_index, field_name_src, struct_ty, initializing);
2655326590}
......@@ -26563,17 +26600,18 @@ fn structFieldPtrByIndex(
2656326600 initializing: bool,
2656426601) CompileError!Air.Inst.Ref {
2656526602 const mod = sema.mod;
26603 const ip = &mod.intern_pool;
2656626604 if (struct_ty.isAnonStruct(mod)) {
2656726605 return sema.tupleFieldPtr(block, src, struct_ptr, field_src, field_index, initializing);
2656826606 }
2656926607
26570 const struct_obj = mod.typeToStruct(struct_ty).?;
26571 const field = struct_obj.fields.values()[field_index];
26608 const struct_type = mod.typeToStruct(struct_ty).?;
26609 const field_ty = struct_type.field_types.get(ip)[field_index];
2657226610 const struct_ptr_ty = sema.typeOf(struct_ptr);
2657326611 const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(mod);
2657426612
2657526613 var ptr_ty_data: InternPool.Key.PtrType = .{
26576 .child = field.ty.toIntern(),
26614 .child = field_ty,
2657726615 .flags = .{
2657826616 .is_const = struct_ptr_ty_info.flags.is_const,
2657926617 .is_volatile = struct_ptr_ty_info.flags.is_volatile,
......@@ -26583,20 +26621,23 @@ fn structFieldPtrByIndex(
2658326621
2658426622 const target = mod.getTarget();
2658526623
26586 const parent_align = struct_ptr_ty_info.flags.alignment.toByteUnitsOptional() orelse
26624 const parent_align = if (struct_ptr_ty_info.flags.alignment != .none)
26625 struct_ptr_ty_info.flags.alignment
26626 else
2658726627 try sema.typeAbiAlignment(struct_ptr_ty_info.child.toType());
2658826628
26589 if (struct_obj.layout == .Packed) {
26629 if (struct_type.layout == .Packed) {
2659026630 comptime assert(Type.packed_struct_layout_version == 2);
2659126631
2659226632 var running_bits: u16 = 0;
26593 for (struct_obj.fields.values(), 0..) |f, i| {
26594 if (!(try sema.typeHasRuntimeBits(f.ty))) continue;
26633 for (0..struct_type.field_types.len) |i| {
26634 const f_ty = struct_type.field_types.get(ip)[i].toType();
26635 if (!(try sema.typeHasRuntimeBits(f_ty))) continue;
2659526636
2659626637 if (i == field_index) {
2659726638 ptr_ty_data.packed_offset.bit_offset = running_bits;
2659826639 }
26599 running_bits += @intCast(f.ty.bitSize(mod));
26640 running_bits += @intCast(f_ty.bitSize(mod));
2660026641 }
2660126642 ptr_ty_data.packed_offset.host_size = (running_bits + 7) / 8;
2660226643
......@@ -26607,7 +26648,7 @@ fn structFieldPtrByIndex(
2660726648 ptr_ty_data.packed_offset.bit_offset += struct_ptr_ty_info.packed_offset.bit_offset;
2660826649 }
2660926650
26610 ptr_ty_data.flags.alignment = Alignment.fromByteUnits(parent_align);
26651 ptr_ty_data.flags.alignment = parent_align;
2661126652
2661226653 // If the field happens to be byte-aligned, simplify the pointer type.
2661326654 // The pointee type bit size must match its ABI byte size so that loads and stores
......@@ -26617,38 +26658,43 @@ fn structFieldPtrByIndex(
2661726658 // targets before adding the necessary complications to this code. This will not
2661826659 // cause miscompilations; it only means the field pointer uses bit masking when it
2661926660 // might not be strictly necessary.
26620 if (parent_align != 0 and ptr_ty_data.packed_offset.bit_offset % 8 == 0 and
26661 if (parent_align != .none and ptr_ty_data.packed_offset.bit_offset % 8 == 0 and
2662126662 target.cpu.arch.endian() == .Little)
2662226663 {
2662326664 const elem_size_bytes = ptr_ty_data.child.toType().abiSize(mod);
2662426665 const elem_size_bits = ptr_ty_data.child.toType().bitSize(mod);
2662526666 if (elem_size_bytes * 8 == elem_size_bits) {
2662626667 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().?));
2662826669 assert(new_align != .none);
2662926670 ptr_ty_data.flags.alignment = new_align;
2663026671 ptr_ty_data.packed_offset = .{ .host_size = 0, .bit_offset = 0 };
2663126672 }
2663226673 }
26633 } else if (struct_obj.layout == .Extern) {
26674 } else if (struct_type.layout == .Extern) {
2663426675 // For extern structs, field aligment might be bigger than type's natural alignment. Eg, in
2663526676 // `extern struct { x: u32, y: u16 }` the second field is aligned as u32.
2663626677 const field_offset = struct_ty.structFieldOffset(field_index, mod);
26637 ptr_ty_data.flags.alignment = Alignment.fromByteUnits(
26638 if (parent_align == 0) 0 else std.math.gcd(field_offset, parent_align),
26639 );
26678 ptr_ty_data.flags.alignment = if (parent_align == .none)
26679 .none
26680 else
26681 @enumFromInt(@min(@intFromEnum(parent_align), @ctz(field_offset)));
2664026682 } else {
2664126683 // Our alignment is capped at the field alignment
26642 const field_align = try sema.structFieldAlignment(field, struct_obj.layout);
26643 ptr_ty_data.flags.alignment = Alignment.fromByteUnits(@min(field_align, parent_align));
26684 const field_align = try sema.structFieldAlignment(
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);
2664426690 }
2664526691
2664626692 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)) {
2664926695 const val = try mod.intern(.{ .ptr = .{
2665026696 .ty = ptr_field_ty.toIntern(),
26651 .addr = .{ .comptime_field = field.default_val },
26697 .addr = .{ .comptime_field = struct_type.field_inits.get(ip)[field_index] },
2665226698 } });
2665326699 return Air.internedToRef(val);
2665426700 }
......@@ -26678,33 +26724,33 @@ fn structFieldVal(
2667826724 struct_ty: Type,
2667926725) CompileError!Air.Inst.Ref {
2668026726 const mod = sema.mod;
26727 const ip = &mod.intern_pool;
2668126728 assert(struct_ty.zigTypeTag(mod) == .Struct);
2668226729
2668326730 try sema.resolveTypeFields(struct_ty);
26684 switch (mod.intern_pool.indexToKey(struct_ty.toIntern())) {
26731 switch (ip.indexToKey(struct_ty.toIntern())) {
2668526732 .struct_type => |struct_type| {
26686 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
26687 if (struct_obj.is_tuple) 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];
26733 if (struct_type.isTuple(ip))
26734 return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty);
2669326735
26694 if (field.is_comptime) {
26695 return Air.internedToRef(field.default_val);
26736 const field_index = struct_type.nameIndex(ip, field_name) orelse
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]);
2669626740 }
2669726741
26742 const field_ty = struct_type.field_types.get(ip)[field_index].toType();
26743
2669826744 if (try sema.resolveMaybeUndefVal(struct_byval)) |struct_val| {
26699 if (struct_val.isUndef(mod)) return mod.undefRef(field.ty);
26700 if ((try sema.typeHasOnePossibleValue(field.ty))) |opv| {
26745 if (struct_val.isUndef(mod)) return mod.undefRef(field_ty);
26746 if ((try sema.typeHasOnePossibleValue(field_ty))) |opv| {
2670126747 return Air.internedToRef(opv.toIntern());
2670226748 }
2670326749 return Air.internedToRef((try struct_val.fieldValue(mod, field_index)).toIntern());
2670426750 }
2670526751
2670626752 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);
2670826754 },
2670926755 .anon_struct_type => |anon_struct| {
2671026756 if (anon_struct.names.len == 0) {
......@@ -26823,9 +26869,12 @@ fn unionFieldPtr(
2682326869 .is_volatile = union_ptr_info.flags.is_volatile,
2682426870 .address_space = union_ptr_info.flags.address_space,
2682526871 .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);
2682726876 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);
2682926878 } else union_ptr_info.flags.alignment,
2683026879 },
2683126880 .packed_offset = union_ptr_info.packed_offset,
......@@ -28266,7 +28315,7 @@ const InMemoryCoercionResult = union(enum) {
2826628315 ptr_qualifiers: Qualifiers,
2826728316 ptr_allowzero: Pair,
2826828317 ptr_bit_range: BitRange,
28269 ptr_alignment: IntPair,
28318 ptr_alignment: AlignPair,
2827028319 double_ptr_to_anyopaque: Pair,
2827128320 slice_to_anyopaque: Pair,
2827228321
......@@ -28312,6 +28361,11 @@ const InMemoryCoercionResult = union(enum) {
2831228361 wanted: u64,
2831328362 };
2831428363
28364 const AlignPair = struct {
28365 actual: Alignment,
28366 wanted: Alignment,
28367 };
28368
2831528369 const Size = struct {
2831628370 actual: std.builtin.Type.Pointer.Size,
2831728371 wanted: std.builtin.Type.Pointer.Size,
......@@ -29133,13 +29187,17 @@ fn coerceInMemoryAllowedPtrs(
2913329187 if (src_info.flags.alignment != .none or dest_info.flags.alignment != .none or
2913429188 dest_info.child != src_info.child)
2913529189 {
29136 const src_align = src_info.flags.alignment.toByteUnitsOptional() orelse
29190 const src_align = if (src_info.flags.alignment != .none)
29191 src_info.flags.alignment
29192 else
2913729193 src_info.child.toType().abiAlignment(mod);
2913829194
29139 const dest_align = dest_info.flags.alignment.toByteUnitsOptional() orelse
29195 const dest_align = if (dest_info.flags.alignment != .none)
29196 dest_info.flags.alignment
29197 else
2914029198 dest_info.child.toType().abiAlignment(mod);
2914129199
29142 if (dest_align > src_align) {
29200 if (dest_align.compare(.gt, src_align)) {
2914329201 return InMemoryCoercionResult{ .ptr_alignment = .{
2914429202 .actual = src_align,
2914529203 .wanted = dest_align,
......@@ -30378,13 +30436,17 @@ fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_resul
3037830436 if (inst_info.flags.alignment == .none and dest_info.flags.alignment == .none) return true;
3037930437 if (len0) return true;
3038030438
30381 const inst_align = inst_info.flags.alignment.toByteUnitsOptional() orelse
30439 const inst_align = if (inst_info.flags.alignment != .none)
30440 inst_info.flags.alignment
30441 else
3038230442 inst_info.child.toType().abiAlignment(mod);
3038330443
30384 const dest_align = dest_info.flags.alignment.toByteUnitsOptional() orelse
30444 const dest_align = if (dest_info.flags.alignment != .none)
30445 dest_info.flags.alignment
30446 else
3038530447 dest_info.child.toType().abiAlignment(mod);
3038630448
30387 if (dest_align > inst_align) {
30449 if (dest_align.compare(.gt, inst_align)) {
3038830450 in_memory_result.* = .{ .ptr_alignment = .{
3038930451 .actual = inst_align,
3039030452 .wanted = dest_align,
......@@ -30598,7 +30660,7 @@ fn coerceAnonStructToUnion(
3059830660 else
3059930661 .{ .count = anon_struct_type.names.len },
3060030662 .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);
3060230664 break :name if (field_names.len == 1)
3060330665 .{ .name = field_names[0] }
3060430666 else
......@@ -30869,8 +30931,8 @@ fn coerceTupleToStruct(
3086930931 return sema.coerceTupleToTuple(block, struct_ty, inst, inst_src);
3087030932 }
3087130933
30872 const fields = struct_ty.structFields(mod);
30873 const field_vals = try sema.arena.alloc(InternPool.Index, fields.count());
30934 const struct_type = mod.typeToStruct(struct_ty).?;
30935 const field_vals = try sema.arena.alloc(InternPool.Index, struct_type.field_types.len);
3087430936 const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len);
3087530937 @memset(field_refs, .none);
3087630938
......@@ -30878,10 +30940,7 @@ fn coerceTupleToStruct(
3087830940 var runtime_src: ?LazySrcLoc = null;
3087930941 const field_count = switch (ip.indexToKey(inst_ty.toIntern())) {
3088030942 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
30881 .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj|
30882 struct_obj.fields.count()
30883 else
30884 0,
30943 .struct_type => |s| s.field_types.len,
3088530944 else => unreachable,
3088630945 };
3088730946 for (0..field_count) |field_index_usize| {
......@@ -30893,22 +30952,23 @@ fn coerceTupleToStruct(
3089330952 anon_struct_type.names.get(ip)[field_i]
3089430953 else
3089530954 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],
3089730956 else => unreachable,
3089830957 };
3089930958 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();
3090130960 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);
3090330962 field_refs[field_index] = coerced;
30904 if (field.is_comptime) {
30963 if (struct_type.comptime_bits.getBit(ip, field_index)) {
3090530964 const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse {
3090630965 return sema.failWithNeededComptime(block, field_src, .{
3090730966 .needed_comptime_reason = "value stored in comptime field must be comptime-known",
3090830967 });
3090930968 };
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)) {
3091230972 return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i);
3091330973 }
3091430974 }
......@@ -30928,10 +30988,10 @@ fn coerceTupleToStruct(
3092830988 for (field_refs, 0..) |*field_ref, i| {
3092930989 if (field_ref.* != .none) continue;
3093030990
30931 const field_name = fields.keys()[i];
30932 const field = fields.values()[i];
30991 const field_name = struct_type.field_names.get(ip)[i];
30992 const field_default_val = struct_type.field_inits.get(ip)[i];
3093330993 const field_src = inst_src; // TODO better source location
30934 if (field.default_val == .none) {
30994 if (field_default_val == .none) {
3093530995 const template = "missing struct field: {}";
3093630996 const args = .{field_name.fmt(ip)};
3093730997 if (root_msg) |msg| {
......@@ -30942,9 +31002,9 @@ fn coerceTupleToStruct(
3094231002 continue;
3094331003 }
3094431004 if (runtime_src == null) {
30945 field_vals[i] = field.default_val;
31005 field_vals[i] = field_default_val;
3094631006 } else {
30947 field_ref.* = Air.internedToRef(field.default_val);
31007 field_ref.* = Air.internedToRef(field_default_val);
3094831008 }
3094931009 }
3095031010
......@@ -30980,10 +31040,7 @@ fn coerceTupleToTuple(
3098031040 const ip = &mod.intern_pool;
3098131041 const dest_field_count = switch (ip.indexToKey(tuple_ty.toIntern())) {
3098231042 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
30983 .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj|
30984 struct_obj.fields.count()
30985 else
30986 0,
31043 .struct_type => |struct_type| struct_type.field_types.len,
3098731044 else => unreachable,
3098831045 };
3098931046 const field_vals = try sema.arena.alloc(InternPool.Index, dest_field_count);
......@@ -30993,10 +31050,7 @@ fn coerceTupleToTuple(
3099331050 const inst_ty = sema.typeOf(inst);
3099431051 const src_field_count = switch (ip.indexToKey(inst_ty.toIntern())) {
3099531052 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
30996 .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj|
30997 struct_obj.fields.count()
30998 else
30999 0,
31053 .struct_type => |struct_type| struct_type.field_types.len,
3100031054 else => unreachable,
3100131055 };
3100231056 if (src_field_count > dest_field_count) return error.NotCoercible;
......@@ -31011,7 +31065,7 @@ fn coerceTupleToTuple(
3101131065 anon_struct_type.names.get(ip)[field_i]
3101231066 else
3101331067 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],
3101531069 else => unreachable,
3101631070 };
3101731071
......@@ -31019,20 +31073,20 @@ fn coerceTupleToTuple(
3101931073 return sema.fail(block, field_src, "cannot assign to 'len' field of tuple", .{});
3102031074
3102131075 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(),
31023 .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.values()[field_index_usize].ty,
31076 .anon_struct_type => |anon_struct_type| anon_struct_type.types.get(ip)[field_index_usize],
31077 .struct_type => |struct_type| struct_type.field_types.get(ip)[field_index_usize],
3102431078 else => unreachable,
3102531079 };
3102631080 const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {
3102731081 .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],
3102931083 else => unreachable,
3103031084 };
3103131085
3103231086 const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_src);
3103331087
3103431088 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);
3103631090 field_refs[field_index] = coerced;
3103731091 if (default_val != .none) {
3103831092 const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse {
......@@ -31041,7 +31095,7 @@ fn coerceTupleToTuple(
3104131095 });
3104231096 };
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)) {
3104531099 return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i);
3104631100 }
3104731101 }
......@@ -31063,7 +31117,7 @@ fn coerceTupleToTuple(
3106331117
3106431118 const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {
3106531119 .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],
3106731121 else => unreachable,
3106831122 };
3106931123
......@@ -33181,12 +33235,17 @@ fn resolvePeerTypesInner(
3318133235 }
3318233236
3318333237 // Note that the align can be always non-zero; Module.ptrType will canonicalize it
33184 ptr_info.flags.alignment = Alignment.fromByteUnits(@min(
33185 ptr_info.flags.alignment.toByteUnitsOptional() orelse
33238 ptr_info.flags.alignment = InternPool.Alignment.min(
33239 if (ptr_info.flags.alignment != .none)
33240 ptr_info.flags.alignment
33241 else
3318633242 ptr_info.child.toType().abiAlignment(mod),
33187 peer_info.flags.alignment.toByteUnitsOptional() orelse
33243
33244 if (peer_info.flags.alignment != .none)
33245 peer_info.flags.alignment
33246 else
3318833247 peer_info.child.toType().abiAlignment(mod),
33189 ));
33248 );
3319033249 if (ptr_info.flags.address_space != peer_info.flags.address_space) {
3319133250 return .{ .conflict = .{
3319233251 .peer_idx_a = first_idx,
......@@ -33260,12 +33319,17 @@ fn resolvePeerTypesInner(
3326033319 } };
3326133320
3326233321 // Note that the align can be always non-zero; Type.ptr will canonicalize it
33263 ptr_info.flags.alignment = Alignment.fromByteUnits(@min(
33264 ptr_info.flags.alignment.toByteUnitsOptional() orelse
33322 ptr_info.flags.alignment = Alignment.min(
33323 if (ptr_info.flags.alignment != .none)
33324 ptr_info.flags.alignment
33325 else
3326533326 ptr_info.child.toType().abiAlignment(mod),
33266 peer_info.flags.alignment.toByteUnitsOptional() orelse
33327
33328 if (peer_info.flags.alignment != .none)
33329 peer_info.flags.alignment
33330 else
3326733331 peer_info.child.toType().abiAlignment(mod),
33268 ));
33332 );
3326933333
3327033334 if (ptr_info.flags.address_space != peer_info.flags.address_space) {
3327133335 return generic_err;
......@@ -34191,103 +34255,117 @@ pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void {
3419134255}
3419234256
3419334257fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
34194 const mod = sema.mod;
3419534258 try sema.resolveTypeFields(ty);
34196 if (mod.typeToStruct(ty)) |struct_obj| {
34197 switch (struct_obj.status) {
34198 .none, .have_field_types => {},
34199 .field_types_wip, .layout_wip => {
34200 const msg = try Module.ErrorMsg.create(
34201 sema.gpa,
34202 struct_obj.srcLoc(mod),
34203 "struct '{}' depends on itself",
34204 .{ty.fmt(mod)},
34205 );
34206 return sema.failWithOwnedErrorMsg(null, msg);
34259
34260 const mod = sema.mod;
34261 const ip = &mod.intern_pool;
34262 const struct_type = mod.typeToStruct(ty) orelse return;
34263
34264 if (struct_type.haveLayout(ip))
34265 return;
34266
34267 if (struct_type.layout == .Packed) {
34268 try semaBackingIntType(mod, struct_type);
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;
3420734295 },
34208 .have_layout, .fully_resolved_wip, .fully_resolved => return,
34209 }
34210 const prev_status = struct_obj.status;
34211 errdefer if (struct_obj.status == .layout_wip) {
34212 struct_obj.status = prev_status;
34296 else => return err,
3421334297 };
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;
34216 for (struct_obj.fields.values(), 0..) |field, i| {
34217 sema.resolveTypeLayout(field.ty) catch |err| switch (err) {
34218 error.AnalysisFail => {
34219 const msg = sema.err orelse return err;
34220 try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{});
34221 return err;
34222 },
34223 else => return err,
34224 };
34225 }
34305 if (struct_type.flagsPtr(ip).assumed_runtime_bits and !(try sema.typeHasRuntimeBits(ty))) {
34306 const msg = try Module.ErrorMsg.create(
34307 sema.gpa,
34308 mod.declPtr(struct_type.decl.unwrap().?).srcLoc(mod),
34309 "struct layout depends on it having runtime bits",
34310 .{},
34311 );
34312 return sema.failWithOwnedErrorMsg(null, msg);
34313 }
3422634314
34227 if (struct_obj.layout == .Packed) {
34228 try semaBackingIntType(mod, struct_obj);
34315 if (struct_type.hasReorderedFields(ip)) {
34316 for (sizes, struct_type.runtime_order.get(ip), 0..) |size, *ro, i| {
34317 ro.* = if (size != 0) @enumFromInt(i) else .omitted;
3422934318 }
3423034319
34231 struct_obj.status = .have_layout;
34232 _ = try sema.typeRequiresComptime(ty);
34320 const RuntimeOrder = InternPool.Key.StructType.RuntimeOrder;
3423334321
34234 if (struct_obj.assumed_runtime_bits and !(try sema.typeHasRuntimeBits(ty))) {
34235 const msg = try Module.ErrorMsg.create(
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 }
34322 const AlignSortContext = struct {
34323 aligns: []const Alignment,
3424334324
34244 if (struct_obj.layout == .Auto and !struct_obj.is_tuple and
34245 mod.backendSupportsFeature(.field_reordering))
34246 {
34247 const optimized_order = try mod.tmp_hack_arena.allocator().alloc(u32, struct_obj.fields.count());
34248
34249 for (struct_obj.fields.values(), 0..) |field, i| {
34250 optimized_order[i] = if (try sema.typeHasRuntimeBits(field.ty))
34251 @intCast(i)
34252 else
34253 Module.Struct.omitted_field;
34325 fn lessThan(ctx: @This(), a: RuntimeOrder, b: RuntimeOrder) bool {
34326 if (a == .omitted) return false;
34327 if (b == .omitted) return true;
34328 const a_align = ctx.aligns[@intFromEnum(a)];
34329 const b_align = ctx.aligns[@intFromEnum(b)];
34330 return a_align.compare(.gt, b_align);
3425434331 }
34332 };
34333 mem.sortUnstable(RuntimeOrder, struct_type.runtime_order.get(ip), AlignSortContext{
34334 .aligns = aligns,
34335 }, AlignSortContext.lessThan);
34336 }
3425534337
34256 const AlignSortContext = struct {
34257 struct_obj: *Module.Struct,
34258 sema: *Sema,
34259
34260 fn lessThan(ctx: @This(), a: u32, b: u32) bool {
34261 const m = ctx.sema.mod;
34262 if (a == Module.Struct.omitted_field) return false;
34263 if (b == Module.Struct.omitted_field) return true;
34264 return ctx.struct_obj.fields.values()[a].ty.abiAlignment(m) >
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 }
34338 // Calculate size, alignment, and field offsets.
34339 const offsets = struct_type.offsets.get(ip);
34340 var it = struct_type.iterateRuntimeOrder(ip);
34341 var offset: u64 = 0;
34342 var big_align: Alignment = .none;
34343 while (it.next()) |i| {
34344 big_align = big_align.max(aligns[i]);
34345 offsets[i] = @intCast(aligns[i].forward(offset));
34346 offset = offsets[i] + sizes[i];
3427434347 }
34275 // otherwise it's a tuple; no need to resolve anything
34348 struct_type.size(ip).* = @intCast(big_align.forward(offset));
34349 const flags = struct_type.flagsPtr(ip);
34350 flags.alignment = big_align;
34351 flags.layout_resolved = true;
3427634352}
3427734353
34278fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!void {
34354fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) CompileError!void {
3427934355 const gpa = mod.gpa;
34356 const ip = &mod.intern_pool;
3428034357
3428134358 var fields_bit_sum: u64 = 0;
34282 for (struct_obj.fields.values()) |field| {
34283 fields_bit_sum += field.ty.bitSize(mod);
34359 for (0..struct_type.field_types.len) |i| {
34360 const field_ty = struct_type.field_types.get(ip)[i].toType();
34361 fields_bit_sum += field_ty.bitSize(mod);
3428434362 }
3428534363
34286 const decl_index = struct_obj.owner_decl;
34364 const decl_index = struct_type.decl.unwrap().?;
3428734365 const decl = mod.declPtr(decl_index);
3428834366
34289 const zir = mod.namespacePtr(struct_obj.namespace).file_scope.zir;
34290 const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended;
34367 const zir = mod.namespacePtr(struct_type.namespace.unwrap().?).file_scope.zir;
34368 const extended = zir.instructions.items(.data)[struct_type.zir_index].extended;
3429134369 assert(extended.opcode == .struct_decl);
3429234370 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
3429334371
......@@ -34326,7 +34404,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi
3432634404 .parent = null,
3432734405 .sema = &sema,
3432834406 .src_decl = decl_index,
34329 .namespace = struct_obj.namespace,
34407 .namespace = struct_type.namespace.unwrap() orelse decl.src_namespace,
3433034408 .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
3433134409 .instructions = .{},
3433234410 .inlining = null,
......@@ -34341,13 +34419,13 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi
3434134419 break :blk try sema.resolveType(&block, backing_int_src, backing_int_ref);
3434234420 } else {
3434334421 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);
3434534423 break :blk try sema.analyzeAsType(&block, backing_int_src, ty_ref);
3434634424 }
3434734425 };
3434834426
3434934427 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();
3435134429 for (comptime_mutable_decls.items) |ct_decl_index| {
3435234430 const ct_decl = mod.declPtr(ct_decl_index);
3435334431 _ = try ct_decl.internValue(mod);
......@@ -34374,7 +34452,8 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi
3437434452 .parent = null,
3437534453 .sema = &sema,
3437634454 .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,
3437834457 .wip_capture_scope = undefined,
3437934458 .instructions = .{},
3438034459 .inlining = null,
......@@ -34382,7 +34461,8 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi
3438234461 };
3438334462 return sema.fail(&block, LazySrcLoc.nodeOffset(0), "size of packed struct '{d}' exceeds maximum bit width of 65535", .{fields_bit_sum});
3438434463 }
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();
3438634466 }
3438734467}
3438834468
......@@ -34532,30 +34612,20 @@ fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void {
3453234612 try sema.resolveStructLayout(ty);
3453334613
3453434614 const mod = sema.mod;
34535 try sema.resolveTypeFields(ty);
34536 const struct_obj = mod.typeToStruct(ty).?;
34615 const ip = &mod.intern_pool;
34616 const struct_type = mod.typeToStruct(ty).?;
3453734617
34538 switch (struct_obj.status) {
34539 .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},
34540 .fully_resolved_wip, .fully_resolved => return,
34541 }
34618 if (struct_type.setFullyResolved(ip)) return;
34619 errdefer struct_type.clearFullyResolved(ip);
3454234620
34543 {
34544 // After we have resolve struct layout we have to go over the fields again to
34545 // make sure pointer fields get their child types resolved as well.
34546 // See also similar code for unions.
34547 const prev_status = struct_obj.status;
34548 errdefer struct_obj.status = prev_status;
34621 // After we have resolve struct layout we have to go over the fields again to
34622 // make sure pointer fields get their child types resolved as well.
34623 // See also similar code for unions.
3454934624
34550 struct_obj.status = .fully_resolved_wip;
34551 for (struct_obj.fields.values()) |field| {
34552 try sema.resolveTypeFully(field.ty);
34553 }
34554 struct_obj.status = .fully_resolved;
34625 for (0..struct_type.field_types.len) |i| {
34626 const field_ty = struct_type.field_types.get(ip)[i].toType();
34627 try sema.resolveTypeFully(field_ty);
3455534628 }
34556
34557 // And let's not forget comptime-only status.
34558 _ = try sema.typeRequiresComptime(ty);
3455934629}
3456034630
3456134631fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void {
......@@ -34591,8 +34661,10 @@ fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void {
3459134661
3459234662pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void {
3459334663 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) {
3459634668 .var_args_param_type => unreachable,
3459734669
3459834670 .none => unreachable,
......@@ -34673,20 +34745,15 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void {
3467334745 .empty_struct => unreachable,
3467434746 .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)]) {
3467734749 .type_struct,
3467834750 .type_struct_ns,
34679 .type_union,
34680 .simple_type,
34681 => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
34682 .struct_type => |struct_type| {
34683 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return;
34684 try sema.resolveTypeFieldsStruct(ty, struct_obj);
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 },
34751 .type_struct_packed,
34752 .type_struct_packed_inits,
34753 => try sema.resolveTypeFieldsStruct(ty_ip, ip.indexToKey(ty_ip).struct_type),
34754
34755 .type_union => try sema.resolveTypeFieldsUnion(ty_ip.toType(), ip.indexToKey(ty_ip).union_type),
34756 .simple_type => try sema.resolveSimpleType(ip.indexToKey(ty_ip).simple_type),
3469034757 else => {},
3469134758 },
3469234759 }
......@@ -34716,43 +34783,44 @@ fn resolveSimpleType(sema: *Sema, simple_type: InternPool.SimpleType) CompileErr
3471634783
3471734784fn resolveTypeFieldsStruct(
3471834785 sema: *Sema,
34719 ty: Type,
34720 struct_obj: *Module.Struct,
34786 ty: InternPool.Index,
34787 struct_type: InternPool.Key.StructType,
3472134788) 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) {
3472334795 .file_failure,
3472434796 .dependency_failure,
3472534797 .sema_failure,
3472634798 .sema_failure_retryable,
3472734799 => {
3472834800 sema.owner_decl.analysis = .dependency_failure;
34729 sema.owner_decl.generation = sema.mod.generation;
34801 sema.owner_decl.generation = mod.generation;
3473034802 return error.AnalysisFail;
3473134803 },
3473234804 else => {},
3473334805 }
34734 switch (struct_obj.status) {
34735 .none => {},
34736 .field_types_wip => {
34737 const msg = try Module.ErrorMsg.create(
34738 sema.gpa,
34739 struct_obj.srcLoc(sema.mod),
34740 "struct '{}' depends on itself",
34741 .{ty.fmt(sema.mod)},
34742 );
34743 return sema.failWithOwnedErrorMsg(null, msg);
34744 },
34745 .have_field_types,
34746 .have_layout,
34747 .layout_wip,
34748 .fully_resolved_wip,
34749 .fully_resolved,
34750 => return,
34806
34807 if (struct_type.haveFieldTypes(ip))
34808 return;
34809
34810 if (struct_type.flagsPtr(ip).field_types_wip) {
34811 const msg = try Module.ErrorMsg.create(
34812 sema.gpa,
34813 mod.declPtr(owner_decl).srcLoc(mod),
34814 "struct '{}' depends on itself",
34815 .{ty.toType().fmt(mod)},
34816 );
34817 return sema.failWithOwnedErrorMsg(null, msg);
3475134818 }
3475234819
34753 struct_obj.status = .field_types_wip;
34754 errdefer struct_obj.status = .none;
34755 try semaStructFields(sema.mod, struct_obj);
34820 struct_type.flagsPtr(ip).field_types_wip = true;
34821 errdefer struct_type.flagsPtr(ip).field_types_wip = false;
34822
34823 try semaStructFields(mod, sema.arena, struct_type);
3475634824}
3475734825
3475834826fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Key.UnionType) CompileError!void {
......@@ -34936,12 +35004,19 @@ fn resolveInferredErrorSetTy(
3493635004 }
3493735005}
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 {
3494035012 const gpa = mod.gpa;
3494135013 const ip = &mod.intern_pool;
34942 const decl_index = struct_obj.owner_decl;
34943 const zir = mod.namespacePtr(struct_obj.namespace).file_scope.zir;
34944 const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended;
35014 const decl_index = struct_type.decl.unwrap() orelse return;
35015 const decl = mod.declPtr(decl_index);
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;
3494535020 assert(extended.opcode == .struct_decl);
3494635021 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
3494735022 var extra_index: usize = extended.operand;
......@@ -34977,18 +35052,16 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3497735052 while (decls_it.next()) |_| {}
3497835053 extra_index = decls_it.extra_index;
3497935054
34980 if (fields_len == 0) {
34981 if (struct_obj.layout == .Packed) {
34982 try semaBackingIntType(mod, struct_obj);
34983 }
34984 struct_obj.status = .have_layout;
34985 return;
34986 }
34987
34988 const decl = mod.declPtr(decl_index);
34989
34990 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
34991 defer analysis_arena.deinit();
35055 if (fields_len == 0) switch (struct_type.layout) {
35056 .Packed => {
35057 try semaBackingIntType(mod, struct_type);
35058 return;
35059 },
35060 .Auto, .Extern => {
35061 struct_type.flagsPtr(ip).layout_resolved = true;
35062 return;
35063 },
35064 };
3499235065
3499335066 var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);
3499435067 defer comptime_mutable_decls.deinit();
......@@ -34996,7 +35069,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3499635069 var sema: Sema = .{
3499735070 .mod = mod,
3499835071 .gpa = gpa,
34999 .arena = analysis_arena.allocator(),
35072 .arena = arena,
3500035073 .code = zir,
3500135074 .owner_decl = decl,
3500235075 .owner_decl_index = decl_index,
......@@ -35013,7 +35086,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3501335086 .parent = null,
3501435087 .sema = &sema,
3501535088 .src_decl = decl_index,
35016 .namespace = struct_obj.namespace,
35089 .namespace = namespace_index,
3501735090 .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
3501835091 .instructions = .{},
3501935092 .inlining = null,
......@@ -35021,9 +35094,6 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3502135094 };
3502235095 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
3502735097 const Field = struct {
3502835098 type_body_len: u32 = 0,
3502935099 align_body_len: u32 = 0,
......@@ -35031,7 +35101,9 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3503135101 type_ref: Zir.Inst.Ref = .none,
3503235102 };
3503335103 const fields = try sema.arena.alloc(Field, fields_len);
35104
3503435105 var any_inits = false;
35106 var any_aligned = false;
3503535107
3503635108 {
3503735109 const bits_per_field = 4;
......@@ -35056,9 +35128,11 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3505635128 const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0;
3505735129 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;
3506035134 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]);
3506235136 extra_index += 1;
3506335137 }
3506435138 extra_index += 1; // doc_comment
......@@ -35073,37 +35147,27 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3507335147 extra_index += 1;
3507435148
3507535149 // This string needs to outlive the ZIR code.
35076 const field_name = try ip.getOrPutString(gpa, if (field_name_zir) |s|
35077 s
35078 else
35079 try std.fmt.allocPrint(sema.arena, "{d}", .{field_i}));
35080
35081 const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);
35082 if (gop.found_existing) {
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);
35150 if (opt_field_name_zir) |field_name_zir| {
35151 const field_name = try ip.getOrPutString(gpa, field_name_zir);
35152 if (struct_type.addFieldName(ip, field_name)) |other_index| {
35153 const msg = msg: {
35154 const field_src = mod.fieldSrcLoc(decl_index, .{ .index = field_i }).lazy;
35155 const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{}'", .{field_name.fmt(ip)});
35156 errdefer msg.destroy(gpa);
3508735157
35088 const prev_field_index = struct_obj.fields.getIndex(field_name).?;
35089 const prev_field_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ .index = prev_field_index });
35090 try mod.errNoteNonLazy(prev_field_src, msg, "other field here", .{});
35091 try sema.errNote(&block_scope, src, msg, "struct declared here", .{});
35092 break :msg msg;
35093 };
35094 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35158 const prev_field_src = mod.fieldSrcLoc(decl_index, .{ .index = other_index });
35159 try mod.errNoteNonLazy(prev_field_src, msg, "other field here", .{});
35160 try sema.errNote(&block_scope, src, msg, "struct declared here", .{});
35161 break :msg msg;
35162 };
35163 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35164 }
3509535165 }
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
3510435167 if (has_align) {
3510535168 fields[field_i].align_body_len = zir.extra[extra_index];
3510635169 extra_index += 1;
35170 any_aligned = true;
3510735171 }
3510835172 if (has_init) {
3510935173 fields[field_i].init_body_len = zir.extra[extra_index];
......@@ -35122,7 +35186,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3512235186 if (zir_field.type_ref != .none) {
3512335187 break :ty sema.resolveType(&block_scope, .unneeded, zir_field.type_ref) catch |err| switch (err) {
3512435188 error.NeededSourceLocation => {
35125 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
35189 const ty_src = mod.fieldSrcLoc(decl_index, .{
3512635190 .index = field_i,
3512735191 .range = .type,
3512835192 }).lazy;
......@@ -35135,10 +35199,10 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3513535199 assert(zir_field.type_body_len != 0);
3513635200 const body = zir.extra[extra_index..][0..zir_field.type_body_len];
3513735201 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);
3513935203 break :ty sema.analyzeAsType(&block_scope, .unneeded, ty_ref) catch |err| switch (err) {
3514035204 error.NeededSourceLocation => {
35141 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
35205 const ty_src = mod.fieldSrcLoc(decl_index, .{
3514235206 .index = field_i,
3514335207 .range = .type,
3514435208 }).lazy;
......@@ -35152,12 +35216,11 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3515235216 return error.GenericPoison;
3515335217 }
3515435218
35155 const field = &struct_obj.fields.values()[field_i];
35156 field.ty = field_ty;
35219 struct_type.field_types.get(ip)[field_i] = field_ty.toIntern();
3515735220
3515835221 if (field_ty.zigTypeTag(mod) == .Opaque) {
3515935222 const msg = msg: {
35160 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
35223 const ty_src = mod.fieldSrcLoc(decl_index, .{
3516135224 .index = field_i,
3516235225 .range = .type,
3516335226 }).lazy;
......@@ -35171,7 +35234,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3517135234 }
3517235235 if (field_ty.zigTypeTag(mod) == .NoReturn) {
3517335236 const msg = msg: {
35174 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
35237 const ty_src = mod.fieldSrcLoc(decl_index, .{
3517535238 .index = field_i,
3517635239 .range = .type,
3517735240 }).lazy;
......@@ -35183,45 +35246,49 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3518335246 };
3518435247 return sema.failWithOwnedErrorMsg(&block_scope, msg);
3518535248 }
35186 if (struct_obj.layout == .Extern and !try sema.validateExternType(field.ty, .struct_field)) {
35187 const msg = msg: {
35188 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
35189 .index = field_i,
35190 .range = .type,
35191 });
35192 const msg = try sema.errMsg(&block_scope, ty_src.lazy, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(mod)});
35193 errdefer msg.destroy(sema.gpa);
35249 switch (struct_type.layout) {
35250 .Extern => if (!try sema.validateExternType(field_ty, .struct_field)) {
35251 const msg = msg: {
35252 const ty_src = mod.fieldSrcLoc(decl_index, .{
35253 .index = field_i,
35254 .range = .type,
35255 });
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);
35198 break :msg msg;
35199 };
35200 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35201 } else if (struct_obj.layout == .Packed and !(validatePackedType(field.ty, mod))) {
35202 const msg = msg: {
35203 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
35204 .index = field_i,
35205 .range = .type,
35206 });
35207 const msg = try sema.errMsg(&block_scope, ty_src.lazy, "packed structs cannot contain fields of type '{}'", .{field.ty.fmt(mod)});
35208 errdefer msg.destroy(sema.gpa);
35261 try sema.addDeclaredHereNote(msg, field_ty);
35262 break :msg msg;
35263 };
35264 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35265 },
35266 .Packed => if (!validatePackedType(field_ty, mod)) {
35267 const msg = msg: {
35268 const ty_src = mod.fieldSrcLoc(decl_index, .{
35269 .index = field_i,
35270 .range = .type,
35271 });
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);
35213 break :msg msg;
35214 };
35215 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35277 try sema.addDeclaredHereNote(msg, field_ty);
35278 break :msg msg;
35279 };
35280 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35281 },
35282 else => {},
3521635283 }
3521735284
3521835285 if (zir_field.align_body_len > 0) {
3521935286 const body = zir.extra[extra_index..][0..zir_field.align_body_len];
3522035287 extra_index += body.len;
35221 const align_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);
35222 field.abi_align = sema.analyzeAsAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) {
35288 const align_ref = try sema.resolveBody(&block_scope, body, zir_index);
35289 const field_align = sema.analyzeAsAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) {
3522335290 error.NeededSourceLocation => {
35224 const align_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
35291 const align_src = mod.fieldSrcLoc(decl_index, .{
3522535292 .index = field_i,
3522635293 .range = .alignment,
3522735294 }).lazy;
......@@ -35230,36 +35297,38 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3523035297 },
3523135298 else => |e| return e,
3523235299 };
35300 struct_type.field_aligns.get(ip)[field_i] = field_align;
3523335301 }
3523435302
3523535303 extra_index += zir_field.init_body_len;
3523635304 }
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
3524035309 if (any_inits) {
3524135310 extra_index = bodies_index;
3524235311 for (fields, 0..) |zir_field, field_i| {
35312 const field_ty = struct_type.field_types.get(ip)[field_i].toType();
3524335313 extra_index += zir_field.type_body_len;
3524435314 extra_index += zir_field.align_body_len;
3524535315 if (zir_field.init_body_len > 0) {
3524635316 const body = zir.extra[extra_index..][0..zir_field.init_body_len];
3524735317 extra_index += body.len;
35248 const init = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);
35249 const field = &struct_obj.fields.values()[field_i];
35250 const coerced = sema.coerce(&block_scope, field.ty, init, .unneeded) catch |err| switch (err) {
35318 const init = try sema.resolveBody(&block_scope, body, zir_index);
35319 const coerced = sema.coerce(&block_scope, field_ty, init, .unneeded) catch |err| switch (err) {
3525135320 error.NeededSourceLocation => {
35252 const init_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
35321 const init_src = mod.fieldSrcLoc(decl_index, .{
3525335322 .index = field_i,
3525435323 .range = .value,
3525535324 }).lazy;
35256 _ = try sema.coerce(&block_scope, field.ty, init, init_src);
35325 _ = try sema.coerce(&block_scope, field_ty, init, init_src);
3525735326 unreachable;
3525835327 },
3525935328 else => |e| return e,
3526035329 };
3526135330 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, .{
3526335332 .index = field_i,
3526435333 .range = .value,
3526535334 }).lazy;
......@@ -35267,7 +35336,8 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3526735336 .needed_comptime_reason = "struct field default value must be comptime-known",
3526835337 });
3526935338 };
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;
3527135341 }
3527235342 }
3527335343 }
......@@ -35275,8 +35345,6 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3527535345 const ct_decl = mod.declPtr(ct_decl_index);
3527635346 _ = try ct_decl.internValue(mod);
3527735347 }
35278
35279 struct_obj.have_field_inits = true;
3528035348}
3528135349
3528235350fn 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 {
3606036128 .type_struct,
3606136129 .type_struct_ns,
3606236130 .type_struct_anon,
36131 .type_struct_packed,
36132 .type_struct_packed_inits,
3606336133 .type_tuple_anon,
3606436134 .type_union,
3606536135 => switch (ip.indexToKey(ty.toIntern())) {
......@@ -36081,41 +36151,46 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3608136151
3608236152 .struct_type => |struct_type| {
3608336153 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 and
36155 if (struct_type.field_types.len == 0) {
36156 // In this case the struct has no fields at all and
3610736157 // therefore has one possible value.
3610836158 return (try mod.intern(.{ .aggregate = .{
3610936159 .ty = ty.toIntern(),
36110 .storage = .{ .elems = field_vals },
36160 .storage = .{ .elems = &.{} },
3611136161 } })).toValue();
3611236162 }
3611336163
36114 // In this case the struct has no fields at all and
36164 const field_vals = try sema.arena.alloc(
36165 InternPool.Index,
36166 struct_type.field_types.len,
36167 );
36168 for (field_vals, 0..) |*field_val, i| {
36169 if (struct_type.comptime_bits.getBit(ip, i)) {
36170 field_val.* = struct_type.field_inits.get(ip)[i];
36171 continue;
36172 }
36173 const field_ty = struct_type.field_types.get(ip)[i].toType();
36174 if (field_ty.eql(ty, mod)) {
36175 const msg = try Module.ErrorMsg.create(
36176 sema.gpa,
36177 mod.declPtr(struct_type.decl.unwrap().?).srcLoc(mod),
36178 "struct '{}' depends on itself",
36179 .{ty.fmt(mod)},
36180 );
36181 try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{});
36182 return sema.failWithOwnedErrorMsg(null, msg);
36183 }
36184 if (try sema.typeHasOnePossibleValue(field_ty)) |field_opv| {
36185 field_val.* = try field_opv.intern(field_ty, mod);
36186 } else return null;
36187 }
36188
36189 // In this case the struct has no runtime-known fields and
3611536190 // therefore has one possible value.
3611636191 return (try mod.intern(.{ .aggregate = .{
3611736192 .ty = ty.toIntern(),
36118 .storage = .{ .elems = &.{} },
36193 .storage = .{ .elems = field_vals },
3611936194 } })).toValue();
3612036195 },
3612136196
......@@ -36574,25 +36649,32 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3657436649 => true,
3657536650 },
3657636651 .struct_type => |struct_type| {
36577 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false;
36578 switch (struct_obj.requires_comptime) {
36652 if (struct_type.layout == .Packed) {
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) {
3657936658 .no, .wip => return false,
3658036659 .yes => return true,
3658136660 .unknown => {
36582 if (struct_obj.status == .field_types_wip)
36661 if (struct_type.flagsPtr(ip).field_types_wip)
3658336662 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;
36588 for (struct_obj.fields.values()) |field| {
36589 if (field.is_comptime) continue;
36590 if (try sema.typeRequiresComptime(field.ty)) {
36591 struct_obj.requires_comptime = .yes;
36668 for (0..struct_type.field_types.len) |i_usize| {
36669 const i: u32 = @intCast(i_usize);
36670 if (struct_type.fieldIsComptime(ip, i)) continue;
36671 const field_ty = struct_type.field_types.get(ip)[i];
36672 if (try sema.typeRequiresComptime(field_ty.toType())) {
36673 struct_type.setRequiresComptime(ip);
3659236674 return true;
3659336675 }
3659436676 }
36595 struct_obj.requires_comptime = .no;
36677 struct_type.flagsPtr(ip).requires_comptime = .no;
3659636678 return false;
3659736679 },
3659836680 }
......@@ -36673,40 +36755,41 @@ fn typeAbiSize(sema: *Sema, ty: Type) !u64 {
3667336755 return ty.abiSize(sema.mod);
3667436756}
3667536757
36676fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!u32 {
36758fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!Alignment {
3667736759 return (try ty.abiAlignmentAdvanced(sema.mod, .{ .sema = sema })).scalar;
3667836760}
3667936761
3668036762/// Not valid to call for packed unions.
3668136763/// Keep implementation in sync with `Module.unionFieldNormalAlignment`.
36682/// TODO: this returns alignment in byte units should should be a u64
36683fn unionFieldAlignment(sema: *Sema, u: InternPool.UnionType, field_index: u32) !u32 {
36764fn unionFieldAlignment(sema: *Sema, u: InternPool.UnionType, field_index: u32) !Alignment {
3668436765 const mod = sema.mod;
3668536766 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;
3668736769 const field_ty = u.field_types.get(ip)[field_index].toType();
36688 if (field_ty.isNoReturn(sema.mod)) return 0;
36689 return @intCast(try sema.typeAbiAlignment(field_ty));
36770 if (field_ty.isNoReturn(sema.mod)) return .none;
36771 return sema.typeAbiAlignment(field_ty);
3669036772}
3669136773
36692/// Keep implementation in sync with `Module.Struct.Field.alignment`.
36693fn structFieldAlignment(sema: *Sema, field: Module.Struct.Field, layout: std.builtin.Type.ContainerLayout) !u32 {
36774/// Keep implementation in sync with `Module.structFieldAlignment`.
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;
3669436783 const mod = sema.mod;
36695 if (field.abi_align.toByteUnitsOptional()) |a| {
36696 assert(layout != .Packed);
36697 return @intCast(a);
36698 }
3669936784 switch (layout) {
36700 .Packed => return 0,
36701 .Auto => if (mod.getTarget().ofmt != .c) {
36702 return sema.typeAbiAlignment(field.ty);
36703 },
36785 .Packed => return .none,
36786 .Auto => if (mod.getTarget().ofmt != .c) return sema.typeAbiAlignment(field_ty),
3670436787 .Extern => {},
3670536788 }
3670636789 // extern
36707 const ty_abi_align = try sema.typeAbiAlignment(field.ty);
36708 if (field.ty.isAbiInt(mod) and field.ty.intInfo(mod).bits >= 128) {
36709 return @max(ty_abi_align, 16);
36790 const ty_abi_align = try sema.typeAbiAlignment(field_ty);
36791 if (field_ty.isAbiInt(mod) and field_ty.intInfo(mod).bits >= 128) {
36792 return ty_abi_align.max(.@"16");
3671036793 }
3671136794 return ty_abi_align;
3671236795}
......@@ -36752,14 +36835,14 @@ fn structFieldIndex(
3675236835 field_src: LazySrcLoc,
3675336836) !u32 {
3675436837 const mod = sema.mod;
36838 const ip = &mod.intern_pool;
3675536839 try sema.resolveTypeFields(struct_ty);
3675636840 if (struct_ty.isAnonStruct(mod)) {
3675736841 return sema.anonStructFieldIndex(block, struct_ty, field_name, field_src);
3675836842 } else {
36759 const struct_obj = mod.typeToStruct(struct_ty).?;
36760 const field_index_usize = struct_obj.fields.getIndex(field_name) orelse
36761 return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);
36762 return @intCast(field_index_usize);
36843 const struct_type = mod.typeToStruct(struct_ty).?;
36844 return struct_type.nameIndex(ip, field_name) orelse
36845 return sema.failWithBadStructFieldAccess(block, struct_type, field_src, field_name);
3676336846 }
3676436847}
3676536848
......@@ -36776,13 +36859,7 @@ fn anonStructFieldIndex(
3677636859 .anon_struct_type => |anon_struct_type| for (anon_struct_type.names.get(ip), 0..) |name, i| {
3677736860 if (name == field_name) return @intCast(i);
3677836861 },
36779 .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| {
36780 for (struct_obj.fields.keys(), 0..) |name, i| {
36781 if (name == field_name) {
36782 return @intCast(i);
36783 }
36784 }
36785 },
36862 .struct_type => |struct_type| if (struct_type.nameIndex(ip, field_name)) |i| return i,
3678636863 else => unreachable,
3678736864 }
3678836865 return sema.fail(block, field_src, "no field named '{}' in anonymous struct '{}'", .{
......@@ -37167,8 +37244,8 @@ fn intFitsInType(
3716737244 // If it is u16 or bigger we know the alignment fits without resolving it.
3716837245 if (info.bits >= max_needed_bits) return true;
3716937246 const x = try sema.typeAbiAlignment(lazy_ty.toType());
37170 if (x == 0) return true;
37171 const actual_needed_bits = std.math.log2(x) + 1 + @intFromBool(info.signedness == .signed);
37247 if (x == .none) return true;
37248 const actual_needed_bits = @as(usize, x.toLog2Units()) + 1 + @intFromBool(info.signedness == .signed);
3717237249 return info.bits >= actual_needed_bits;
3717337250 },
3717437251 .lazy_size => |lazy_ty| {
......@@ -37381,7 +37458,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
3738137458
3738237459 const vector_info: struct {
3738337460 host_size: u16 = 0,
37384 alignment: u32 = 0,
37461 alignment: Alignment = .none,
3738537462 vector_index: VI = .none,
3738637463 } = if (parent_ty.isVector(mod) and ptr_info.flags.size == .One) blk: {
3738737464 const elem_bits = elem_ty.bitSize(mod);
......@@ -37391,7 +37468,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
3739137468
3739237469 break :blk .{
3739337470 .host_size = @intCast(parent_ty.arrayLen(mod)),
37394 .alignment = @intCast(parent_ty.abiAlignment(mod)),
37471 .alignment = parent_ty.abiAlignment(mod),
3739537472 .vector_index = if (offset) |some| @enumFromInt(some) else .runtime,
3739637473 };
3739737474 } else .{};
......@@ -37399,9 +37476,9 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
3739937476 const alignment: Alignment = a: {
3740037477 // Calculate the new pointer alignment.
3740137478 if (ptr_info.flags.alignment == .none) {
37402 if (vector_info.alignment != 0) break :a Alignment.fromNonzeroByteUnits(vector_info.alignment);
37403 // ABI-aligned pointer. Any pointer arithmetic maintains the same ABI-alignedness.
37404 break :a .none;
37479 // In case of an ABI-aligned pointer, any pointer arithmetic
37480 // maintains the same ABI-alignedness.
37481 break :a vector_info.alignment;
3740537482 }
3740637483 // If the addend is not a comptime-known value we can still count on
3740737484 // it being a multiple of the type size.
......@@ -37413,7 +37490,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
3741337490 // non zero).
3741437491 const new_align: Alignment = @enumFromInt(@min(
3741537492 @ctz(addend),
37416 @intFromEnum(ptr_info.flags.alignment),
37493 ptr_info.flags.alignment.toLog2Units(),
3741737494 ));
3741837495 assert(new_align != .none);
3741937496 break :a new_align;
src/TypedValue.zig+1-1
......@@ -432,7 +432,7 @@ fn printAggregate(
432432 if (i != 0) try writer.writeAll(", ");
433433
434434 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(),
436436 .anon_struct_type => |x| if (x.isTuple()) .none else x.names.get(ip)[i].toOptional(),
437437 else => unreachable,
438438 };
src/arch/aarch64/CodeGen.zig+20-27
......@@ -23,6 +23,7 @@ const DW = std.dwarf;
2323const leb128 = std.leb;
2424const log = std.log.scoped(.codegen);
2525const build_options = @import("build_options");
26const Alignment = InternPool.Alignment;
2627
2728const CodeGenError = codegen.CodeGenError;
2829const Result = codegen.Result;
......@@ -506,11 +507,9 @@ fn gen(self: *Self) !void {
506507 // (or w0 when pointer size is 32 bits). As this register
507508 // might get overwritten along the way, save the address
508509 // to the stack.
509 const ptr_bits = self.target.ptrBitWidth();
510 const ptr_bytes = @divExact(ptr_bits, 8);
511510 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
515514 try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = ret_ptr_reg });
516515 self.ret_mcv = MCValue{ .stack_offset = stack_offset };
......@@ -998,11 +997,11 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
998997fn allocMem(
999998 self: *Self,
1000999 abi_size: u32,
1001 abi_align: u32,
1000 abi_align: Alignment,
10021001 maybe_inst: ?Air.Inst.Index,
10031002) !u32 {
10041003 assert(abi_size > 0);
1005 assert(abi_align > 0);
1004 assert(abi_align != .none);
10061005
10071006 // In order to efficiently load and store stack items that fit
10081007 // into registers, we bump up the alignment to the next power of
......@@ -1010,10 +1009,10 @@ fn allocMem(
10101009 const adjusted_align = if (abi_size > 8)
10111010 abi_align
10121011 else
1013 std.math.ceilPowerOfTwoAssert(u32, abi_size);
1012 Alignment.fromNonzeroByteUnits(std.math.ceilPowerOfTwoAssert(u64, abi_size));
10141013
10151014 // 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);
10171016 self.next_stack_offset = offset;
10181017 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 {
15151514 const len = try self.resolveInst(bin_op.rhs);
15161515 const len_ty = self.typeOf(bin_op.rhs);
15171516
1518 const ptr_bits = self.target.ptrBitWidth();
1519 const ptr_bytes = @divExact(ptr_bits, 8);
1520
1521 const stack_offset = try self.allocMem(ptr_bytes * 2, ptr_bytes * 2, inst);
1517 const stack_offset = try self.allocMem(16, .@"8", inst);
15221518 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);
15241520 break :result MCValue{ .stack_offset = stack_offset };
15251521 };
15261522 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 {
32853281 break :result MCValue{ .register = reg };
32863282 }
32873283
3288 const optional_abi_size = @as(u32, @intCast(optional_ty.abiSize(mod)));
3284 const optional_abi_size: u32 = @intCast(optional_ty.abiSize(mod));
32893285 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
32923288 const stack_offset = try self.allocMem(optional_abi_size, optional_abi_align, inst);
32933289 try self.genSetStack(payload_ty, stack_offset, operand);
......@@ -3376,7 +3372,7 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
33763372fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
33773373 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
33783374 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
3379 const ptr_bits = self.target.ptrBitWidth();
3375 const ptr_bits = 64;
33803376 const ptr_bytes = @divExact(ptr_bits, 8);
33813377 const mcv = try self.resolveInst(ty_op.operand);
33823378 switch (mcv) {
......@@ -3400,7 +3396,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
34003396fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {
34013397 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
34023398 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
3403 const ptr_bits = self.target.ptrBitWidth();
3399 const ptr_bits = 64;
34043400 const ptr_bytes = @divExact(ptr_bits, 8);
34053401 const mcv = try self.resolveInst(ty_op.operand);
34063402 switch (mcv) {
......@@ -4272,8 +4268,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
42724268 if (info.return_value == .stack_offset) {
42734269 log.debug("airCall: return by reference", .{});
42744270 const ret_ty = fn_ty.fnReturnType(mod);
4275 const ret_abi_size = @as(u32, @intCast(ret_ty.abiSize(mod)));
4276 const ret_abi_align = @as(u32, @intCast(ret_ty.abiAlignment(mod)));
4271 const ret_abi_size: u32 = @intCast(ret_ty.abiSize(mod));
4272 const ret_abi_align = ret_ty.abiAlignment(mod);
42774273 const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst);
42784274
42794275 const ret_ptr_reg = self.registerAlias(.x0, Type.usize);
......@@ -5939,11 +5935,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
59395935 const ptr = try self.resolveInst(ty_op.operand);
59405936 const array_ty = ptr_ty.childType(mod);
59415937 const array_len = @as(u32, @intCast(array_ty.arrayLen(mod)));
5942
5943 const ptr_bits = self.target.ptrBitWidth();
5944 const ptr_bytes = @divExact(ptr_bits, 8);
5945
5946 const stack_offset = try self.allocMem(ptr_bytes * 2, ptr_bytes * 2, inst);
5938 const ptr_bytes = 8;
5939 const stack_offset = try self.allocMem(ptr_bytes * 2, .@"8", inst);
59475940 try self.genSetStack(ptr_ty, stack_offset, ptr);
59485941 try self.genSetStack(Type.usize, stack_offset - ptr_bytes, .{ .immediate = array_len });
59495942 break :result MCValue{ .stack_offset = stack_offset };
......@@ -6254,7 +6247,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
62546247
62556248 // We round up NCRN only for non-Apple platforms which allow the 16-byte aligned
62566249 // 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()) {
62586251 // Round up NCRN to the next even number
62596252 ncrn += ncrn % 2;
62606253 }
......@@ -6272,7 +6265,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
62726265 ncrn = 8;
62736266 // TODO Apple allows the arguments on the stack to be non-8-byte aligned provided
62746267 // 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") {
62766269 if (nsaa % 8 != 0) {
62776270 nsaa += 8 - (nsaa % 8);
62786271 }
......@@ -6312,10 +6305,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
63126305
63136306 for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| {
63146307 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));
63166309 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));
63196312 result_arg.* = .{ .stack_argument_offset = stack_offset };
63206313 stack_offset += param_size;
63216314 } else {
src/arch/arm/CodeGen.zig+13-12
......@@ -23,6 +23,7 @@ const DW = std.dwarf;
2323const leb128 = std.leb;
2424const log = std.log.scoped(.codegen);
2525const build_options = @import("build_options");
26const Alignment = InternPool.Alignment;
2627
2728const Result = codegen.Result;
2829const CodeGenError = codegen.CodeGenError;
......@@ -508,7 +509,7 @@ fn gen(self: *Self) !void {
508509 // The address of where to store the return value is in
509510 // r0. As this register might get overwritten along the
510511 // 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
513514 try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = .r0 });
514515 self.ret_mcv = MCValue{ .stack_offset = stack_offset };
......@@ -986,14 +987,14 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
986987fn allocMem(
987988 self: *Self,
988989 abi_size: u32,
989 abi_align: u32,
990 abi_align: Alignment,
990991 maybe_inst: ?Air.Inst.Index,
991992) !u32 {
992993 assert(abi_size > 0);
993 assert(abi_align > 0);
994 assert(abi_align != .none);
994995
995996 // 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);
997998 self.next_stack_offset = offset;
998999 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 {
14901491 const len = try self.resolveInst(bin_op.rhs);
14911492 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);
14941495 try self.genSetStack(ptr_ty, stack_offset, ptr);
14951496 try self.genSetStack(len_ty, stack_offset - 4, len);
14961497 break :result MCValue{ .stack_offset = stack_offset };
......@@ -4251,8 +4252,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
42514252 const r0_lock: ?RegisterLock = if (info.return_value == .stack_offset) blk: {
42524253 log.debug("airCall: return by reference", .{});
42534254 const ret_ty = fn_ty.fnReturnType(mod);
4254 const ret_abi_size = @as(u32, @intCast(ret_ty.abiSize(mod)));
4255 const ret_abi_align = @as(u32, @intCast(ret_ty.abiAlignment(mod)));
4255 const ret_abi_size: u32 = @intCast(ret_ty.abiSize(mod));
4256 const ret_abi_align = ret_ty.abiAlignment(mod);
42564257 const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst);
42574258
42584259 const ptr_ty = try mod.singleMutPtrType(ret_ty);
......@@ -5896,7 +5897,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
58965897 const array_ty = ptr_ty.childType(mod);
58975898 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);
59005901 try self.genSetStack(ptr_ty, stack_offset, ptr);
59015902 try self.genSetStack(Type.usize, stack_offset - 4, .{ .immediate = array_len });
59025903 break :result MCValue{ .stack_offset = stack_offset };
......@@ -6201,7 +6202,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
62016202 }
62026203
62036204 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")
62056206 ncrn = std.mem.alignForward(usize, ncrn, 2);
62066207
62076208 const param_size = @as(u32, @intCast(ty.toType().abiSize(mod)));
......@@ -6216,7 +6217,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
62166217 return self.fail("TODO MCValues split between registers and stack", .{});
62176218 } else {
62186219 ncrn = 4;
6219 if (ty.toType().abiAlignment(mod) == 8)
6220 if (ty.toType().abiAlignment(mod) == .@"8")
62206221 nsaa = std.mem.alignForward(u32, nsaa, 8);
62216222
62226223 result_arg.* = .{ .stack_argument_offset = nsaa };
......@@ -6252,10 +6253,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
62526253
62536254 for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| {
62546255 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));
62566257 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));
62596260 result_arg.* = .{ .stack_argument_offset = stack_offset };
62606261 stack_offset += param_size;
62616262 } else {
src/arch/arm/abi.zig+2-2
......@@ -47,7 +47,7 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class {
4747 const field_ty = ty.structFieldType(i, mod);
4848 const field_alignment = ty.structFieldAlign(i, mod);
4949 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")) {
5151 return Class.arrSize(bit_size, 64);
5252 }
5353 }
......@@ -66,7 +66,7 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class {
6666
6767 for (union_obj.field_types.get(ip), 0..) |field_ty, field_index| {
6868 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"))
7070 {
7171 return Class.arrSize(bit_size, 64);
7272 }
src/arch/riscv64/CodeGen.zig+9-10
......@@ -23,6 +23,7 @@ const leb128 = std.leb;
2323const log = std.log.scoped(.codegen);
2424const build_options = @import("build_options");
2525const codegen = @import("../../codegen.zig");
26const Alignment = InternPool.Alignment;
2627
2728const CodeGenError = codegen.CodeGenError;
2829const Result = codegen.Result;
......@@ -53,7 +54,7 @@ ret_mcv: MCValue,
5354fn_type: Type,
5455arg_index: usize,
5556src_loc: Module.SrcLoc,
56stack_align: u32,
57stack_align: Alignment,
5758
5859/// MIR Instructions
5960mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
......@@ -788,11 +789,10 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
788789 try table.ensureUnusedCapacity(self.gpa, additional_count);
789790}
790791
791fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 {
792 if (abi_align > self.stack_align)
793 self.stack_align = abi_align;
792fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: Alignment) !u32 {
793 self.stack_align = self.stack_align.max(abi_align);
794794 // 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));
796796 self.next_stack_offset = offset + abi_size;
797797 if (self.next_stack_offset > self.max_end_stack)
798798 self.max_end_stack = self.next_stack_offset;
......@@ -822,8 +822,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
822822 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)});
823823 };
824824 const abi_align = elem_ty.abiAlignment(mod);
825 if (abi_align > self.stack_align)
826 self.stack_align = abi_align;
825 self.stack_align = self.stack_align.max(abi_align);
827826
828827 if (reg_ok) {
829828 // Make sure the type can fit in a register before we try to allocate one.
......@@ -2602,7 +2601,7 @@ const CallMCValues = struct {
26022601 args: []MCValue,
26032602 return_value: MCValue,
26042603 stack_byte_count: u32,
2605 stack_align: u32,
2604 stack_align: Alignment,
26062605
26072606 fn deinit(self: *CallMCValues, func: *Self) void {
26082607 func.gpa.free(self.args);
......@@ -2632,7 +2631,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
26322631 assert(result.args.len == 0);
26332632 result.return_value = .{ .unreach = {} };
26342633 result.stack_byte_count = 0;
2635 result.stack_align = 1;
2634 result.stack_align = .@"1";
26362635 return result;
26372636 },
26382637 .Unspecified, .C => {
......@@ -2671,7 +2670,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
26712670 }
26722671
26732672 result.stack_byte_count = next_stack_offset;
2674 result.stack_align = 16;
2673 result.stack_align = .@"16";
26752674 },
26762675 else => return self.fail("TODO implement function parameters for {} on riscv64", .{cc}),
26772676 }
src/arch/sparc64/CodeGen.zig+14-21
......@@ -24,6 +24,7 @@ const CodeGenError = codegen.CodeGenError;
2424const Result = @import("../../codegen.zig").Result;
2525const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
2626const Endian = std.builtin.Endian;
27const Alignment = InternPool.Alignment;
2728
2829const build_options = @import("build_options");
2930
......@@ -62,7 +63,7 @@ ret_mcv: MCValue,
6263fn_type: Type,
6364arg_index: usize,
6465src_loc: Module.SrcLoc,
65stack_align: u32,
66stack_align: Alignment,
6667
6768/// MIR Instructions
6869mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
......@@ -227,7 +228,7 @@ const CallMCValues = struct {
227228 args: []MCValue,
228229 return_value: MCValue,
229230 stack_byte_count: u32,
230 stack_align: u32,
231 stack_align: Alignment,
231232
232233 fn deinit(self: *CallMCValues, func: *Self) void {
233234 func.gpa.free(self.args);
......@@ -424,7 +425,7 @@ fn gen(self: *Self) !void {
424425
425426 // Backpatch stack offset
426427 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);
428429 if (math.cast(i13, stack_size)) |size| {
429430 self.mir_instructions.set(save_inst, .{
430431 .tag = .save,
......@@ -880,11 +881,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
880881 const ptr = try self.resolveInst(ty_op.operand);
881882 const array_ty = ptr_ty.childType(mod);
882883 const array_len = @as(u32, @intCast(array_ty.arrayLen(mod)));
883
884 const ptr_bits = self.target.ptrBitWidth();
885 const ptr_bytes = @divExact(ptr_bits, 8);
886
887 const stack_offset = try self.allocMem(inst, ptr_bytes * 2, ptr_bytes * 2);
884 const ptr_bytes = 8;
885 const stack_offset = try self.allocMem(inst, ptr_bytes * 2, .@"8");
888886 try self.genSetStack(ptr_ty, stack_offset, ptr);
889887 try self.genSetStack(Type.usize, stack_offset - ptr_bytes, .{ .immediate = array_len });
890888 break :result MCValue{ .stack_offset = stack_offset };
......@@ -2438,11 +2436,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
24382436 const ptr_ty = self.typeOf(bin_op.lhs);
24392437 const len = try self.resolveInst(bin_op.rhs);
24402438 const len_ty = self.typeOf(bin_op.rhs);
2441
2442 const ptr_bits = self.target.ptrBitWidth();
2443 const ptr_bytes = @divExact(ptr_bits, 8);
2444
2445 const stack_offset = try self.allocMem(inst, ptr_bytes * 2, ptr_bytes * 2);
2439 const ptr_bytes = 8;
2440 const stack_offset = try self.allocMem(inst, ptr_bytes * 2, .@"8");
24462441 try self.genSetStack(ptr_ty, stack_offset, ptr);
24472442 try self.genSetStack(len_ty, stack_offset - ptr_bytes, len);
24482443 break :result MCValue{ .stack_offset = stack_offset };
......@@ -2782,11 +2777,10 @@ fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
27822777 return result_index;
27832778}
27842779
2785fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 {
2786 if (abi_align > self.stack_align)
2787 self.stack_align = abi_align;
2780fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: Alignment) !u32 {
2781 self.stack_align = self.stack_align.max(abi_align);
27882782 // 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);
27902784 self.next_stack_offset = offset;
27912785 if (self.next_stack_offset > self.max_end_stack)
27922786 self.max_end_stack = self.next_stack_offset;
......@@ -2825,8 +2819,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
28252819 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)});
28262820 };
28272821 const abi_align = elem_ty.abiAlignment(mod);
2828 if (abi_align > self.stack_align)
2829 self.stack_align = abi_align;
2822 self.stack_align = self.stack_align.max(abi_align);
28302823
28312824 if (reg_ok) {
28322825 // 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)
44794472 assert(result.args.len == 0);
44804473 result.return_value = .{ .unreach = {} };
44814474 result.stack_byte_count = 0;
4482 result.stack_align = 1;
4475 result.stack_align = .@"1";
44834476 return result;
44844477 },
44854478 .Unspecified, .C => {
......@@ -4521,7 +4514,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView)
45214514 }
45224515
45234516 result.stack_byte_count = next_stack_offset;
4524 result.stack_align = 16;
4517 result.stack_align = .@"16";
45254518
45264519 if (ret_ty.zigTypeTag(mod) == .NoReturn) {
45274520 result.return_value = .{ .unreach = {} };
src/arch/wasm/CodeGen.zig+88-75
......@@ -25,6 +25,7 @@ const target_util = @import("../../target.zig");
2525const Mir = @import("Mir.zig");
2626const Emit = @import("Emit.zig");
2727const abi = @import("abi.zig");
28const Alignment = InternPool.Alignment;
2829const errUnionPayloadOffset = codegen.errUnionPayloadOffset;
2930const errUnionErrorOffset = codegen.errUnionErrorOffset;
3031
......@@ -709,7 +710,7 @@ stack_size: u32 = 0,
709710/// tool-conventions: https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md
710711/// and also what the llvm backend will emit.
711712/// However, local variables or the usage of `@setAlignStack` can overwrite this default.
712stack_alignment: u32 = 16,
713stack_alignment: Alignment = .@"16",
713714
714715// For each individual Wasm valtype we store a seperate free list which
715716// 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
991992/// Using a given `Type`, returns the corresponding type
992993fn typeToValtype(ty: Type, mod: *Module) wasm.Valtype {
993994 const target = mod.getTarget();
995 const ip = &mod.intern_pool;
994996 return switch (ty.zigTypeTag(mod)) {
995997 .Float => switch (ty.floatBits(target)) {
996998 16 => wasm.Valtype.i32, // stored/loaded as u16
......@@ -1005,12 +1007,12 @@ fn typeToValtype(ty: Type, mod: *Module) wasm.Valtype {
10051007 if (info.bits > 32 and info.bits <= 128) break :blk wasm.Valtype.i64;
10061008 break :blk wasm.Valtype.i32; // represented as pointer to stack
10071009 },
1008 .Struct => switch (ty.containerLayout(mod)) {
1009 .Packed => {
1010 const struct_obj = mod.typeToStruct(ty).?;
1011 return typeToValtype(struct_obj.backing_int_ty, mod);
1012 },
1013 else => wasm.Valtype.i32,
1010 .Struct => {
1011 if (mod.typeToPackedStruct(ty)) |packed_struct| {
1012 return typeToValtype(packed_struct.backingIntType(ip).toType(), mod);
1013 } else {
1014 return wasm.Valtype.i32;
1015 }
10141016 },
10151017 .Vector => switch (determineSimdStoreStrategy(ty, mod)) {
10161018 .direct => wasm.Valtype.v128,
......@@ -1285,12 +1287,12 @@ fn genFunc(func: *CodeGen) InnerError!void {
12851287 // store stack pointer so we can restore it when we return from the function
12861288 try prologue.append(.{ .tag = .local_tee, .data = .{ .label = func.initial_stack_value.local.value } });
12871289 // get the total stack size
1288 const aligned_stack = std.mem.alignForward(u32, func.stack_size, func.stack_alignment);
1289 try prologue.append(.{ .tag = .i32_const, .data = .{ .imm32 = @as(i32, @intCast(aligned_stack)) } });
1290 // substract it from the current stack pointer
1290 const aligned_stack = func.stack_alignment.forward(func.stack_size);
1291 try prologue.append(.{ .tag = .i32_const, .data = .{ .imm32 = @intCast(aligned_stack) } });
1292 // subtract it from the current stack pointer
12911293 try prologue.append(.{ .tag = .i32_sub, .data = .{ .tag = {} } });
12921294 // 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 } });
12941296 // Bitwise-and the value to get the new stack pointer to ensure the pointers are aligned with the abi alignment
12951297 try prologue.append(.{ .tag = .i32_and, .data = .{ .tag = {} } });
12961298 // 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:
14381440 });
14391441 try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{
14401442 .offset = value.offset(),
1441 .alignment = scalar_type.abiAlignment(mod),
1443 .alignment = @intCast(scalar_type.abiAlignment(mod).toByteUnitsOptional().?),
14421444 });
14431445 }
14441446 },
......@@ -1527,11 +1529,9 @@ fn allocStack(func: *CodeGen, ty: Type) !WValue {
15271529 };
15281530 const abi_align = ty.abiAlignment(mod);
15291531
1530 if (abi_align > func.stack_alignment) {
1531 func.stack_alignment = abi_align;
1532 }
1532 func.stack_alignment = func.stack_alignment.max(abi_align);
15331533
1534 const offset = std.mem.alignForward(u32, func.stack_size, abi_align);
1534 const offset: u32 = @intCast(abi_align.forward(func.stack_size));
15351535 defer func.stack_size = offset + abi_size;
15361536
15371537 return WValue{ .stack_offset = .{ .value = offset, .references = 1 } };
......@@ -1560,11 +1560,9 @@ fn allocStackPtr(func: *CodeGen, inst: Air.Inst.Index) !WValue {
15601560 pointee_ty.fmt(mod), pointee_ty.abiSize(mod),
15611561 });
15621562 };
1563 if (abi_alignment > func.stack_alignment) {
1564 func.stack_alignment = abi_alignment;
1565 }
1563 func.stack_alignment = func.stack_alignment.max(abi_alignment);
15661564
1567 const offset = std.mem.alignForward(u32, func.stack_size, abi_alignment);
1565 const offset: u32 = @intCast(abi_alignment.forward(func.stack_size));
15681566 defer func.stack_size = offset + abi_size;
15691567
15701568 return WValue{ .stack_offset = .{ .value = offset, .references = 1 } };
......@@ -1749,10 +1747,8 @@ fn isByRef(ty: Type, mod: *Module) bool {
17491747 return ty.hasRuntimeBitsIgnoreComptime(mod);
17501748 },
17511749 .Struct => {
1752 if (mod.typeToStruct(ty)) |struct_obj| {
1753 if (struct_obj.layout == .Packed and struct_obj.haveFieldTypes()) {
1754 return isByRef(struct_obj.backing_int_ty, mod);
1755 }
1750 if (mod.typeToPackedStruct(ty)) |packed_struct| {
1751 return isByRef(packed_struct.backingIntType(ip).toType(), mod);
17561752 }
17571753 return ty.hasRuntimeBitsIgnoreComptime(mod);
17581754 },
......@@ -2120,7 +2116,7 @@ fn airRet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
21202116 });
21212117 try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{
21222118 .offset = operand.offset(),
2123 .alignment = scalar_type.abiAlignment(mod),
2119 .alignment = @intCast(scalar_type.abiAlignment(mod).toByteUnitsOptional().?),
21242120 });
21252121 },
21262122 else => try func.emitWValue(operand),
......@@ -2385,19 +2381,19 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
23852381 },
23862382 .Vector => switch (determineSimdStoreStrategy(ty, mod)) {
23872383 .unrolled => {
2388 const len = @as(u32, @intCast(abi_size));
2384 const len: u32 = @intCast(abi_size);
23892385 return func.memcpy(lhs, rhs, .{ .imm32 = len });
23902386 },
23912387 .direct => {
23922388 try func.emitWValue(lhs);
23932389 try func.lowerToStack(rhs);
23942390 // 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);
23962392 // stores as := opcode, offset, alignment (opcode::memarg)
23972393 try func.mir_extra.appendSlice(func.gpa, &[_]u32{
23982394 std.wasm.simdOpcode(.v128_store),
23992395 offset + lhs.offset(),
2400 ty.abiAlignment(mod),
2396 @intCast(ty.abiAlignment(mod).toByteUnits(0)),
24012397 });
24022398 return func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
24032399 },
......@@ -2451,7 +2447,10 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
24512447 // store rhs value at stack pointer's location in memory
24522448 try func.addMemArg(
24532449 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 },
24552454 );
24562455}
24572456
......@@ -2510,7 +2509,7 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu
25102509 try func.mir_extra.appendSlice(func.gpa, &[_]u32{
25112510 std.wasm.simdOpcode(.v128_load),
25122511 offset + operand.offset(),
2513 ty.abiAlignment(mod),
2512 @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
25142513 });
25152514 try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
25162515 return WValue{ .stack = {} };
......@@ -2526,7 +2525,10 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu
25262525
25272526 try func.addMemArg(
25282527 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 },
25302532 );
25312533
25322534 return WValue{ .stack = {} };
......@@ -3023,10 +3025,10 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue
30233025 else => blk: {
30243026 const layout: Module.UnionLayout = parent_ty.unionGetLayout(mod);
30253027 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
30283030 // 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);
30303032 },
30313033 },
30323034 .Pointer => switch (parent_ty.ptrSize(mod)) {
......@@ -3103,8 +3105,12 @@ fn toTwosComplement(value: anytype, bits: u7) std.meta.Int(.unsigned, @typeInfo(
31033105 return @as(WantedT, @intCast(result));
31043106}
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.
31063110fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
31073111 const mod = func.bin_file.base.options.module.?;
3112 // TODO: enable this assertion
3113 //assert(!isByRef(ty, mod));
31083114 const ip = &mod.intern_pool;
31093115 var val = arg_val;
31103116 switch (ip.indexToKey(val.ip_index)) {
......@@ -3235,16 +3241,18 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
32353241 val.writeToMemory(ty, mod, &buf) catch unreachable;
32363242 return func.storeSimdImmd(buf);
32373243 },
3238 .struct_type, .anon_struct_type => {
3239 const struct_obj = mod.typeToStruct(ty).?;
3240 assert(struct_obj.layout == .Packed);
3244 .struct_type => |struct_type| {
3245 // non-packed structs are not handled in this function because they
3246 // are by-ref types.
3247 assert(struct_type.layout == .Packed);
32413248 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();
32433251 const int_val = try mod.intValue(
3244 struct_obj.backing_int_ty,
3245 std.mem.readIntLittle(u64, &buf),
3252 backing_int_ty,
3253 mem.readIntLittle(u64, &buf),
32463254 );
3247 return func.lowerConstant(int_val, struct_obj.backing_int_ty);
3255 return func.lowerConstant(int_val, backing_int_ty);
32483256 },
32493257 else => unreachable,
32503258 },
......@@ -3269,6 +3277,7 @@ fn storeSimdImmd(func: *CodeGen, value: [16]u8) !WValue {
32693277
32703278fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue {
32713279 const mod = func.bin_file.base.options.module.?;
3280 const ip = &mod.intern_pool;
32723281 switch (ty.zigTypeTag(mod)) {
32733282 .Bool, .ErrorSet => return WValue{ .imm32 = 0xaaaaaaaa },
32743283 .Int, .Enum => switch (ty.intInfo(mod).bits) {
......@@ -3298,9 +3307,8 @@ fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue {
32983307 return WValue{ .imm32 = 0xaaaaaaaa };
32993308 },
33003309 .Struct => {
3301 const struct_obj = mod.typeToStruct(ty).?;
3302 assert(struct_obj.layout == .Packed);
3303 return func.emitUndefined(struct_obj.backing_int_ty);
3310 const packed_struct = mod.typeToPackedStruct(ty).?;
3311 return func.emitUndefined(packed_struct.backingIntType(ip).toType());
33043312 },
33053313 else => return func.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty.zigTypeTag(mod)}),
33063314 }
......@@ -3340,7 +3348,7 @@ fn intStorageAsI32(storage: InternPool.Key.Int.Storage, mod: *Module) i32 {
33403348 .i64 => |x| @as(i32, @intCast(x)),
33413349 .u64 => |x| @as(i32, @bitCast(@as(u32, @intCast(x)))),
33423350 .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))))),
33443352 .lazy_size => |ty| @as(i32, @bitCast(@as(u32, @intCast(ty.toType().abiSize(mod))))),
33453353 };
33463354}
......@@ -3757,6 +3765,7 @@ fn structFieldPtr(
37573765
37583766fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
37593767 const mod = func.bin_file.base.options.module.?;
3768 const ip = &mod.intern_pool;
37603769 const ty_pl = func.air.instructions.items(.data)[inst].ty_pl;
37613770 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 {
37693778 const result = switch (struct_ty.containerLayout(mod)) {
37703779 .Packed => switch (struct_ty.zigTypeTag(mod)) {
37713780 .Struct => result: {
3772 const struct_obj = mod.typeToStruct(struct_ty).?;
3773 const offset = struct_obj.packedFieldBitOffset(mod, field_index);
3774 const backing_ty = struct_obj.backing_int_ty;
3781 const packed_struct = mod.typeToPackedStruct(struct_ty).?;
3782 const offset = mod.structPackedFieldBitOffset(packed_struct, field_index);
3783 const backing_ty = packed_struct.backingIntType(ip).toType();
37753784 const wasm_bits = toWasmBits(backing_ty.intInfo(mod).bits) orelse {
37763785 return func.fail("TODO: airStructFieldVal for packed structs larger than 128 bits", .{});
37773786 };
......@@ -3793,7 +3802,7 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
37933802 const truncated = try func.trunc(shifted_value, int_type, backing_ty);
37943803 const bitcasted = try func.bitcast(field_ty, int_type, truncated);
37953804 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) {
37973806 // In this case we do not have to perform any transformations,
37983807 // we can simply reuse the operand.
37993808 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
40534062 if (pl_ty.hasRuntimeBitsIgnoreComptime(mod)) {
40544063 try func.addMemArg(.i32_load16_u, .{
40554064 .offset = operand.offset() + @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod))),
4056 .alignment = Type.anyerror.abiAlignment(mod),
4065 .alignment = @intCast(Type.anyerror.abiAlignment(mod).toByteUnitsOptional().?),
40574066 });
40584067 }
40594068
......@@ -4141,7 +4150,10 @@ fn airWrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void
41414150 try func.emitWValue(err_union);
41424151 try func.addImm32(0);
41434152 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 });
41454157 break :result err_union;
41464158 };
41474159 func.finishAir(inst, result, &.{ty_op.operand});
......@@ -4977,7 +4989,7 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
49774989 try func.mir_extra.appendSlice(func.gpa, &[_]u32{
49784990 opcode,
49794991 operand.offset(),
4980 elem_ty.abiAlignment(mod),
4992 @intCast(elem_ty.abiAlignment(mod).toByteUnitsOptional().?),
49814993 });
49824994 try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
49834995 try func.addLabel(.local_set, result.local.value);
......@@ -5065,7 +5077,7 @@ fn airShuffle(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
50655077 std.wasm.simdOpcode(.i8x16_shuffle),
50665078 } ++ [1]u32{undefined} ** 4;
50675079
5068 var lanes = std.mem.asBytes(operands[1..]);
5080 var lanes = mem.asBytes(operands[1..]);
50695081 for (0..@as(usize, @intCast(mask_len))) |index| {
50705082 const mask_elem = (try mask.elemValue(mod, index)).toSignedInt(mod);
50715083 const base_index = if (mask_elem >= 0)
......@@ -5099,6 +5111,7 @@ fn airReduce(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
50995111
51005112fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
51015113 const mod = func.bin_file.base.options.module.?;
5114 const ip = &mod.intern_pool;
51025115 const ty_pl = func.air.instructions.items(.data)[inst].ty_pl;
51035116 const result_ty = func.typeOfIndex(inst);
51045117 const len = @as(usize, @intCast(result_ty.arrayLen(mod)));
......@@ -5150,13 +5163,13 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
51505163 if (isByRef(result_ty, mod)) {
51515164 return func.fail("TODO: airAggregateInit for packed structs larger than 64 bits", .{});
51525165 }
5153 const struct_obj = mod.typeToStruct(result_ty).?;
5154 const fields = struct_obj.fields.values();
5155 const backing_type = struct_obj.backing_int_ty;
5166 const packed_struct = mod.typeToPackedStruct(result_ty).?;
5167 const field_types = packed_struct.field_types;
5168 const backing_type = packed_struct.backingIntType(ip).toType();
51565169
51575170 // ensure the result is zero'd
51585171 const result = try func.allocLocal(backing_type);
5159 if (struct_obj.backing_int_ty.bitSize(mod) <= 32)
5172 if (backing_type.bitSize(mod) <= 32)
51605173 try func.addImm32(0)
51615174 else
51625175 try func.addImm64(0);
......@@ -5164,22 +5177,22 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
51645177
51655178 var current_bit: u16 = 0;
51665179 for (elements, 0..) |elem, elem_index| {
5167 const field = fields[elem_index];
5168 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
5180 const field_ty = field_types.get(ip)[elem_index].toType();
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)
51715184 WValue{ .imm32 = current_bit }
51725185 else
51735186 WValue{ .imm64 = current_bit };
51745187
51755188 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));
51775190 const int_ty = try mod.intType(.unsigned, value_bit_size);
51785191
51795192 // load our current result on stack so we can perform all transformations
51805193 // using only stack values. Saving the cost of loads and stores.
51815194 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);
51835196 const extended_val = try func.intcast(bitcasted, int_ty, backing_type);
51845197 // no need to shift any values when the current offset is 0
51855198 const shifted = if (current_bit != 0) shifted: {
......@@ -5199,7 +5212,7 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
51995212 if ((try result_ty.structFieldValueComptime(mod, elem_index)) != null) continue;
52005213
52015214 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));
52035216 const value = try func.resolveInst(elem);
52045217 try func.store(offset, value, elem_ty, 0);
52055218
......@@ -5256,7 +5269,7 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
52565269 if (isByRef(union_ty, mod)) {
52575270 const result_ptr = try func.allocStack(union_ty);
52585271 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)) {
52605273 if (isByRef(field_ty, mod)) {
52615274 const payload_ptr = try func.buildPointerOffset(result_ptr, layout.tag_size, .new);
52625275 try func.store(payload_ptr, payload, field_ty, 0);
......@@ -5420,9 +5433,9 @@ fn airSetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
54205433
54215434 // when the tag alignment is smaller than the payload, the field will be stored
54225435 // after the payload.
5423 const offset = if (layout.tag_align < layout.payload_align) blk: {
5424 break :blk @as(u32, @intCast(layout.payload_size));
5425 } else @as(u32, 0);
5436 const offset: u32 = if (layout.tag_align.compare(.lt, layout.payload_align)) blk: {
5437 break :blk @intCast(layout.payload_size);
5438 } else 0;
54265439 try func.store(union_ptr, new_tag, tag_ty, offset);
54275440 func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
54285441}
......@@ -5439,9 +5452,9 @@ fn airGetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
54395452 const operand = try func.resolveInst(ty_op.operand);
54405453 // when the tag alignment is smaller than the payload, the field will be stored
54415454 // after the payload.
5442 const offset = if (layout.tag_align < layout.payload_align) blk: {
5443 break :blk @as(u32, @intCast(layout.payload_size));
5444 } else @as(u32, 0);
5455 const offset: u32 = if (layout.tag_align.compare(.lt, layout.payload_align)) blk: {
5456 break :blk @intCast(layout.payload_size);
5457 } else 0;
54455458 const tag = try func.load(operand, tag_ty, offset);
54465459 const result = try tag.toLocal(func, tag_ty);
54475460 func.finishAir(inst, result, &.{ty_op.operand});
......@@ -6366,7 +6379,7 @@ fn lowerTry(
63666379 const err_offset = @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod)));
63676380 try func.addMemArg(.i32_load16_u, .{
63686381 .offset = err_union.offset() + err_offset,
6369 .alignment = Type.anyerror.abiAlignment(mod),
6382 .alignment = @intCast(Type.anyerror.abiAlignment(mod).toByteUnitsOptional().?),
63706383 });
63716384 }
63726385 try func.addTag(.i32_eqz);
......@@ -7287,7 +7300,7 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
72877300 else => |size| return func.fail("TODO: implement `@cmpxchg` for types with abi size '{d}'", .{size}),
72887301 }, .{
72897302 .offset = ptr_operand.offset(),
7290 .alignment = ty.abiAlignment(mod),
7303 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
72917304 });
72927305 try func.addLabel(.local_tee, val_local.local.value);
72937306 _ = try func.cmp(.stack, expected_val, ty, .eq);
......@@ -7349,7 +7362,7 @@ fn airAtomicLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
73497362 try func.emitWValue(ptr);
73507363 try func.addAtomicMemArg(tag, .{
73517364 .offset = ptr.offset(),
7352 .alignment = ty.abiAlignment(mod),
7365 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
73537366 });
73547367 } else {
73557368 _ = try func.load(ptr, ty, 0);
......@@ -7410,7 +7423,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
74107423 },
74117424 .{
74127425 .offset = ptr.offset(),
7413 .alignment = ty.abiAlignment(mod),
7426 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
74147427 },
74157428 );
74167429 const select_res = try func.allocLocal(ty);
......@@ -7470,7 +7483,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
74707483 };
74717484 try func.addAtomicMemArg(tag, .{
74727485 .offset = ptr.offset(),
7473 .alignment = ty.abiAlignment(mod),
7486 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
74747487 });
74757488 const result = try WValue.toLocal(.stack, func, ty);
74767489 return func.finishAir(inst, result, &.{ pl_op.operand, extra.operand });
......@@ -7566,7 +7579,7 @@ fn airAtomicStore(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
75667579 try func.lowerToStack(operand);
75677580 try func.addAtomicMemArg(tag, .{
75687581 .offset = ptr.offset(),
7569 .alignment = ty.abiAlignment(mod),
7582 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
75707583 });
75717584 } else {
75727585 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 {
3232 if (ty.bitSize(mod) <= 64) return direct;
3333 return .{ .direct, .direct };
3434 }
35 // When the struct type is non-scalar
36 if (ty.structFieldCount(mod) > 1) return memory;
37 // When the struct's alignment is non-natural
38 const field = ty.structFields(mod).values()[0];
39 if (field.abi_align != .none) {
40 if (field.abi_align.toByteUnitsOptional().? > field.ty.abiAlignment(mod)) {
41 return memory;
42 }
35 if (ty.structFieldCount(mod) > 1) {
36 // The struct type is non-scalar.
37 return memory;
38 }
39 const field_ty = ty.structFieldType(0, mod);
40 const resolved_align = ty.structFieldAlign(0, mod);
41 if (resolved_align.compare(.gt, field_ty.abiAlignment(mod))) {
42 // The struct's alignment is greater than natural alignment.
43 return memory;
4344 }
44 return classifyType(field.ty, mod);
45 return classifyType(field_ty, mod);
4546 },
4647 .Int, .Enum, .ErrorSet, .Vector => {
4748 const int_bits = ty.intInfo(mod).bits;
......@@ -101,15 +102,11 @@ pub fn scalarType(ty: Type, mod: *Module) Type {
101102 const ip = &mod.intern_pool;
102103 switch (ty.zigTypeTag(mod)) {
103104 .Struct => {
104 switch (ty.containerLayout(mod)) {
105 .Packed => {
106 const struct_obj = mod.typeToStruct(ty).?;
107 return scalarType(struct_obj.backing_int_ty, mod);
108 },
109 else => {
110 assert(ty.structFieldCount(mod) == 1);
111 return scalarType(ty.structFieldType(0, mod), mod);
112 },
105 if (mod.typeToPackedStruct(ty)) |packed_struct| {
106 return scalarType(packed_struct.backingIntType(ip).toType(), mod);
107 } else {
108 assert(ty.structFieldCount(mod) == 1);
109 return scalarType(ty.structFieldType(0, mod), mod);
113110 }
114111 },
115112 .Union => {
src/arch/x86_64/CodeGen.zig+59-57
......@@ -27,6 +27,7 @@ const Lower = @import("Lower.zig");
2727const Mir = @import("Mir.zig");
2828const Module = @import("../../Module.zig");
2929const InternPool = @import("../../InternPool.zig");
30const Alignment = InternPool.Alignment;
3031const Target = std.Target;
3132const Type = @import("../../type.zig").Type;
3233const TypedValue = @import("../../TypedValue.zig");
......@@ -607,19 +608,21 @@ const InstTracking = struct {
607608
608609const FrameAlloc = struct {
609610 abi_size: u31,
610 abi_align: u5,
611 abi_align: Alignment,
611612 ref_count: u16,
612613
613 fn init(alloc_abi: struct { size: u64, alignment: u32 }) FrameAlloc {
614 assert(math.isPowerOfTwo(alloc_abi.alignment));
614 fn init(alloc_abi: struct { size: u64, alignment: Alignment }) FrameAlloc {
615615 return .{
616616 .abi_size = @intCast(alloc_abi.size),
617 .abi_align = math.log2_int(u32, alloc_abi.alignment),
617 .abi_align = alloc_abi.alignment,
618618 .ref_count = 0,
619619 };
620620 }
621621 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 });
623626 }
624627};
625628
......@@ -702,12 +705,12 @@ pub fn generate(
702705 @intFromEnum(FrameIndex.stack_frame),
703706 FrameAlloc.init(.{
704707 .size = 0,
705 .alignment = @intCast(func.analysis(ip).stack_alignment.toByteUnitsOptional() orelse 1),
708 .alignment = func.analysis(ip).stack_alignment.max(.@"1"),
706709 }),
707710 );
708711 function.frame_allocs.set(
709712 @intFromEnum(FrameIndex.call_frame),
710 FrameAlloc.init(.{ .size = 0, .alignment = 1 }),
713 FrameAlloc.init(.{ .size = 0, .alignment = .@"1" }),
711714 );
712715
713716 const fn_info = mod.typeToFunc(fn_type).?;
......@@ -729,15 +732,21 @@ pub fn generate(
729732 function.ret_mcv = call_info.return_value;
730733 function.frame_allocs.set(@intFromEnum(FrameIndex.ret_addr), FrameAlloc.init(.{
731734 .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),
733736 }));
734737 function.frame_allocs.set(@intFromEnum(FrameIndex.base_ptr), FrameAlloc.init(.{
735738 .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 ),
737743 }));
738744 function.frame_allocs.set(
739745 @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 }),
741750 );
742751
743752 function.gen() catch |err| switch (err) {
......@@ -2156,8 +2165,8 @@ fn setFrameLoc(
21562165) void {
21572166 const frame_i = @intFromEnum(frame_index);
21582167 if (aligned) {
2159 const alignment = @as(i32, 1) << self.frame_allocs.items(.abi_align)[frame_i];
2160 offset.* = mem.alignForward(i32, offset.*, alignment);
2168 const alignment = self.frame_allocs.items(.abi_align)[frame_i];
2169 offset.* = @intCast(alignment.forward(@intCast(offset.*)));
21612170 }
21622171 self.frame_locs.set(frame_i, .{ .base = base, .disp = offset.* });
21632172 offset.* += self.frame_allocs.items(.abi_size)[frame_i];
......@@ -2179,7 +2188,7 @@ fn computeFrameLayout(self: *Self) !FrameLayout {
21792188 const SortContext = struct {
21802189 frame_align: @TypeOf(frame_align),
21812190 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)]);
21832192 }
21842193 };
21852194 const sort_context = SortContext{ .frame_align = frame_align };
......@@ -2189,8 +2198,8 @@ fn computeFrameLayout(self: *Self) !FrameLayout {
21892198 const call_frame_align = frame_align[@intFromEnum(FrameIndex.call_frame)];
21902199 const stack_frame_align = frame_align[@intFromEnum(FrameIndex.stack_frame)];
21912200 const args_frame_align = frame_align[@intFromEnum(FrameIndex.args_frame)];
2192 const needed_align = @max(call_frame_align, stack_frame_align);
2193 const need_align_stack = needed_align > args_frame_align;
2201 const needed_align = call_frame_align.max(stack_frame_align);
2202 const need_align_stack = needed_align.compare(.gt, args_frame_align);
21942203
21952204 // Create list of registers to save in the prologue.
21962205 // TODO handle register classes
......@@ -2214,21 +2223,21 @@ fn computeFrameLayout(self: *Self) !FrameLayout {
22142223 self.setFrameLoc(.stack_frame, .rsp, &rsp_offset, true);
22152224 for (stack_frame_order) |frame_index| self.setFrameLoc(frame_index, .rsp, &rsp_offset, true);
22162225 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)));
22182227 rsp_offset -= stack_frame_align_offset;
22192228 frame_size[@intFromEnum(FrameIndex.call_frame)] =
22202229 @intCast(rsp_offset - frame_offset[@intFromEnum(FrameIndex.stack_frame)]);
22212230
22222231 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),
22242233 .stack_adjust = @intCast(rsp_offset - frame_offset[@intFromEnum(FrameIndex.call_frame)]),
22252234 .save_reg_list = save_reg_list,
22262235 };
22272236}
22282237
2229fn getFrameAddrAlignment(self: *Self, frame_addr: FrameAddr) u32 {
2230 const alloc_align = @as(u32, 1) << self.frame_allocs.get(@intFromEnum(frame_addr.index)).abi_align;
2231 return @min(alloc_align, @as(u32, @bitCast(frame_addr.off)) & (alloc_align - 1));
2238fn getFrameAddrAlignment(self: *Self, frame_addr: FrameAddr) Alignment {
2239 const alloc_align = self.frame_allocs.get(@intFromEnum(frame_addr.index)).abi_align;
2240 return @enumFromInt(@min(@intFromEnum(alloc_align), @ctz(frame_addr.off)));
22322241}
22332242
22342243fn getFrameAddrSize(self: *Self, frame_addr: FrameAddr) u32 {
......@@ -2241,13 +2250,13 @@ fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex {
22412250 const frame_align = frame_allocs_slice.items(.abi_align);
22422251
22432252 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
22462255 for (self.free_frame_indices.keys(), 0..) |frame_index, free_i| {
22472256 const abi_size = frame_size[@intFromEnum(frame_index)];
22482257 if (abi_size != alloc.abi_size) continue;
22492258 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
22522261 _ = self.free_frame_indices.swapRemoveAt(free_i);
22532262 return frame_index;
......@@ -2266,7 +2275,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !FrameIndex {
22662275 .size = math.cast(u32, val_ty.abiSize(mod)) orelse {
22672276 return self.fail("type '{}' too big to fit into stack frame", .{val_ty.fmt(mod)});
22682277 },
2269 .alignment = @max(ptr_ty.ptrAlignment(mod), 1),
2278 .alignment = ptr_ty.ptrAlignment(mod).max(.@"1"),
22702279 }));
22712280}
22722281
......@@ -4266,7 +4275,7 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
42664275 };
42674276 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: {
42704279 // TODO reusing the operand
42714280 const reg = try self.copyToTmpRegister(ptr_union_ty, ptr);
42724281 try self.genBinOpMir(
......@@ -4309,7 +4318,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
43094318 switch (operand) {
43104319 .load_frame => |frame_addr| {
43114320 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))
43134322 @intCast(layout.payload_size)
43144323 else
43154324 0;
......@@ -4321,7 +4330,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
43214330 return self.fail("TODO implement get_union_tag for ABI larger than 8 bytes and operand {}", .{operand});
43224331 },
43234332 .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))
43254334 @intCast(layout.payload_size * 8)
43264335 else
43274336 0;
......@@ -5600,8 +5609,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
56005609 const src_mcv = try self.resolveInst(operand);
56015610 const field_off: u32 = switch (container_ty.containerLayout(mod)) {
56025611 .Auto, .Extern => @intCast(container_ty.structFieldOffset(index, mod) * 8),
5603 .Packed => if (mod.typeToStruct(container_ty)) |struct_obj|
5604 struct_obj.packedFieldBitOffset(mod, index)
5612 .Packed => if (mod.typeToStruct(container_ty)) |struct_type|
5613 mod.structPackedFieldBitOffset(struct_type, index)
56055614 else
56065615 0,
56075616 };
......@@ -8084,14 +8093,17 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
80848093 // We need a properly aligned and sized call frame to be able to call this function.
80858094 {
80868095 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 });
80888100 const frame_allocs_slice = self.frame_allocs.slice();
80898101 const stack_frame_size =
80908102 &frame_allocs_slice.items(.abi_size)[@intFromEnum(FrameIndex.call_frame)];
80918103 stack_frame_size.* = @max(stack_frame_size.*, needed_call_frame.abi_size);
80928104 const stack_frame_align =
80938105 &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);
80958107 }
80968108
80978109 try self.spillEflagsIfOccupied();
......@@ -9944,7 +9956,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
99449956 .indirect => try self.moveStrategy(ty, false),
99459957 .load_frame => |frame_addr| try self.moveStrategy(
99469958 ty,
9947 self.getFrameAddrAlignment(frame_addr) >= ty.abiAlignment(mod),
9959 self.getFrameAddrAlignment(frame_addr).compare(.gte, ty.abiAlignment(mod)),
99489960 ),
99499961 .lea_frame => .{ .move = .{ ._, .lea } },
99509962 else => unreachable,
......@@ -9973,10 +9985,8 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
99739985 .base = .{ .reg = .ds },
99749986 .disp = small_addr,
99759987 });
9976 switch (try self.moveStrategy(ty, mem.isAlignedGeneric(
9977 u32,
9988 switch (try self.moveStrategy(ty, ty.abiAlignment(mod).check(
99789989 @as(u32, @bitCast(small_addr)),
9979 ty.abiAlignment(mod),
99809990 ))) {
99819991 .move => |tag| try self.asmRegisterMemory(tag, dst_alias, src_mem),
99829992 .insert_extract => |ie| try self.asmRegisterMemoryImmediate(
......@@ -10142,22 +10152,14 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal
1014210152 );
1014310153 const src_alias = registerAlias(src_reg, abi_size);
1014410154 switch (try self.moveStrategy(ty, switch (base) {
10145 .none => mem.isAlignedGeneric(
10146 u32,
10147 @as(u32, @bitCast(disp)),
10148 ty.abiAlignment(mod),
10149 ),
10155 .none => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))),
1015010156 .reg => |reg| switch (reg) {
10151 .es, .cs, .ss, .ds => mem.isAlignedGeneric(
10152 u32,
10153 @as(u32, @bitCast(disp)),
10154 ty.abiAlignment(mod),
10155 ),
10157 .es, .cs, .ss, .ds => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))),
1015610158 else => false,
1015710159 },
1015810160 .frame => |frame_index| self.getFrameAddrAlignment(
1015910161 .{ .index = frame_index, .off = disp },
10160 ) >= ty.abiAlignment(mod),
10162 ).compare(.gte, ty.abiAlignment(mod)),
1016110163 })) {
1016210164 .move => |tag| try self.asmMemoryRegister(tag, dst_mem, src_alias),
1016310165 .insert_extract, .vex_insert_extract => |ie| try self.asmMemoryRegisterImmediate(
......@@ -11079,7 +11081,7 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
1107911081 stack_frame_size.* = @max(stack_frame_size.*, needed_call_frame.abi_size);
1108011082 const stack_frame_align =
1108111083 &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);
1108311085 }
1108411086
1108511087 try self.spillEflagsIfOccupied();
......@@ -11418,7 +11420,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
1141811420 const frame_index =
1141911421 try self.allocFrameIndex(FrameAlloc.initType(result_ty, mod));
1142011422 if (result_ty.containerLayout(mod) == .Packed) {
11421 const struct_obj = mod.typeToStruct(result_ty).?;
11423 const struct_type = mod.typeToStruct(result_ty).?;
1142211424 try self.genInlineMemset(
1142311425 .{ .lea_frame = .{ .index = frame_index } },
1142411426 .{ .immediate = 0 },
......@@ -11437,7 +11439,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
1143711439 }
1143811440 const elem_abi_size: u32 = @intCast(elem_ty.abiSize(mod));
1143911441 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);
1144111443 const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size);
1144211444 const elem_bit_off = elem_off % elem_abi_bits;
1144311445 const elem_mcv = try self.resolveInst(elem);
......@@ -11576,13 +11578,13 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
1157611578 const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index);
1157711579 const tag_int_val = try tag_val.intFromEnum(tag_ty, mod);
1157811580 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))
1158011582 @intCast(layout.payload_size)
1158111583 else
1158211584 0;
1158311585 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))
1158611588 0
1158711589 else
1158811590 @intCast(layout.tag_size);
......@@ -11823,7 +11825,7 @@ const CallMCValues = struct {
1182311825 args: []MCValue,
1182411826 return_value: InstTracking,
1182511827 stack_byte_count: u31,
11826 stack_align: u31,
11828 stack_align: Alignment,
1182711829
1182811830 fn deinit(self: *CallMCValues, func: *Self) void {
1182911831 func.gpa.free(self.args);
......@@ -11867,12 +11869,12 @@ fn resolveCallingConventionValues(
1186711869 .Naked => {
1186811870 assert(result.args.len == 0);
1186911871 result.return_value = InstTracking.init(.unreach);
11870 result.stack_align = 8;
11872 result.stack_align = .@"8";
1187111873 },
1187211874 .C => {
1187311875 var param_reg_i: usize = 0;
1187411876 var param_sse_reg_i: usize = 0;
11875 result.stack_align = 16;
11877 result.stack_align = .@"16";
1187611878
1187711879 switch (self.target.os.tag) {
1187811880 .windows => {
......@@ -11957,7 +11959,7 @@ fn resolveCallingConventionValues(
1195711959 }
1195811960
1195911961 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().?);
1196111963 result.stack_byte_count =
1196211964 mem.alignForward(u31, result.stack_byte_count, param_align);
1196311965 arg.* = .{ .load_frame = .{
......@@ -11968,7 +11970,7 @@ fn resolveCallingConventionValues(
1196811970 }
1196911971 },
1197011972 .Unspecified => {
11971 result.stack_align = 16;
11973 result.stack_align = .@"16";
1197211974
1197311975 // Return values
1197411976 if (ret_ty.zigTypeTag(mod) == .NoReturn) {
......@@ -11997,7 +11999,7 @@ fn resolveCallingConventionValues(
1199711999 continue;
1199812000 }
1199912001 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().?);
1200112003 result.stack_byte_count =
1200212004 mem.alignForward(u31, result.stack_byte_count, param_align);
1200312005 arg.* = .{ .load_frame = .{
......@@ -12010,7 +12012,7 @@ fn resolveCallingConventionValues(
1201012012 else => return self.fail("TODO implement function parameters and return values for {} on x86_64", .{cc}),
1201112013 }
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));
1201412016 return result;
1201512017}
1201612018
src/arch/x86_64/abi.zig+14-24
......@@ -210,8 +210,9 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {
210210 // it contains unaligned fields, it has class MEMORY"
211211 // "If the size of the aggregate exceeds a single eightbyte, each is classified
212212 // separately.".
213 const struct_type = mod.typeToStruct(ty).?;
213214 const ty_size = ty.abiSize(mod);
214 if (ty.containerLayout(mod) == .Packed) {
215 if (struct_type.layout == .Packed) {
215216 assert(ty_size <= 128);
216217 result[0] = .integer;
217218 if (ty_size > 64) result[1] = .integer;
......@@ -222,15 +223,13 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {
222223
223224 var result_i: usize = 0; // out of 8
224225 var byte_i: usize = 0; // out of 8
225 const fields = ty.structFields(mod);
226 for (fields.values()) |field| {
227 if (field.abi_align != .none) {
228 if (field.abi_align.toByteUnitsOptional().? < field.ty.abiAlignment(mod)) {
229 return memory_class;
230 }
231 }
232 const field_size = field.ty.abiSize(mod);
233 const field_class_array = classifySystemV(field.ty, mod, .other);
226 for (struct_type.field_types.get(ip), 0..) |field_ty_ip, i| {
227 const field_ty = field_ty_ip.toType();
228 const field_align = struct_type.fieldAlign(ip, i);
229 if (field_align != .none and field_align.compare(.lt, field_ty.abiAlignment(mod)))
230 return memory_class;
231 const field_size = field_ty.abiSize(mod);
232 const field_class_array = classifySystemV(field_ty, mod, .other);
234233 const field_class = std.mem.sliceTo(&field_class_array, .none);
235234 if (byte_i + field_size <= 8) {
236235 // Combine this field with the previous one.
......@@ -341,10 +340,11 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {
341340 return memory_class;
342341
343342 for (union_obj.field_types.get(ip), 0..) |field_ty, field_index| {
344 if (union_obj.fieldAlign(ip, @intCast(field_index)).toByteUnitsOptional()) |a| {
345 if (a < field_ty.toType().abiAlignment(mod)) {
346 return memory_class;
347 }
343 const field_align = union_obj.fieldAlign(ip, @intCast(field_index));
344 if (field_align != .none and
345 field_align.compare(.lt, field_ty.toType().abiAlignment(mod)))
346 {
347 return memory_class;
348348 }
349349 // Combine this field with the previous one.
350350 const field_class = classifySystemV(field_ty.toType(), mod, .other);
......@@ -533,13 +533,3 @@ const Register = @import("bits.zig").Register;
533533const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
534534const Type = @import("../../type.zig").Type;
535535const 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;
2222const TypedValue = @import("TypedValue.zig");
2323const Value = @import("value.zig").Value;
2424const Zir = @import("Zir.zig");
25const Alignment = InternPool.Alignment;
2526
2627pub const Result = union(enum) {
2728 /// The `code` parameter passed to `generateSymbol` has the value ok.
......@@ -116,7 +117,8 @@ pub fn generateLazySymbol(
116117 bin_file: *link.File,
117118 src_loc: Module.SrcLoc,
118119 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,
120122 code: *std.ArrayList(u8),
121123 debug_output: DebugInfoOutput,
122124 reloc_info: RelocInfo,
......@@ -141,7 +143,7 @@ pub fn generateLazySymbol(
141143 }
142144
143145 if (lazy_sym.ty.isAnyError(mod)) {
144 alignment.* = 4;
146 alignment.* = .@"4";
145147 const err_names = mod.global_error_set.keys();
146148 mem.writeInt(u32, try code.addManyAsArray(4), @as(u32, @intCast(err_names.len)), endian);
147149 var offset = code.items.len;
......@@ -157,7 +159,7 @@ pub fn generateLazySymbol(
157159 mem.writeInt(u32, code.items[offset..][0..4], @as(u32, @intCast(code.items.len)), endian);
158160 return Result.ok;
159161 } else if (lazy_sym.ty.zigTypeTag(mod) == .Enum) {
160 alignment.* = 1;
162 alignment.* = .@"1";
161163 for (lazy_sym.ty.enumFields(mod)) |tag_name_ip| {
162164 const tag_name = mod.intern_pool.stringToSlice(tag_name_ip);
163165 try code.ensureUnusedCapacity(tag_name.len + 1);
......@@ -273,7 +275,7 @@ pub fn generateSymbol(
273275 const abi_align = typed_value.ty.abiAlignment(mod);
274276
275277 // 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) {
277279 try code.writer().writeInt(u16, err_val, endian);
278280 }
279281
......@@ -291,7 +293,7 @@ pub fn generateSymbol(
291293 .fail => |em| return .{ .fail = em },
292294 }
293295 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);
295297 const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow;
296298
297299 if (padding > 0) {
......@@ -300,11 +302,11 @@ pub fn generateSymbol(
300302 }
301303
302304 // 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)) {
304306 const begin = code.items.len;
305307 try code.writer().writeInt(u16, err_val, endian);
306308 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);
308310 const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow;
309311
310312 if (padding > 0) {
......@@ -474,23 +476,18 @@ pub fn generateSymbol(
474476 }
475477 }
476478 },
477 .struct_type => |struct_type| {
478 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
479
480 if (struct_obj.layout == .Packed) {
481 const fields = struct_obj.fields.values();
479 .struct_type => |struct_type| switch (struct_type.layout) {
480 .Packed => {
482481 const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse
483482 return error.Overflow;
484483 const current_pos = code.items.len;
485484 try code.resize(current_pos + abi_size);
486485 var bits: u16 = 0;
487486
488 for (fields, 0..) |field, index| {
489 const field_ty = field.ty;
490
487 for (struct_type.field_types.get(ip), 0..) |field_ty, index| {
491488 const field_val = switch (aggregate.storage) {
492489 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
493 .ty = field_ty.toIntern(),
490 .ty = field_ty,
494491 .storage = .{ .u64 = bytes[index] },
495492 } }),
496493 .elems => |elems| elems[index],
......@@ -499,48 +496,51 @@ pub fn generateSymbol(
499496
500497 // pointer may point to a decl which must be marked used
501498 // but can also result in a relocation. Therefore we handle those separately.
502 if (field_ty.zigTypeTag(mod) == .Pointer) {
503 const field_size = math.cast(usize, field_ty.abiSize(mod)) orelse
499 if (field_ty.toType().zigTypeTag(mod) == .Pointer) {
500 const field_size = math.cast(usize, field_ty.toType().abiSize(mod)) orelse
504501 return error.Overflow;
505502 var tmp_list = try std.ArrayList(u8).initCapacity(code.allocator, field_size);
506503 defer tmp_list.deinit();
507504 switch (try generateSymbol(bin_file, src_loc, .{
508 .ty = field_ty,
505 .ty = field_ty.toType(),
509506 .val = field_val.toValue(),
510507 }, &tmp_list, debug_output, reloc_info)) {
511508 .ok => @memcpy(code.items[current_pos..][0..tmp_list.items.len], tmp_list.items),
512509 .fail => |em| return Result{ .fail = em },
513510 }
514511 } 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;
516513 }
517 bits += @as(u16, @intCast(field_ty.bitSize(mod)));
514 bits += @as(u16, @intCast(field_ty.toType().bitSize(mod)));
518515 }
519 } else {
516 },
517 .Auto, .Extern => {
520518 const struct_begin = code.items.len;
521 const fields = struct_obj.fields.values();
522
523 var it = typed_value.ty.iterateStructOffsets(mod);
519 const field_types = struct_type.field_types.get(ip);
520 const offsets = struct_type.offsets.get(ip);
524521
525 while (it.next()) |field_offset| {
526 const field_ty = fields[field_offset.field].ty;
527
528 if (!field_ty.hasRuntimeBits(mod)) continue;
522 var it = struct_type.iterateRuntimeOrder(ip);
523 while (it.next()) |field_index| {
524 const field_ty = field_types[field_index];
525 if (!field_ty.toType().hasRuntimeBits(mod)) continue;
529526
530527 const field_val = switch (ip.indexToKey(typed_value.val.toIntern()).aggregate.storage) {
531528 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
532 .ty = field_ty.toIntern(),
533 .storage = .{ .u64 = bytes[field_offset.field] },
529 .ty = field_ty,
530 .storage = .{ .u64 = bytes[field_index] },
534531 } }),
535 .elems => |elems| elems[field_offset.field],
532 .elems => |elems| elems[field_index],
536533 .repeated_elem => |elem| elem,
537534 };
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;
540540 if (padding > 0) try code.appendNTimes(0, padding);
541541
542542 switch (try generateSymbol(bin_file, src_loc, .{
543 .ty = field_ty,
543 .ty = field_ty.toType(),
544544 .val = field_val.toValue(),
545545 }, code, debug_output, reloc_info)) {
546546 .ok => {},
......@@ -548,9 +548,16 @@ pub fn generateSymbol(
548548 }
549549 }
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;
552559 if (padding > 0) try code.appendNTimes(0, padding);
553 }
560 },
554561 },
555562 else => unreachable,
556563 },
......@@ -565,7 +572,7 @@ pub fn generateSymbol(
565572 }
566573
567574 // 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)) {
569576 switch (try generateSymbol(bin_file, src_loc, .{
570577 .ty = typed_value.ty.unionTagType(mod).?,
571578 .val = un.tag.toValue(),
......@@ -595,7 +602,7 @@ pub fn generateSymbol(
595602 }
596603 }
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)) {
599606 switch (try generateSymbol(bin_file, src_loc, .{
600607 .ty = union_obj.enum_tag_ty.toType(),
601608 .val = un.tag.toValue(),
......@@ -695,10 +702,10 @@ fn lowerParentPtr(
695702 @intCast(field.index),
696703 mod,
697704 )),
698 .Packed => if (mod.typeToStruct(base_type.toType())) |struct_obj|
699 math.divExact(u16, struct_obj.packedFieldBitOffset(
700 mod,
701 @intCast(field.index),
705 .Packed => if (mod.typeToStruct(base_type.toType())) |struct_type|
706 math.divExact(u16, mod.structPackedFieldBitOffset(
707 struct_type,
708 field.index,
702709 ), 8) catch |err| switch (err) {
703710 error.UnexpectedRemainder => 0,
704711 error.DivisionByZero => unreachable,
......@@ -844,12 +851,12 @@ fn genDeclRef(
844851 // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`?
845852 if (tv.ty.castPtrToFn(mod)) |fn_ty| {
846853 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().? });
848855 }
849856 } else if (tv.ty.zigTypeTag(mod) == .Pointer) {
850857 const elem_ty = tv.ty.elemType2(mod);
851858 if (!elem_ty.hasRuntimeBits(mod)) {
852 return GenResult.mcv(.{ .immediate = elem_ty.abiAlignment(mod) });
859 return GenResult.mcv(.{ .immediate = elem_ty.abiAlignment(mod).toByteUnitsOptional().? });
853860 }
854861 }
855862
......@@ -1036,10 +1043,10 @@ pub fn errUnionPayloadOffset(payload_ty: Type, mod: *Module) u64 {
10361043 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return 0;
10371044 const payload_align = payload_ty.abiAlignment(mod);
10381045 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)) {
10401047 return 0;
10411048 } else {
1042 return mem.alignForward(u64, Type.anyerror.abiSize(mod), payload_align);
1049 return payload_align.forward(Type.anyerror.abiSize(mod));
10431050 }
10441051}
10451052
......@@ -1047,8 +1054,8 @@ pub fn errUnionErrorOffset(payload_ty: Type, mod: *Module) u64 {
10471054 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return 0;
10481055 const payload_align = payload_ty.abiAlignment(mod);
10491056 const error_align = Type.anyerror.abiAlignment(mod);
1050 if (payload_align >= error_align and payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
1051 return mem.alignForward(u64, payload_ty.abiSize(mod), error_align);
1057 if (payload_align.compare(.gte, error_align) and payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
1058 return error_align.forward(payload_ty.abiSize(mod));
10521059 } else {
10531060 return 0;
10541061 }
src/codegen/c.zig+130-134
......@@ -17,6 +17,7 @@ const LazySrcLoc = Module.LazySrcLoc;
1717const Air = @import("../Air.zig");
1818const Liveness = @import("../Liveness.zig");
1919const InternPool = @import("../InternPool.zig");
20const Alignment = InternPool.Alignment;
2021
2122const BigIntLimb = std.math.big.Limb;
2223const BigInt = std.math.big.int;
......@@ -292,7 +293,7 @@ pub const Function = struct {
292293
293294 const result: CValue = if (lowersToArray(ty, mod)) result: {
294295 const writer = f.object.code_header.writer();
295 const alignment = 0;
296 const alignment: Alignment = .none;
296297 const decl_c_value = try f.allocLocalValue(ty, alignment);
297298 const gpa = f.object.dg.gpa;
298299 try f.allocs.put(gpa, decl_c_value.new_local, false);
......@@ -318,25 +319,25 @@ pub const Function = struct {
318319 /// Skips the reuse logic. This function should be used for any persistent allocation, i.e.
319320 /// those which go into `allocs`. This function does not add the resulting local into `allocs`;
320321 /// 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 {
322323 const mod = f.object.dg.module;
323324 const gpa = f.object.dg.gpa;
324325 try f.locals.append(gpa, .{
325326 .cty_idx = try f.typeToIndex(ty, .complete),
326327 .alignas = CType.AlignAs.init(alignment, ty.abiAlignment(mod)),
327328 });
328 return .{ .new_local = @as(LocalIndex, @intCast(f.locals.items.len - 1)) };
329 return .{ .new_local = @intCast(f.locals.items.len - 1) };
329330 }
330331
331332 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);
333334 log.debug("%{d}: allocating t{d}", .{ inst, result.new_local });
334335 return result;
335336 }
336337
337338 /// Only allocates the local; does not print anything. Will attempt to re-use locals, so should
338339 /// 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 {
340341 const mod = f.object.dg.module;
341342 if (f.free_locals_map.getPtr(.{
342343 .cty_idx = try f.typeToIndex(ty, .complete),
......@@ -1299,139 +1300,134 @@ pub const DeclGen = struct {
12991300 }
13001301 try writer.writeByte('}');
13011302 },
1302 .struct_type => |struct_type| {
1303 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
1304 switch (struct_obj.layout) {
1305 .Auto, .Extern => {
1306 if (!location.isInitializer()) {
1303 .struct_type => |struct_type| switch (struct_type.layout) {
1304 .Auto, .Extern => {
1305 if (!location.isInitializer()) {
1306 try writer.writeByte('(');
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);
13071358 try writer.writeByte('(');
1308 try dg.renderType(writer, ty);
1309 try writer.writeByte(')');
13101359 }
13111360
1312 try writer.writeByte('{');
1313 var empty = true;
1314 for (struct_obj.fields.values(), 0..) |field, field_i| {
1315 if (field.is_comptime) continue;
1316 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
1361 var eff_index: usize = 0;
1362 var needs_closing_paren = false;
1363 for (field_types, 0..) |field_ty, field_i| {
1364 if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
13171365
1318 if (!empty) try writer.writeByte(',');
13191366 const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {
13201367 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
1321 .ty = field.ty.toIntern(),
1368 .ty = field_ty,
13221369 .storage = .{ .u64 = bytes[field_i] },
13231370 } }),
13241371 .elems => |elems| elems[field_i],
13251372 .repeated_elem => |elem| elem,
13261373 };
1327 try dg.renderValue(writer, field.ty, 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
1339 var bit_offset: u64 = 0;
1340 var eff_num_fields: usize = 0;
1374 const cast_context = IntCastContext{ .value = .{ .value = field_val.toValue() } };
1375 if (bit_offset != 0) {
1376 try writer.writeAll("zig_shl_");
1377 try dg.renderTypeForBuiltinFnName(writer, ty);
1378 try writer.writeByte('(');
1379 try dg.renderIntCast(writer, ty, cast_context, field_ty.toType(), .FunctionArgument);
1380 try writer.writeAll(", ");
1381 const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset);
1382 try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
1383 try writer.writeByte(')');
1384 } else {
1385 try dg.renderIntCast(writer, ty, cast_context, field_ty.toType(), .FunctionArgument);
1386 }
13411387
1342 for (struct_obj.fields.values()) |field| {
1343 if (field.is_comptime) continue;
1344 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
1388 if (needs_closing_paren) try writer.writeByte(')');
1389 if (eff_index != eff_num_fields - 1) try writer.writeAll(", ");
13451390
1346 eff_num_fields += 1;
1391 bit_offset += field_ty.toType().bitSize(mod);
1392 needs_closing_paren = true;
1393 eff_index += 1;
13471394 }
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(" | ");
13501403 try writer.writeByte('(');
1351 try dg.renderValue(writer, ty, Value.undef, initializer_type);
1404 try dg.renderType(writer, ty);
13521405 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;
1363 var needs_closing_paren = false;
1364 for (struct_obj.fields.values(), 0..) |field, field_i| {
1365 if (field.is_comptime) continue;
1366 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
1367
1368 const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {
1369 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
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(')');
1407 const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {
1408 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
1409 .ty = field_ty,
1410 .storage = .{ .u64 = bytes[field_i] },
1411 } }),
1412 .elems => |elems| elems[field_i],
1413 .repeated_elem => |elem| elem,
1414 };
14091415
1410 const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {
1411 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
1412 .ty = field.ty.toIntern(),
1413 .storage = .{ .u64 = bytes[field_i] },
1414 } }),
1415 .elems => |elems| elems[field_i],
1416 .repeated_elem => |elem| elem,
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;
1416 if (bit_offset != 0) {
1417 try dg.renderValue(writer, field_ty.toType(), field_val.toValue(), .Other);
1418 try writer.writeAll(" << ");
1419 const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset);
1420 try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
1421 } else {
1422 try dg.renderValue(writer, field_ty.toType(), field_val.toValue(), .Other);
14301423 }
1431 try writer.writeByte(')');
1424
1425 bit_offset += field_ty.toType().bitSize(mod);
1426 empty = false;
14321427 }
1433 },
1434 }
1428 try writer.writeByte(')');
1429 }
1430 },
14351431 },
14361432 else => unreachable,
14371433 },
......@@ -1723,7 +1719,7 @@ pub const DeclGen = struct {
17231719 ty: Type,
17241720 name: CValue,
17251721 qualifiers: CQualifiers,
1726 alignment: u64,
1722 alignment: Alignment,
17271723 kind: CType.Kind,
17281724 ) error{ OutOfMemory, AnalysisFail }!void {
17291725 const mod = dg.module;
......@@ -1854,7 +1850,7 @@ pub const DeclGen = struct {
18541850 decl.ty,
18551851 .{ .decl = decl_index },
18561852 CQualifiers.init(.{ .@"const" = variable.is_const }),
1857 @as(u32, @intCast(decl.alignment.toByteUnits(0))),
1853 decl.alignment,
18581854 .complete,
18591855 );
18601856 try fwd_decl_writer.writeAll(";\n");
......@@ -2460,7 +2456,7 @@ pub fn genErrDecls(o: *Object) !void {
24602456 } });
24612457
24622458 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);
24642460 try writer.writeAll(" = ");
24652461 try o.dg.renderValue(writer, name_ty, name_val.toValue(), .StaticInitializer);
24662462 try writer.writeAll(";\n");
......@@ -2472,7 +2468,7 @@ pub fn genErrDecls(o: *Object) !void {
24722468 });
24732469
24742470 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);
24762472 try writer.writeAll(" = {");
24772473 for (mod.global_error_set.keys(), 0..) |name_nts, value| {
24782474 const name = mod.intern_pool.stringToSlice(name_nts);
......@@ -2523,7 +2519,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
25232519 try w.writeByte(' ');
25242520 try w.writeAll(fn_name);
25252521 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);
25272523 try w.writeAll(") {\n switch (tag) {\n");
25282524 for (enum_ty.enumFields(mod), 0..) |name_ip, index_usize| {
25292525 const index = @as(u32, @intCast(index_usize));
......@@ -2546,7 +2542,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
25462542 try w.print(" case {}: {{\n static ", .{
25472543 try o.dg.fmtIntLiteral(enum_ty, int_val, .Other),
25482544 });
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);
25502546 try w.writeAll(" = ");
25512547 try o.dg.renderValue(w, name_ty, name_val.toValue(), .Initializer);
25522548 try w.writeAll(";\n return (");
......@@ -2706,7 +2702,7 @@ pub fn genDecl(o: *Object) !void {
27062702 if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage ");
27072703 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s|
27082704 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);
27102706 if (decl.@"linksection" != .none) try w.writeAll(", read, write)");
27112707 try w.writeAll(" = ");
27122708 try o.dg.renderValue(w, tv.ty, variable.init.toValue(), .StaticInitializer);
......@@ -2717,14 +2713,14 @@ pub fn genDecl(o: *Object) !void {
27172713 const fwd_decl_writer = o.dg.fwd_decl.writer();
27182714
27192715 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);
27212717 try fwd_decl_writer.writeAll(";\n");
27222718
27232719 const w = o.writer();
27242720 if (!is_global) try w.writeAll("static ");
27252721 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s|
27262722 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);
27282724 if (decl.@"linksection" != .none) try w.writeAll(", read)");
27292725 try w.writeAll(" = ");
27302726 try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer);
......@@ -3353,8 +3349,8 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
33533349
33543350 try reap(f, inst, &.{ty_op.operand});
33553351
3356 const is_aligned = if (ptr_info.flags.alignment.toByteUnitsOptional()) |alignment|
3357 alignment >= src_ty.abiAlignment(mod)
3352 const is_aligned = if (ptr_info.flags.alignment != .none)
3353 ptr_info.flags.alignment.compare(.gte, src_ty.abiAlignment(mod))
33583354 else
33593355 true;
33603356 const is_array = lowersToArray(src_ty, mod);
......@@ -3625,8 +3621,8 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
36253621 return .none;
36263622 }
36273623
3628 const is_aligned = if (ptr_info.flags.alignment.toByteUnitsOptional()) |alignment|
3629 alignment >= src_ty.abiAlignment(mod)
3624 const is_aligned = if (ptr_info.flags.alignment != .none)
3625 ptr_info.flags.alignment.compare(.gte, src_ty.abiAlignment(mod))
36303626 else
36313627 true;
36323628 const is_array = lowersToArray(ptr_info.child.toType(), mod);
......@@ -4847,7 +4843,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
48474843 if (is_reg) {
48484844 const output_ty = if (output == .none) inst_ty else f.typeOf(output).childType(mod);
48494845 try writer.writeAll("register ");
4850 const alignment = 0;
4846 const alignment: Alignment = .none;
48514847 const local_value = try f.allocLocalValue(output_ty, alignment);
48524848 try f.allocs.put(gpa, local_value.new_local, false);
48534849 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 {
48804876 if (asmInputNeedsLocal(f, constraint, input_val)) {
48814877 const input_ty = f.typeOf(input);
48824878 if (is_reg) try writer.writeAll("register ");
4883 const alignment = 0;
4879 const alignment: Alignment = .none;
48844880 const local_value = try f.allocLocalValue(input_ty, alignment);
48854881 try f.allocs.put(gpa, local_value.new_local, false);
48864882 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 {
54275423 else
54285424 .{ .identifier = ip.stringToSlice(struct_ty.structFieldName(extra.field_index, mod)) },
54295425 .Packed => {
5430 const struct_obj = mod.typeToStruct(struct_ty).?;
5426 const struct_type = mod.typeToStruct(struct_ty).?;
54315427 const int_info = struct_ty.intInfo(mod);
54325428
54335429 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);
54365432 const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset);
54375433
54385434 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 {
283283 @"align": Alignment,
284284 abi: Alignment,
285285
286 pub fn init(alignment: u64, abi_alignment: u32) AlignAs {
287 const @"align" = Alignment.fromByteUnits(alignment);
288 const abi_align = Alignment.fromNonzeroByteUnits(abi_alignment);
286 pub fn init(@"align": Alignment, abi_align: Alignment) AlignAs {
287 assert(abi_align != .none);
289288 return .{
290289 .@"align" = if (@"align" != .none) @"align" else abi_align,
291290 .abi = abi_align,
292291 };
293292 }
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 }
294300 pub fn abiAlign(ty: Type, mod: *Module) AlignAs {
295301 const abi_align = ty.abiAlignment(mod);
296302 return init(abi_align, abi_align);
......@@ -1360,6 +1366,7 @@ pub const CType = extern union {
13601366
13611367 pub fn initType(self: *@This(), ty: Type, kind: Kind, lookup: Lookup) !void {
13621368 const mod = lookup.getModule();
1369 const ip = &mod.intern_pool;
13631370
13641371 self.* = undefined;
13651372 if (!ty.isFnOrHasRuntimeBitsIgnoreComptime(mod))
......@@ -1382,12 +1389,12 @@ pub const CType = extern union {
13821389 .array => switch (kind) {
13831390 .forward, .complete, .global => {
13841391 const abi_size = ty.abiSize(mod);
1385 const abi_align = ty.abiAlignment(mod);
1392 const abi_align = ty.abiAlignment(mod).toByteUnits(0);
13861393 self.storage = .{ .seq = .{ .base = .{ .tag = .array }, .data = .{
13871394 .len = @divExact(abi_size, abi_align),
13881395 .elem_type = tagFromIntInfo(.{
13891396 .signedness = .unsigned,
1390 .bits = @as(u16, @intCast(abi_align * 8)),
1397 .bits = @intCast(abi_align * 8),
13911398 }).toIndex(),
13921399 } } };
13931400 self.value = .{ .cty = initPayload(&self.storage.seq) };
......@@ -1488,10 +1495,10 @@ pub const CType = extern union {
14881495 },
14891496
14901497 .Struct, .Union => |zig_ty_tag| if (ty.containerLayout(mod) == .Packed) {
1491 if (mod.typeToStruct(ty)) |struct_obj| {
1492 try self.initType(struct_obj.backing_int_ty, kind, lookup);
1498 if (mod.typeToPackedStruct(ty)) |packed_struct| {
1499 try self.initType(packed_struct.backingIntType(ip).toType(), kind, lookup);
14931500 } else {
1494 const bits = @as(u16, @intCast(ty.bitSize(mod)));
1501 const bits: u16 = @intCast(ty.bitSize(mod));
14951502 const int_ty = try mod.intType(.unsigned, bits);
14961503 try self.initType(int_ty, kind, lookup);
14971504 }
......@@ -1722,7 +1729,6 @@ pub const CType = extern union {
17221729
17231730 .Fn => {
17241731 const info = mod.typeToFunc(ty).?;
1725 const ip = &mod.intern_pool;
17261732 if (!info.is_generic) {
17271733 if (lookup.isMutable()) {
17281734 const param_kind: Kind = switch (kind) {
src/codegen/llvm.zig+300-289
......@@ -1076,7 +1076,7 @@ pub const Object = struct {
10761076 table_variable_index.setMutability(.constant, &o.builder);
10771077 table_variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
10781078 table_variable_index.setAlignment(
1079 Builder.Alignment.fromByteUnits(slice_ty.abiAlignment(mod)),
1079 slice_ty.abiAlignment(mod).toLlvm(),
10801080 &o.builder,
10811081 );
10821082
......@@ -1318,8 +1318,9 @@ pub const Object = struct {
13181318 _ = try attributes.removeFnAttr(.@"noinline");
13191319 }
13201320
1321 if (func.analysis(ip).stack_alignment.toByteUnitsOptional()) |alignment| {
1322 try attributes.addFnAttr(.{ .alignstack = Builder.Alignment.fromByteUnits(alignment) }, &o.builder);
1321 const stack_alignment = func.analysis(ip).stack_alignment;
1322 if (stack_alignment != .none) {
1323 try attributes.addFnAttr(.{ .alignstack = stack_alignment.toLlvm() }, &o.builder);
13231324 try attributes.addFnAttr(.@"noinline", &o.builder);
13241325 } else {
13251326 _ = try attributes.removeFnAttr(.alignstack);
......@@ -1407,7 +1408,7 @@ pub const Object = struct {
14071408 const param = wip.arg(llvm_arg_i);
14081409
14091410 if (isByRef(param_ty, mod)) {
1410 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
1411 const alignment = param_ty.abiAlignment(mod).toLlvm();
14111412 const param_llvm_ty = param.typeOfWip(&wip);
14121413 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
14131414 _ = try wip.store(.normal, param, arg_ptr, alignment);
......@@ -1423,7 +1424,7 @@ pub const Object = struct {
14231424 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
14241425 const param_llvm_ty = try o.lowerType(param_ty);
14251426 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
14281429 try o.addByRefParamAttrs(&attributes, llvm_arg_i, alignment, it.byval_attr, param_llvm_ty);
14291430 llvm_arg_i += 1;
......@@ -1438,7 +1439,7 @@ pub const Object = struct {
14381439 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
14391440 const param_llvm_ty = try o.lowerType(param_ty);
14401441 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
14431444 try attributes.addParamAttr(llvm_arg_i, .noundef, &o.builder);
14441445 llvm_arg_i += 1;
......@@ -1456,7 +1457,7 @@ pub const Object = struct {
14561457 llvm_arg_i += 1;
14571458
14581459 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();
14601461 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
14611462 _ = try wip.store(.normal, param, arg_ptr, alignment);
14621463
......@@ -1481,10 +1482,10 @@ pub const Object = struct {
14811482 if (ptr_info.flags.is_const) {
14821483 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
14831484 }
1484 const elem_align = Builder.Alignment.fromByteUnits(
1485 ptr_info.flags.alignment.toByteUnitsOptional() orelse
1486 @max(ptr_info.child.toType().abiAlignment(mod), 1),
1487 );
1485 const elem_align = (if (ptr_info.flags.alignment != .none)
1486 @as(InternPool.Alignment, ptr_info.flags.alignment)
1487 else
1488 ptr_info.child.toType().abiAlignment(mod).max(.@"1")).toLlvm();
14881489 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
14891490 const ptr_param = wip.arg(llvm_arg_i);
14901491 llvm_arg_i += 1;
......@@ -1501,7 +1502,7 @@ pub const Object = struct {
15011502 const field_types = it.types_buffer[0..it.types_len];
15021503 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
15031504 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();
15051506 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, param_alignment, target);
15061507 const llvm_ty = try o.builder.structType(.normal, field_types);
15071508 for (0..field_types.len) |field_i| {
......@@ -1531,7 +1532,7 @@ pub const Object = struct {
15311532 const param = wip.arg(llvm_arg_i);
15321533 llvm_arg_i += 1;
15331534
1534 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
1535 const alignment = param_ty.abiAlignment(mod).toLlvm();
15351536 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
15361537 _ = try wip.store(.normal, param, arg_ptr, alignment);
15371538
......@@ -1546,7 +1547,7 @@ pub const Object = struct {
15461547 const param = wip.arg(llvm_arg_i);
15471548 llvm_arg_i += 1;
15481549
1549 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
1550 const alignment = param_ty.abiAlignment(mod).toLlvm();
15501551 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
15511552 _ = try wip.store(.normal, param, arg_ptr, alignment);
15521553
......@@ -1967,7 +1968,7 @@ pub const Object = struct {
19671968 di_file,
19681969 owner_decl.src_node + 1,
19691970 ty.abiSize(mod) * 8,
1970 ty.abiAlignment(mod) * 8,
1971 ty.abiAlignment(mod).toByteUnits(0) * 8,
19711972 enumerators.ptr,
19721973 @intCast(enumerators.len),
19731974 try o.lowerDebugType(int_ty, .full),
......@@ -2055,7 +2056,7 @@ pub const Object = struct {
20552056
20562057 var offset: u64 = 0;
20572058 offset += ptr_size;
2058 offset = std.mem.alignForward(u64, offset, len_align);
2059 offset = len_align.forward(offset);
20592060 const len_offset = offset;
20602061
20612062 const fields: [2]*llvm.DIType = .{
......@@ -2065,7 +2066,7 @@ pub const Object = struct {
20652066 di_file,
20662067 line,
20672068 ptr_size * 8, // size in bits
2068 ptr_align * 8, // align in bits
2069 ptr_align.toByteUnits(0) * 8, // align in bits
20692070 0, // offset in bits
20702071 0, // flags
20712072 try o.lowerDebugType(ptr_ty, .full),
......@@ -2076,7 +2077,7 @@ pub const Object = struct {
20762077 di_file,
20772078 line,
20782079 len_size * 8, // size in bits
2079 len_align * 8, // align in bits
2080 len_align.toByteUnits(0) * 8, // align in bits
20802081 len_offset * 8, // offset in bits
20812082 0, // flags
20822083 try o.lowerDebugType(len_ty, .full),
......@@ -2089,7 +2090,7 @@ pub const Object = struct {
20892090 di_file,
20902091 line,
20912092 ty.abiSize(mod) * 8, // size in bits
2092 ty.abiAlignment(mod) * 8, // align in bits
2093 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
20932094 0, // flags
20942095 null, // derived from
20952096 &fields,
......@@ -2110,7 +2111,7 @@ pub const Object = struct {
21102111 const ptr_di_ty = dib.createPointerType(
21112112 elem_di_ty,
21122113 target.ptrBitWidth(),
2113 ty.ptrAlignment(mod) * 8,
2114 ty.ptrAlignment(mod).toByteUnits(0) * 8,
21142115 name,
21152116 );
21162117 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
......@@ -2142,7 +2143,7 @@ pub const Object = struct {
21422143 .Array => {
21432144 const array_di_ty = dib.createArrayType(
21442145 ty.abiSize(mod) * 8,
2145 ty.abiAlignment(mod) * 8,
2146 ty.abiAlignment(mod).toByteUnits(0) * 8,
21462147 try o.lowerDebugType(ty.childType(mod), .full),
21472148 @intCast(ty.arrayLen(mod)),
21482149 );
......@@ -2174,7 +2175,7 @@ pub const Object = struct {
21742175
21752176 const vector_di_ty = dib.createVectorType(
21762177 ty.abiSize(mod) * 8,
2177 ty.abiAlignment(mod) * 8,
2178 @intCast(ty.abiAlignment(mod).toByteUnits(0) * 8),
21782179 elem_di_type,
21792180 ty.vectorLen(mod),
21802181 );
......@@ -2223,7 +2224,7 @@ pub const Object = struct {
22232224
22242225 var offset: u64 = 0;
22252226 offset += payload_size;
2226 offset = std.mem.alignForward(u64, offset, non_null_align);
2227 offset = non_null_align.forward(offset);
22272228 const non_null_offset = offset;
22282229
22292230 const fields: [2]*llvm.DIType = .{
......@@ -2233,7 +2234,7 @@ pub const Object = struct {
22332234 di_file,
22342235 line,
22352236 payload_size * 8, // size in bits
2236 payload_align * 8, // align in bits
2237 payload_align.toByteUnits(0) * 8, // align in bits
22372238 0, // offset in bits
22382239 0, // flags
22392240 try o.lowerDebugType(child_ty, .full),
......@@ -2244,7 +2245,7 @@ pub const Object = struct {
22442245 di_file,
22452246 line,
22462247 non_null_size * 8, // size in bits
2247 non_null_align * 8, // align in bits
2248 non_null_align.toByteUnits(0) * 8, // align in bits
22482249 non_null_offset * 8, // offset in bits
22492250 0, // flags
22502251 try o.lowerDebugType(non_null_ty, .full),
......@@ -2257,7 +2258,7 @@ pub const Object = struct {
22572258 di_file,
22582259 line,
22592260 ty.abiSize(mod) * 8, // size in bits
2260 ty.abiAlignment(mod) * 8, // align in bits
2261 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
22612262 0, // flags
22622263 null, // derived from
22632264 &fields,
......@@ -2306,16 +2307,16 @@ pub const Object = struct {
23062307 var payload_index: u32 = undefined;
23072308 var error_offset: u64 = undefined;
23082309 var payload_offset: u64 = undefined;
2309 if (error_align > payload_align) {
2310 if (error_align.compare(.gt, payload_align)) {
23102311 error_index = 0;
23112312 payload_index = 1;
23122313 error_offset = 0;
2313 payload_offset = std.mem.alignForward(u64, error_size, payload_align);
2314 payload_offset = payload_align.forward(error_size);
23142315 } else {
23152316 payload_index = 0;
23162317 error_index = 1;
23172318 payload_offset = 0;
2318 error_offset = std.mem.alignForward(u64, payload_size, error_align);
2319 error_offset = error_align.forward(payload_size);
23192320 }
23202321
23212322 var fields: [2]*llvm.DIType = undefined;
......@@ -2325,7 +2326,7 @@ pub const Object = struct {
23252326 di_file,
23262327 line,
23272328 error_size * 8, // size in bits
2328 error_align * 8, // align in bits
2329 error_align.toByteUnits(0) * 8, // align in bits
23292330 error_offset * 8, // offset in bits
23302331 0, // flags
23312332 try o.lowerDebugType(Type.anyerror, .full),
......@@ -2336,7 +2337,7 @@ pub const Object = struct {
23362337 di_file,
23372338 line,
23382339 payload_size * 8, // size in bits
2339 payload_align * 8, // align in bits
2340 payload_align.toByteUnits(0) * 8, // align in bits
23402341 payload_offset * 8, // offset in bits
23412342 0, // flags
23422343 try o.lowerDebugType(payload_ty, .full),
......@@ -2348,7 +2349,7 @@ pub const Object = struct {
23482349 di_file,
23492350 line,
23502351 ty.abiSize(mod) * 8, // size in bits
2351 ty.abiAlignment(mod) * 8, // align in bits
2352 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
23522353 0, // flags
23532354 null, // derived from
23542355 &fields,
......@@ -2374,10 +2375,10 @@ pub const Object = struct {
23742375 const name = try o.allocTypeName(ty);
23752376 defer gpa.free(name);
23762377
2377 if (mod.typeToStruct(ty)) |struct_obj| {
2378 if (struct_obj.layout == .Packed and struct_obj.haveFieldTypes()) {
2379 assert(struct_obj.haveLayout());
2380 const info = struct_obj.backing_int_ty.intInfo(mod);
2378 if (mod.typeToPackedStruct(ty)) |struct_type| {
2379 const backing_int_ty = struct_type.backingIntType(ip).*;
2380 if (backing_int_ty != .none) {
2381 const info = backing_int_ty.toType().intInfo(mod);
23812382 const dwarf_encoding: c_uint = switch (info.signedness) {
23822383 .signed => DW.ATE.signed,
23832384 .unsigned => DW.ATE.unsigned,
......@@ -2417,7 +2418,7 @@ pub const Object = struct {
24172418
24182419 const field_size = field_ty.toType().abiSize(mod);
24192420 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);
24212422 offset = field_offset + field_size;
24222423
24232424 const field_name = if (tuple.names.len != 0)
......@@ -2432,7 +2433,7 @@ pub const Object = struct {
24322433 null, // file
24332434 0, // line
24342435 field_size * 8, // size in bits
2435 field_align * 8, // align in bits
2436 field_align.toByteUnits(0) * 8, // align in bits
24362437 field_offset * 8, // offset in bits
24372438 0, // flags
24382439 try o.lowerDebugType(field_ty.toType(), .full),
......@@ -2445,7 +2446,7 @@ pub const Object = struct {
24452446 null, // file
24462447 0, // line
24472448 ty.abiSize(mod) * 8, // size in bits
2448 ty.abiAlignment(mod) * 8, // align in bits
2449 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
24492450 0, // flags
24502451 null, // derived from
24512452 di_fields.items.ptr,
......@@ -2459,10 +2460,8 @@ pub const Object = struct {
24592460 try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(full_di_ty));
24602461 return full_di_ty;
24612462 },
2462 .struct_type => |struct_type| s: {
2463 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :s;
2464
2465 if (!struct_obj.haveFieldTypes()) {
2463 .struct_type => |struct_type| {
2464 if (!struct_type.haveFieldTypes(ip)) {
24662465 // This can happen if a struct type makes it all the way to
24672466 // flush() without ever being instantiated or referenced (even
24682467 // via pointer). The only reason we are hearing about it now is
......@@ -2492,26 +2491,30 @@ pub const Object = struct {
24922491 return struct_di_ty;
24932492 }
24942493
2495 const fields = ty.structFields(mod);
2496 const layout = ty.containerLayout(mod);
2494 const struct_type = mod.typeToStruct(ty).?;
2495 const field_types = struct_type.field_types.get(ip);
2496 const field_names = struct_type.field_names.get(ip);
24972497
24982498 var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
24992499 defer di_fields.deinit(gpa);
25002500
2501 try di_fields.ensureUnusedCapacity(gpa, fields.count());
2501 try di_fields.ensureUnusedCapacity(gpa, field_types.len);
25022502
25032503 comptime assert(struct_layout_version == 2);
25042504 var offset: u64 = 0;
2505
2506 var it = mod.typeToStruct(ty).?.runtimeFieldIterator(mod);
2507 while (it.next()) |field_and_index| {
2508 const field = field_and_index.field;
2509 const field_size = field.ty.abiSize(mod);
2510 const field_align = field.alignment(mod, layout);
2511 const field_offset = std.mem.alignForward(u64, offset, field_align);
2505 var it = struct_type.iterateRuntimeOrder(ip);
2506 while (it.next()) |field_index| {
2507 const field_ty = field_types[field_index].toType();
2508 const field_size = field_ty.abiSize(mod);
2509 const field_align = mod.structFieldAlignment(
2510 struct_type.fieldAlign(ip, field_index),
2511 field_ty,
2512 struct_type.layout,
2513 );
2514 const field_offset = field_align.forward(offset);
25122515 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
25162519 try di_fields.append(gpa, dib.createMemberType(
25172520 fwd_decl.toScope(),
......@@ -2519,10 +2522,10 @@ pub const Object = struct {
25192522 null, // file
25202523 0, // line
25212524 field_size * 8, // size in bits
2522 field_align * 8, // align in bits
2525 field_align.toByteUnits(0) * 8, // align in bits
25232526 field_offset * 8, // offset in bits
25242527 0, // flags
2525 try o.lowerDebugType(field.ty, .full),
2528 try o.lowerDebugType(field_ty, .full),
25262529 ));
25272530 }
25282531
......@@ -2532,7 +2535,7 @@ pub const Object = struct {
25322535 null, // file
25332536 0, // line
25342537 ty.abiSize(mod) * 8, // size in bits
2535 ty.abiAlignment(mod) * 8, // align in bits
2538 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
25362539 0, // flags
25372540 null, // derived from
25382541 di_fields.items.ptr,
......@@ -2588,7 +2591,7 @@ pub const Object = struct {
25882591 null, // file
25892592 0, // line
25902593 ty.abiSize(mod) * 8, // size in bits
2591 ty.abiAlignment(mod) * 8, // align in bits
2594 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
25922595 0, // flags
25932596 null, // derived from
25942597 &di_fields,
......@@ -2624,7 +2627,7 @@ pub const Object = struct {
26242627 null, // file
26252628 0, // line
26262629 field_size * 8, // size in bits
2627 field_align * 8, // align in bits
2630 field_align.toByteUnits(0) * 8, // align in bits
26282631 0, // offset in bits
26292632 0, // flags
26302633 field_di_ty,
......@@ -2644,7 +2647,7 @@ pub const Object = struct {
26442647 null, // file
26452648 0, // line
26462649 ty.abiSize(mod) * 8, // size in bits
2647 ty.abiAlignment(mod) * 8, // align in bits
2650 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
26482651 0, // flags
26492652 di_fields.items.ptr,
26502653 @intCast(di_fields.items.len),
......@@ -2661,12 +2664,12 @@ pub const Object = struct {
26612664
26622665 var tag_offset: u64 = undefined;
26632666 var payload_offset: u64 = undefined;
2664 if (layout.tag_align >= layout.payload_align) {
2667 if (layout.tag_align.compare(.gte, layout.payload_align)) {
26652668 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);
26672670 } else {
26682671 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);
26702673 }
26712674
26722675 const tag_di = dib.createMemberType(
......@@ -2675,7 +2678,7 @@ pub const Object = struct {
26752678 null, // file
26762679 0, // line
26772680 layout.tag_size * 8,
2678 layout.tag_align * 8, // align in bits
2681 layout.tag_align.toByteUnits(0) * 8,
26792682 tag_offset * 8, // offset in bits
26802683 0, // flags
26812684 try o.lowerDebugType(union_obj.enum_tag_ty.toType(), .full),
......@@ -2687,14 +2690,14 @@ pub const Object = struct {
26872690 null, // file
26882691 0, // line
26892692 layout.payload_size * 8, // size in bits
2690 layout.payload_align * 8, // align in bits
2693 layout.payload_align.toByteUnits(0) * 8,
26912694 payload_offset * 8, // offset in bits
26922695 0, // flags
26932696 union_di_ty,
26942697 );
26952698
26962699 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))
26982701 .{ tag_di, payload_di }
26992702 else
27002703 .{ payload_di, tag_di };
......@@ -2705,7 +2708,7 @@ pub const Object = struct {
27052708 null, // file
27062709 0, // line
27072710 ty.abiSize(mod) * 8, // size in bits
2708 ty.abiAlignment(mod) * 8, // align in bits
2711 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
27092712 0, // flags
27102713 null, // derived from
27112714 &full_di_fields,
......@@ -2925,8 +2928,8 @@ pub const Object = struct {
29252928 else => function_index.setCallConv(toLlvmCallConv(fn_info.cc, target), &o.builder),
29262929 }
29272930
2928 if (fn_info.alignment.toByteUnitsOptional()) |alignment|
2929 function_index.setAlignment(Builder.Alignment.fromByteUnits(alignment), &o.builder);
2931 if (fn_info.alignment != .none)
2932 function_index.setAlignment(fn_info.alignment.toLlvm(), &o.builder);
29302933
29312934 // Function attributes that are independent of analysis results of the function body.
29322935 try o.addCommonFnAttributes(&attributes);
......@@ -2949,9 +2952,8 @@ pub const Object = struct {
29492952 .byref => {
29502953 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1];
29512954 const param_llvm_ty = try o.lowerType(param_ty.toType());
2952 const alignment =
2953 Builder.Alignment.fromByteUnits(param_ty.toType().abiAlignment(mod));
2954 try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
2955 const alignment = param_ty.toType().abiAlignment(mod);
2956 try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment.toLlvm(), it.byval_attr, param_llvm_ty);
29552957 },
29562958 .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder),
29572959 // No attributes needed for these.
......@@ -3248,21 +3250,21 @@ pub const Object = struct {
32483250
32493251 var fields: [3]Builder.Type = undefined;
32503252 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: {
32523254 fields[0] = error_type;
32533255 fields[1] = payload_type;
32543256 const payload_end =
3255 std.mem.alignForward(u64, error_size, payload_align) +
3257 payload_align.forward(error_size) +
32563258 payload_size;
3257 const abi_size = std.mem.alignForward(u64, payload_end, error_align);
3259 const abi_size = error_align.forward(payload_end);
32583260 break :pad abi_size - payload_end;
32593261 } else pad: {
32603262 fields[0] = payload_type;
32613263 fields[1] = error_type;
32623264 const error_end =
3263 std.mem.alignForward(u64, payload_size, error_align) +
3265 error_align.forward(payload_size) +
32643266 error_size;
3265 const abi_size = std.mem.alignForward(u64, error_end, payload_align);
3267 const abi_size = payload_align.forward(error_end);
32663268 break :pad abi_size - error_end;
32673269 };
32683270 if (padding_len > 0) {
......@@ -3276,43 +3278,44 @@ pub const Object = struct {
32763278 const gop = try o.type_map.getOrPut(o.gpa, t.toIntern());
32773279 if (gop.found_existing) return gop.value_ptr.*;
32783280
3279 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
3280 if (struct_obj.layout == .Packed) {
3281 assert(struct_obj.haveLayout());
3282 const int_ty = try o.lowerType(struct_obj.backing_int_ty);
3281 if (struct_type.layout == .Packed) {
3282 const int_ty = try o.lowerType(struct_type.backingIntType(ip).toType());
32833283 gop.value_ptr.* = int_ty;
32843284 return int_ty;
32853285 }
32863286
32873287 const name = try o.builder.string(ip.stringToSlice(
3288 try struct_obj.getFullyQualifiedName(mod),
3288 try mod.declPtr(struct_type.decl.unwrap().?).getFullyQualifiedName(mod),
32893289 ));
32903290 const ty = try o.builder.opaqueType(name);
32913291 gop.value_ptr.* = ty; // must be done before any recursive calls
32923292
3293 assert(struct_obj.haveFieldTypes());
3294
32953293 var llvm_field_types = std.ArrayListUnmanaged(Builder.Type){};
32963294 defer llvm_field_types.deinit(o.gpa);
32973295 // Although we can estimate how much capacity to add, these cannot be
32983296 // relied upon because of the recursive calls to lowerType below.
3299 try llvm_field_types.ensureUnusedCapacity(o.gpa, struct_obj.fields.count());
3300 try o.struct_field_map.ensureUnusedCapacity(o.gpa, @intCast(struct_obj.fields.count()));
3297 try llvm_field_types.ensureUnusedCapacity(o.gpa, struct_type.field_types.len);
3298 try o.struct_field_map.ensureUnusedCapacity(o.gpa, struct_type.field_types.len);
33013299
33023300 comptime assert(struct_layout_version == 2);
33033301 var offset: u64 = 0;
3304 var big_align: u32 = 1;
3302 var big_align: InternPool.Alignment = .@"1";
33053303 var struct_kind: Builder.Type.Structure.Kind = .normal;
33063304
3307 var it = struct_obj.runtimeFieldIterator(mod);
3308 while (it.next()) |field_and_index| {
3309 const field = field_and_index.field;
3310 const field_align = field.alignment(mod, struct_obj.layout);
3311 const field_ty_align = field.ty.abiAlignment(mod);
3312 if (field_align < field_ty_align) struct_kind = .@"packed";
3313 big_align = @max(big_align, field_align);
3305 for (struct_type.runtime_order.get(ip)) |runtime_index| {
3306 const field_index = runtime_index.toInt() orelse break;
3307 const field_ty = struct_type.field_types.get(ip)[field_index].toType();
3308 const field_aligns = struct_type.field_aligns.get(ip);
3309 const field_align = mod.structFieldAlignment(
3310 if (field_aligns.len == 0) .none else field_aligns[field_index],
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);
33143317 const prev_offset = offset;
3315 offset = std.mem.alignForward(u64, offset, field_align);
3318 offset = field_align.forward(offset);
33163319
33173320 const padding_len = offset - prev_offset;
33183321 if (padding_len > 0) try llvm_field_types.append(
......@@ -3321,15 +3324,15 @@ pub const Object = struct {
33213324 );
33223325 try o.struct_field_map.put(o.gpa, .{
33233326 .struct_ty = t.toIntern(),
3324 .field_index = field_and_index.index,
3327 .field_index = field_index,
33253328 }, @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);
33293332 }
33303333 {
33313334 const prev_offset = offset;
3332 offset = std.mem.alignForward(u64, offset, big_align);
3335 offset = big_align.forward(offset);
33333336 const padding_len = offset - prev_offset;
33343337 if (padding_len > 0) try llvm_field_types.append(
33353338 o.gpa,
......@@ -3353,7 +3356,7 @@ pub const Object = struct {
33533356
33543357 comptime assert(struct_layout_version == 2);
33553358 var offset: u64 = 0;
3356 var big_align: u32 = 0;
3359 var big_align: InternPool.Alignment = .none;
33573360
33583361 for (
33593362 anon_struct_type.types.get(ip),
......@@ -3363,9 +3366,9 @@ pub const Object = struct {
33633366 if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue;
33643367
33653368 const field_align = field_ty.toType().abiAlignment(mod);
3366 big_align = @max(big_align, field_align);
3369 big_align = big_align.max(field_align);
33673370 const prev_offset = offset;
3368 offset = std.mem.alignForward(u64, offset, field_align);
3371 offset = field_align.forward(offset);
33693372
33703373 const padding_len = offset - prev_offset;
33713374 if (padding_len > 0) try llvm_field_types.append(
......@@ -3382,7 +3385,7 @@ pub const Object = struct {
33823385 }
33833386 {
33843387 const prev_offset = offset;
3385 offset = std.mem.alignForward(u64, offset, big_align);
3388 offset = big_align.forward(offset);
33863389 const padding_len = offset - prev_offset;
33873390 if (padding_len > 0) try llvm_field_types.append(
33883391 o.gpa,
......@@ -3447,7 +3450,7 @@ pub const Object = struct {
34473450 var llvm_fields: [3]Builder.Type = undefined;
34483451 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)) {
34513454 llvm_fields = .{ enum_tag_ty, payload_ty, .none };
34523455 } else {
34533456 llvm_fields = .{ payload_ty, enum_tag_ty, .none };
......@@ -3687,7 +3690,7 @@ pub const Object = struct {
36873690
36883691 var fields: [3]Builder.Type = undefined;
36893692 var vals: [3]Builder.Constant = undefined;
3690 if (error_align > payload_align) {
3693 if (error_align.compare(.gt, payload_align)) {
36913694 vals[0] = llvm_error_value;
36923695 vals[1] = llvm_payload_value;
36933696 } else {
......@@ -3910,7 +3913,7 @@ pub const Object = struct {
39103913 comptime assert(struct_layout_version == 2);
39113914 var llvm_index: usize = 0;
39123915 var offset: u64 = 0;
3913 var big_align: u32 = 0;
3916 var big_align: InternPool.Alignment = .none;
39143917 var need_unnamed = false;
39153918 for (
39163919 tuple.types.get(ip),
......@@ -3921,9 +3924,9 @@ pub const Object = struct {
39213924 if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
39223925
39233926 const field_align = field_ty.toType().abiAlignment(mod);
3924 big_align = @max(big_align, field_align);
3927 big_align = big_align.max(field_align);
39253928 const prev_offset = offset;
3926 offset = std.mem.alignForward(u64, offset, field_align);
3929 offset = field_align.forward(offset);
39273930
39283931 const padding_len = offset - prev_offset;
39293932 if (padding_len > 0) {
......@@ -3946,7 +3949,7 @@ pub const Object = struct {
39463949 }
39473950 {
39483951 const prev_offset = offset;
3949 offset = std.mem.alignForward(u64, offset, big_align);
3952 offset = big_align.forward(offset);
39503953 const padding_len = offset - prev_offset;
39513954 if (padding_len > 0) {
39523955 fields[llvm_index] = try o.builder.arrayType(padding_len, .i8);
......@@ -3963,22 +3966,21 @@ pub const Object = struct {
39633966 struct_ty, vals);
39643967 },
39653968 .struct_type => |struct_type| {
3966 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
3967 assert(struct_obj.haveLayout());
3969 assert(struct_type.haveLayout(ip));
39683970 const struct_ty = try o.lowerType(ty);
3969 if (struct_obj.layout == .Packed) {
3971 if (struct_type.layout == .Packed) {
39703972 comptime assert(Type.packed_struct_layout_version == 2);
39713973 var running_int = try o.builder.intConst(struct_ty, 0);
39723974 var running_bits: u16 = 0;
3973 for (struct_obj.fields.values(), 0..) |field, field_index| {
3974 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
3975 for (struct_type.field_types.get(ip), 0..) |field_ty, field_index| {
3976 if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
39753977
39763978 const non_int_val =
39773979 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));
39793981 const small_int_ty = try o.builder.intType(ty_bit_size);
39803982 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,
39823984 non_int_val,
39833985 small_int_ty,
39843986 );
......@@ -4010,15 +4012,19 @@ pub const Object = struct {
40104012 comptime assert(struct_layout_version == 2);
40114013 var llvm_index: usize = 0;
40124014 var offset: u64 = 0;
4013 var big_align: u32 = 0;
4015 var big_align: InternPool.Alignment = .none;
40144016 var need_unnamed = false;
4015 var field_it = struct_obj.runtimeFieldIterator(mod);
4016 while (field_it.next()) |field_and_index| {
4017 const field = field_and_index.field;
4018 const field_align = field.alignment(mod, struct_obj.layout);
4019 big_align = @max(big_align, field_align);
4017 var field_it = struct_type.iterateRuntimeOrder(ip);
4018 while (field_it.next()) |field_index| {
4019 const field_ty = struct_type.field_types.get(ip)[field_index];
4020 const field_align = mod.structFieldAlignment(
4021 struct_type.fieldAlign(ip, field_index),
4022 field_ty.toType(),
4023 struct_type.layout,
4024 );
4025 big_align = big_align.max(field_align);
40204026 const prev_offset = offset;
4021 offset = std.mem.alignForward(u64, offset, field_align);
4027 offset = field_align.forward(offset);
40224028
40234029 const padding_len = offset - prev_offset;
40244030 if (padding_len > 0) {
......@@ -4032,18 +4038,18 @@ pub const Object = struct {
40324038 }
40334039
40344040 vals[llvm_index] = try o.lowerValue(
4035 (try val.fieldValue(mod, field_and_index.index)).toIntern(),
4041 (try val.fieldValue(mod, field_index)).toIntern(),
40364042 );
40374043 fields[llvm_index] = vals[llvm_index].typeOf(&o.builder);
40384044 if (fields[llvm_index] != struct_ty.structFields(&o.builder)[llvm_index])
40394045 need_unnamed = true;
40404046 llvm_index += 1;
40414047
4042 offset += field.ty.abiSize(mod);
4048 offset += field_ty.toType().abiSize(mod);
40434049 }
40444050 {
40454051 const prev_offset = offset;
4046 offset = std.mem.alignForward(u64, offset, big_align);
4052 offset = big_align.forward(offset);
40474053 const padding_len = offset - prev_offset;
40484054 if (padding_len > 0) {
40494055 fields[llvm_index] = try o.builder.arrayType(padding_len, .i8);
......@@ -4093,7 +4099,7 @@ pub const Object = struct {
40934099 const payload = try o.lowerValue(un.val);
40944100 const payload_ty = payload.typeOf(&o.builder);
40954101 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))
40974103 ]) need_unnamed = true;
40984104 const field_size = field_ty.abiSize(mod);
40994105 if (field_size == layout.payload_size) break :p payload;
......@@ -4115,7 +4121,7 @@ pub const Object = struct {
41154121 var fields: [3]Builder.Type = undefined;
41164122 var vals: [3]Builder.Constant = undefined;
41174123 var len: usize = 2;
4118 if (layout.tag_align >= layout.payload_align) {
4124 if (layout.tag_align.compare(.gte, layout.payload_align)) {
41194125 fields = .{ tag_ty, payload_ty, undefined };
41204126 vals = .{ tag, payload, undefined };
41214127 } else {
......@@ -4174,14 +4180,15 @@ pub const Object = struct {
41744180
41754181 fn lowerParentPtr(o: *Object, ptr_val: Value, byte_aligned: bool) Allocator.Error!Builder.Constant {
41764182 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) {
41784185 .decl => |decl| o.lowerParentPtrDecl(decl),
41794186 .mut_decl => |mut_decl| o.lowerParentPtrDecl(mut_decl.decl),
41804187 .int => |int| try o.lowerIntAsPtr(int),
41814188 .eu_payload => |eu_ptr| {
41824189 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);
41854192 const payload_ty = eu_ty.errorUnionPayload(mod);
41864193 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
41874194 // In this case, we represent pointer to error union the same as pointer
......@@ -4189,8 +4196,9 @@ pub const Object = struct {
41894196 return parent_ptr;
41904197 }
41914198
4192 const index: u32 =
4193 if (payload_ty.abiAlignment(mod) > Type.err_int.abiSize(mod)) 2 else 1;
4199 const payload_align = payload_ty.abiAlignment(mod);
4200 const err_align = Type.err_int.abiAlignment(mod);
4201 const index: u32 = if (payload_align.compare(.gt, err_align)) 2 else 1;
41944202 return o.builder.gepConst(.inbounds, try o.lowerType(eu_ty), parent_ptr, null, &.{
41954203 try o.builder.intConst(.i32, 0), try o.builder.intConst(.i32, index),
41964204 });
......@@ -4198,7 +4206,7 @@ pub const Object = struct {
41984206 .opt_payload => |opt_ptr| {
41994207 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);
42024210 const payload_ty = opt_ty.optionalChild(mod);
42034211 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod) or
42044212 payload_ty.optionalReprIsPayload(mod))
......@@ -4215,7 +4223,7 @@ pub const Object = struct {
42154223 .comptime_field => unreachable,
42164224 .elem => |elem_ptr| {
42174225 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
42204228 return o.builder.gepConst(.inbounds, try o.lowerType(elem_ty), parent_ptr, null, &.{
42214229 try o.builder.intConst(try o.lowerType(Type.usize), elem_ptr.index),
......@@ -4223,7 +4231,7 @@ pub const Object = struct {
42234231 },
42244232 .field => |field_ptr| {
42254233 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
42284236 const field_index: u32 = @intCast(field_ptr.index);
42294237 switch (parent_ty.zigTypeTag(mod)) {
......@@ -4241,24 +4249,26 @@ pub const Object = struct {
42414249
42424250 const parent_llvm_ty = try o.lowerType(parent_ty);
42434251 return o.builder.gepConst(.inbounds, parent_llvm_ty, parent_ptr, null, &.{
4244 try o.builder.intConst(.i32, 0), try o.builder.intConst(.i32, @intFromBool(
4245 layout.tag_size > 0 and layout.tag_align >= layout.payload_align,
4252 try o.builder.intConst(.i32, 0),
4253 try o.builder.intConst(.i32, @intFromBool(
4254 layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align),
42464255 )),
42474256 });
42484257 },
42494258 .Struct => {
4250 if (parent_ty.containerLayout(mod) == .Packed) {
4259 if (mod.typeToPackedStruct(parent_ty)) |struct_type| {
42514260 if (!byte_aligned) return parent_ptr;
42524261 const llvm_usize = try o.lowerType(Type.usize);
42534262 const base_addr =
42544263 try o.builder.castConst(.ptrtoint, parent_ptr, llvm_usize);
42554264 // count bits of fields before this one
4265 // TODO https://github.com/ziglang/zig/issues/17178
42564266 const prev_bits = b: {
42574267 var b: usize = 0;
4258 for (parent_ty.structFields(mod).values()[0..field_index]) |field| {
4259 if (field.is_comptime) continue;
4260 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
4261 b += @intCast(field.ty.bitSize(mod));
4268 for (0..field_index) |i| {
4269 const field_ty = struct_type.field_types.get(ip)[i].toType();
4270 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
4271 b += @intCast(field_ty.bitSize(mod));
42624272 }
42634273 break :b b;
42644274 };
......@@ -4407,11 +4417,11 @@ pub const Object = struct {
44074417 if (ptr_info.flags.is_const) {
44084418 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
44094419 }
4410 const elem_align = Builder.Alignment.fromByteUnits(
4411 ptr_info.flags.alignment.toByteUnitsOptional() orelse
4412 @max(ptr_info.child.toType().abiAlignment(mod), 1),
4413 );
4414 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
4420 const elem_align = if (ptr_info.flags.alignment != .none)
4421 ptr_info.flags.alignment
4422 else
4423 ptr_info.child.toType().abiAlignment(mod).max(.@"1");
4424 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align.toLlvm() }, &o.builder);
44154425 } else if (ccAbiPromoteInt(fn_info.cc, mod, param_ty)) |s| switch (s) {
44164426 .signed => try attributes.addParamAttr(llvm_arg_i, .signext, &o.builder),
44174427 .unsigned => try attributes.addParamAttr(llvm_arg_i, .zeroext, &o.builder),
......@@ -4469,7 +4479,7 @@ pub const DeclGen = struct {
44694479 } else {
44704480 const variable_index = try o.resolveGlobalDecl(decl_index);
44714481 variable_index.setAlignment(
4472 Builder.Alignment.fromByteUnits(decl.getAlignment(mod)),
4482 decl.getAlignment(mod).toLlvm(),
44734483 &o.builder,
44744484 );
44754485 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |section|
......@@ -4611,9 +4621,7 @@ pub const FuncGen = struct {
46114621 variable_index.setLinkage(.private, &o.builder);
46124622 variable_index.setMutability(.constant, &o.builder);
46134623 variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
4614 variable_index.setAlignment(Builder.Alignment.fromByteUnits(
4615 tv.ty.abiAlignment(mod),
4616 ), &o.builder);
4624 variable_index.setAlignment(tv.ty.abiAlignment(mod).toLlvm(), &o.builder);
46174625 return o.builder.convConst(
46184626 .unneeded,
46194627 variable_index.toConst(&o.builder),
......@@ -4929,7 +4937,7 @@ pub const FuncGen = struct {
49294937 const llvm_ret_ty = try o.lowerType(return_type);
49304938 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();
49334941 const ret_ptr = try self.buildAlloca(llvm_ret_ty, alignment);
49344942 try llvm_args.append(ret_ptr);
49354943 break :blk ret_ptr;
......@@ -4951,7 +4959,7 @@ pub const FuncGen = struct {
49514959 const llvm_arg = try self.resolveInst(arg);
49524960 const llvm_param_ty = try o.lowerType(param_ty);
49534961 if (isByRef(param_ty, mod)) {
4954 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
4962 const alignment = param_ty.abiAlignment(mod).toLlvm();
49554963 const loaded = try self.wip.load(.normal, llvm_param_ty, llvm_arg, alignment, "");
49564964 try llvm_args.append(loaded);
49574965 } else {
......@@ -4965,7 +4973,7 @@ pub const FuncGen = struct {
49654973 if (isByRef(param_ty, mod)) {
49664974 try llvm_args.append(llvm_arg);
49674975 } else {
4968 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
4976 const alignment = param_ty.abiAlignment(mod).toLlvm();
49694977 const param_llvm_ty = llvm_arg.typeOfWip(&self.wip);
49704978 const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment);
49714979 _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment);
......@@ -4977,7 +4985,7 @@ pub const FuncGen = struct {
49774985 const param_ty = self.typeOf(arg);
49784986 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();
49814989 const param_llvm_ty = try o.lowerType(param_ty);
49824990 const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment);
49834991 if (isByRef(param_ty, mod)) {
......@@ -4995,13 +5003,13 @@ pub const FuncGen = struct {
49955003 const int_llvm_ty = try o.builder.intType(@intCast(param_ty.abiSize(mod) * 8));
49965004
49975005 if (isByRef(param_ty, mod)) {
4998 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
5006 const alignment = param_ty.abiAlignment(mod).toLlvm();
49995007 const loaded = try self.wip.load(.normal, int_llvm_ty, llvm_arg, alignment, "");
50005008 try llvm_args.append(loaded);
50015009 } else {
50025010 // LLVM does not allow bitcasting structs so we must allocate
50035011 // 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();
50055013 const int_ptr = try self.buildAlloca(int_llvm_ty, alignment);
50065014 _ = try self.wip.store(.normal, llvm_arg, int_ptr, alignment);
50075015 const loaded = try self.wip.load(.normal, int_llvm_ty, int_ptr, alignment, "");
......@@ -5022,7 +5030,7 @@ pub const FuncGen = struct {
50225030 const llvm_arg = try self.resolveInst(arg);
50235031 const is_by_ref = isByRef(param_ty, mod);
50245032 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();
50265034 const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment);
50275035 _ = try self.wip.store(.normal, llvm_arg, ptr, alignment);
50285036 break :ptr ptr;
......@@ -5048,7 +5056,7 @@ pub const FuncGen = struct {
50485056 const arg = args[it.zig_index - 1];
50495057 const arg_ty = self.typeOf(arg);
50505058 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();
50525060 if (!isByRef(arg_ty, mod)) {
50535061 const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment);
50545062 _ = try self.wip.store(.normal, llvm_arg, ptr, alignment);
......@@ -5066,7 +5074,7 @@ pub const FuncGen = struct {
50665074 const arg = args[it.zig_index - 1];
50675075 const arg_ty = self.typeOf(arg);
50685076 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();
50705078 if (!isByRef(arg_ty, mod)) {
50715079 const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment);
50725080 _ = try self.wip.store(.normal, llvm_arg, ptr, alignment);
......@@ -5097,7 +5105,7 @@ pub const FuncGen = struct {
50975105 const param_index = it.zig_index - 1;
50985106 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
50995107 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();
51015109 try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
51025110 },
51035111 .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder),
......@@ -5128,10 +5136,10 @@ pub const FuncGen = struct {
51285136 if (ptr_info.flags.is_const) {
51295137 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
51305138 }
5131 const elem_align = Builder.Alignment.fromByteUnits(
5132 ptr_info.flags.alignment.toByteUnitsOptional() orelse
5133 @max(ptr_info.child.toType().abiAlignment(mod), 1),
5134 );
5139 const elem_align = (if (ptr_info.flags.alignment != .none)
5140 @as(InternPool.Alignment, ptr_info.flags.alignment)
5141 else
5142 ptr_info.child.toType().abiAlignment(mod).max(.@"1")).toLlvm();
51355143 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
51365144 },
51375145 };
......@@ -5166,7 +5174,7 @@ pub const FuncGen = struct {
51665174 return rp;
51675175 } else {
51685176 // 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();
51705178 return self.wip.load(.normal, llvm_ret_ty, rp, return_alignment, "");
51715179 }
51725180 }
......@@ -5177,7 +5185,7 @@ pub const FuncGen = struct {
51775185 // In this case the function return type is honoring the calling convention by having
51785186 // a different LLVM type than the usual one. We solve this here at the callsite
51795187 // 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();
51815189 if (o.builder.useLibLlvm())
51825190 assert(o.target_data.abiSizeOfType(abi_ret_ty.toLlvm(&o.builder)) >=
51835191 o.target_data.abiSizeOfType(llvm_ret_ty.toLlvm(&o.builder)));
......@@ -5192,7 +5200,7 @@ pub const FuncGen = struct {
51925200 if (isByRef(return_type, mod)) {
51935201 // our by-ref status disagrees with sret so we must allocate, store,
51945202 // and return the allocation pointer.
5195 const alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod));
5203 const alignment = return_type.abiAlignment(mod).toLlvm();
51965204 const rp = try self.buildAlloca(llvm_ret_ty, alignment);
51975205 _ = try self.wip.store(.normal, call, rp, alignment);
51985206 return rp;
......@@ -5266,7 +5274,7 @@ pub const FuncGen = struct {
52665274
52675275 const abi_ret_ty = try lowerFnRetTy(o, fn_info);
52685276 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
52715279 if (isByRef(ret_ty, mod)) {
52725280 // operand is a pointer however self.ret_ptr is null so that means
......@@ -5311,7 +5319,7 @@ pub const FuncGen = struct {
53115319 }
53125320 const ptr = try self.resolveInst(un_op);
53135321 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();
53155323 _ = try self.wip.ret(try self.wip.load(.normal, abi_ret_ty, ptr, alignment, ""));
53165324 return .none;
53175325 }
......@@ -5334,7 +5342,7 @@ pub const FuncGen = struct {
53345342 const llvm_va_list_ty = try o.lowerType(va_list_ty);
53355343 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();
53385346 const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment);
53395347
53405348 _ = try self.wip.callIntrinsic(.normal, .none, .va_copy, &.{}, &.{ dest_list, src_list }, "");
......@@ -5358,7 +5366,7 @@ pub const FuncGen = struct {
53585366 const va_list_ty = self.typeOfIndex(inst);
53595367 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();
53625370 const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment);
53635371
53645372 _ = try self.wip.callIntrinsic(.normal, .none, .va_start, &.{}, &.{dest_list}, "");
......@@ -5690,7 +5698,7 @@ pub const FuncGen = struct {
56905698 return fg.wip.gepStruct(err_union_llvm_ty, err_union, offset, "");
56915699 } else if (isByRef(err_union_ty, mod)) {
56925700 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();
56945702 if (isByRef(payload_ty, mod)) {
56955703 if (can_elide_load)
56965704 return payload_ptr;
......@@ -5997,7 +6005,7 @@ pub const FuncGen = struct {
59976005 if (self.canElideLoad(body_tail))
59986006 return ptr;
59996007
6000 const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
6008 const elem_alignment = elem_ty.abiAlignment(mod).toLlvm();
60016009 return self.loadByRef(ptr, elem_ty, elem_alignment, .normal);
60026010 }
60036011
......@@ -6037,7 +6045,7 @@ pub const FuncGen = struct {
60376045 const elem_ptr =
60386046 try self.wip.gep(.inbounds, array_llvm_ty, array_llvm_val, &indices, "");
60396047 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();
60416049 return self.loadByRef(elem_ptr, elem_ty, elem_alignment, .normal);
60426050 } else {
60436051 const elem_llvm_ty = try o.lowerType(elem_ty);
......@@ -6097,7 +6105,7 @@ pub const FuncGen = struct {
60976105 &.{rhs}, "");
60986106 if (isByRef(elem_ty, mod)) {
60996107 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();
61016109 return self.loadByRef(ptr, elem_ty, elem_alignment, .normal);
61026110 }
61036111
......@@ -6163,8 +6171,8 @@ pub const FuncGen = struct {
61636171 switch (struct_ty.zigTypeTag(mod)) {
61646172 .Struct => switch (struct_ty.containerLayout(mod)) {
61656173 .Packed => {
6166 const struct_obj = mod.typeToStruct(struct_ty).?;
6167 const bit_offset = struct_obj.packedFieldBitOffset(mod, field_index);
6174 const struct_type = mod.typeToStruct(struct_ty).?;
6175 const bit_offset = mod.structPackedFieldBitOffset(struct_type, field_index);
61686176 const containing_int = struct_llvm_val;
61696177 const shift_amt =
61706178 try o.builder.intValue(containing_int.typeOfWip(&self.wip), bit_offset);
......@@ -6220,16 +6228,14 @@ pub const FuncGen = struct {
62206228 const alignment = struct_ty.structFieldAlign(field_index, mod);
62216229 const field_ptr_ty = try mod.ptrType(.{
62226230 .child = field_ty.toIntern(),
6223 .flags = .{
6224 .alignment = InternPool.Alignment.fromNonzeroByteUnits(alignment),
6225 },
6231 .flags = .{ .alignment = alignment },
62266232 });
62276233 if (isByRef(field_ty, mod)) {
62286234 if (canElideLoad(self, body_tail))
62296235 return field_ptr;
62306236
6231 assert(alignment != 0);
6232 const field_alignment = Builder.Alignment.fromByteUnits(alignment);
6237 assert(alignment != .none);
6238 const field_alignment = alignment.toLlvm();
62336239 return self.loadByRef(field_ptr, field_ty, field_alignment, .normal);
62346240 } else {
62356241 return self.load(field_ptr, field_ptr_ty);
......@@ -6238,11 +6244,11 @@ pub const FuncGen = struct {
62386244 .Union => {
62396245 const union_llvm_ty = try o.lowerType(struct_ty);
62406246 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));
62426248 const field_ptr =
62436249 try self.wip.gepStruct(union_llvm_ty, struct_llvm_val, payload_index, "");
62446250 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();
62466252 if (isByRef(field_ty, mod)) {
62476253 if (canElideLoad(self, body_tail)) return field_ptr;
62486254 return self.loadByRef(field_ptr, field_ty, payload_alignment, .normal);
......@@ -6457,7 +6463,7 @@ pub const FuncGen = struct {
64576463 if (isByRef(operand_ty, mod)) {
64586464 _ = dib.insertDeclareAtEnd(operand.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
64596465 } 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();
64616467 const alloca = try self.buildAlloca(operand.typeOfWip(&self.wip), alignment);
64626468 _ = try self.wip.store(.normal, operand, alloca, alignment);
64636469 _ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
......@@ -6612,7 +6618,7 @@ pub const FuncGen = struct {
66126618 llvm_param_values[llvm_param_i] = arg_llvm_value;
66136619 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
66146620 } else {
6615 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
6621 const alignment = arg_ty.abiAlignment(mod).toLlvm();
66166622 const arg_llvm_ty = try o.lowerType(arg_ty);
66176623 const load_inst =
66186624 try self.wip.load(.normal, arg_llvm_ty, arg_llvm_value, alignment, "");
......@@ -6624,7 +6630,7 @@ pub const FuncGen = struct {
66246630 llvm_param_values[llvm_param_i] = arg_llvm_value;
66256631 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
66266632 } else {
6627 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
6633 const alignment = arg_ty.abiAlignment(mod).toLlvm();
66286634 const arg_ptr = try self.buildAlloca(arg_llvm_value.typeOfWip(&self.wip), alignment);
66296635 _ = try self.wip.store(.normal, arg_llvm_value, arg_ptr, alignment);
66306636 llvm_param_values[llvm_param_i] = arg_ptr;
......@@ -6676,7 +6682,7 @@ pub const FuncGen = struct {
66766682 llvm_param_values[llvm_param_i] = llvm_rw_val;
66776683 llvm_param_types[llvm_param_i] = llvm_rw_val.typeOfWip(&self.wip);
66786684 } else {
6679 const alignment = Builder.Alignment.fromByteUnits(rw_ty.abiAlignment(mod));
6685 const alignment = rw_ty.abiAlignment(mod).toLlvm();
66806686 const loaded = try self.wip.load(.normal, llvm_elem_ty, llvm_rw_val, alignment, "");
66816687 llvm_param_values[llvm_param_i] = loaded;
66826688 llvm_param_types[llvm_param_i] = llvm_elem_ty;
......@@ -6837,7 +6843,7 @@ pub const FuncGen = struct {
68376843 const output_ptr = try self.resolveInst(output);
68386844 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();
68416847 _ = try self.wip.store(.normal, output_value, output_ptr, alignment);
68426848 } else {
68436849 ret_val = output_value;
......@@ -7030,7 +7036,7 @@ pub const FuncGen = struct {
70307036 if (operand_is_ptr) {
70317037 return self.wip.gepStruct(err_union_llvm_ty, operand, offset, "");
70327038 } 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();
70347040 const payload_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, offset, "");
70357041 if (isByRef(payload_ty, mod)) {
70367042 if (self.canElideLoad(body_tail)) return payload_ptr;
......@@ -7093,7 +7099,7 @@ pub const FuncGen = struct {
70937099 }
70947100 const err_union_llvm_ty = try o.lowerType(err_union_ty);
70957101 {
7096 const error_alignment = Builder.Alignment.fromByteUnits(Type.err_int.abiAlignment(mod));
7102 const error_alignment = Type.err_int.abiAlignment(mod).toLlvm();
70977103 const error_offset = errUnionErrorOffset(payload_ty, mod);
70987104 // First set the non-error value.
70997105 const non_null_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, error_offset, "");
......@@ -7133,9 +7139,7 @@ pub const FuncGen = struct {
71337139 const field_ty = struct_ty.structFieldType(field_index, mod);
71347140 const field_ptr_ty = try mod.ptrType(.{
71357141 .child = field_ty.toIntern(),
7136 .flags = .{
7137 .alignment = InternPool.Alignment.fromNonzeroByteUnits(field_alignment),
7138 },
7142 .flags = .{ .alignment = field_alignment },
71397143 });
71407144 return self.load(field_ptr, field_ptr_ty);
71417145 }
......@@ -7153,7 +7157,7 @@ pub const FuncGen = struct {
71537157 if (optional_ty.optionalReprIsPayload(mod)) return operand;
71547158 const llvm_optional_ty = try o.lowerType(optional_ty);
71557159 if (isByRef(optional_ty, mod)) {
7156 const alignment = Builder.Alignment.fromByteUnits(optional_ty.abiAlignment(mod));
7160 const alignment = optional_ty.abiAlignment(mod).toLlvm();
71577161 const optional_ptr = try self.buildAlloca(llvm_optional_ty, alignment);
71587162 const payload_ptr = try self.wip.gepStruct(llvm_optional_ty, optional_ptr, 0, "");
71597163 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);
......@@ -7181,10 +7185,10 @@ pub const FuncGen = struct {
71817185 const payload_offset = errUnionPayloadOffset(payload_ty, mod);
71827186 const error_offset = errUnionErrorOffset(payload_ty, mod);
71837187 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();
71857189 const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment);
71867190 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();
71887192 _ = try self.wip.store(.normal, ok_err_code, err_ptr, error_alignment);
71897193 const payload_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, payload_offset, "");
71907194 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);
......@@ -7210,10 +7214,10 @@ pub const FuncGen = struct {
72107214 const payload_offset = errUnionPayloadOffset(payload_ty, mod);
72117215 const error_offset = errUnionErrorOffset(payload_ty, mod);
72127216 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();
72147218 const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment);
72157219 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();
72177221 _ = try self.wip.store(.normal, operand, err_ptr, error_alignment);
72187222 const payload_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, payload_offset, "");
72197223 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);
......@@ -7260,7 +7264,7 @@ pub const FuncGen = struct {
72607264 const access_kind: Builder.MemoryAccessKind =
72617265 if (vector_ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal;
72627266 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();
72647268 const loaded = try self.wip.load(access_kind, elem_llvm_ty, vector_ptr, alignment, "");
72657269
72667270 const new_vector = try self.wip.insertElement(loaded, operand, index, "");
......@@ -7690,7 +7694,7 @@ pub const FuncGen = struct {
76907694 const overflow_index = o.llvmFieldIndex(inst_ty, 1).?;
76917695
76927696 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();
76947698 const alloca_inst = try self.buildAlloca(llvm_inst_ty, result_alignment);
76957699 {
76967700 const field_ptr = try self.wip.gepStruct(llvm_inst_ty, alloca_inst, result_index, "");
......@@ -8048,7 +8052,7 @@ pub const FuncGen = struct {
80488052 const overflow_index = o.llvmFieldIndex(dest_ty, 1).?;
80498053
80508054 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();
80528056 const alloca_inst = try self.buildAlloca(llvm_dest_ty, result_alignment);
80538057 {
80548058 const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, result_index, "");
......@@ -8321,7 +8325,7 @@ pub const FuncGen = struct {
83218325 const array_ptr = try self.buildAlloca(llvm_dest_ty, .default);
83228326 const bitcast_ok = elem_ty.bitSize(mod) == elem_ty.abiSize(mod) * 8;
83238327 if (bitcast_ok) {
8324 const alignment = Builder.Alignment.fromByteUnits(inst_ty.abiAlignment(mod));
8328 const alignment = inst_ty.abiAlignment(mod).toLlvm();
83258329 _ = try self.wip.store(.normal, operand, array_ptr, alignment);
83268330 } else {
83278331 // If the ABI size of the element type is not evenly divisible by size in bits;
......@@ -8349,7 +8353,7 @@ pub const FuncGen = struct {
83498353 if (bitcast_ok) {
83508354 // The array is aligned to the element's alignment, while the vector might have a completely
83518355 // 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();
83538357 return self.wip.load(.normal, llvm_vector_ty, operand, alignment, "");
83548358 } else {
83558359 // If the ABI size of the element type is not evenly divisible by size in bits;
......@@ -8374,14 +8378,12 @@ pub const FuncGen = struct {
83748378 }
83758379
83768380 if (operand_is_ref) {
8377 const alignment = Builder.Alignment.fromByteUnits(operand_ty.abiAlignment(mod));
8381 const alignment = operand_ty.abiAlignment(mod).toLlvm();
83788382 return self.wip.load(.normal, llvm_dest_ty, operand, alignment, "");
83798383 }
83808384
83818385 if (result_is_ref) {
8382 const alignment = Builder.Alignment.fromByteUnits(
8383 @max(operand_ty.abiAlignment(mod), inst_ty.abiAlignment(mod)),
8384 );
8386 const alignment = operand_ty.abiAlignment(mod).max(inst_ty.abiAlignment(mod)).toLlvm();
83858387 const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment);
83868388 _ = try self.wip.store(.normal, operand, result_ptr, alignment);
83878389 return result_ptr;
......@@ -8393,9 +8395,7 @@ pub const FuncGen = struct {
83938395 // Both our operand and our result are values, not pointers,
83948396 // but LLVM won't let us bitcast struct values or vectors with padding bits.
83958397 // Therefore, we store operand to alloca, then load for result.
8396 const alignment = Builder.Alignment.fromByteUnits(
8397 @max(operand_ty.abiAlignment(mod), inst_ty.abiAlignment(mod)),
8398 );
8398 const alignment = operand_ty.abiAlignment(mod).max(inst_ty.abiAlignment(mod)).toLlvm();
83998399 const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment);
84008400 _ = try self.wip.store(.normal, operand, result_ptr, alignment);
84018401 return self.wip.load(.normal, llvm_dest_ty, result_ptr, alignment, "");
......@@ -8441,7 +8441,7 @@ pub const FuncGen = struct {
84418441 if (isByRef(inst_ty, mod)) {
84428442 _ = dib.insertDeclareAtEnd(arg_val.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
84438443 } 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();
84458445 const alloca = try self.buildAlloca(arg_val.typeOfWip(&self.wip), alignment);
84468446 _ = try self.wip.store(.normal, arg_val, alloca, alignment);
84478447 _ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
......@@ -8462,7 +8462,7 @@ pub const FuncGen = struct {
84628462 return (try o.lowerPtrToVoid(ptr_ty)).toValue();
84638463
84648464 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();
84668466 return self.buildAlloca(pointee_llvm_ty, alignment);
84678467 }
84688468
......@@ -8475,7 +8475,7 @@ pub const FuncGen = struct {
84758475 return (try o.lowerPtrToVoid(ptr_ty)).toValue();
84768476 if (self.ret_ptr != .none) return self.ret_ptr;
84778477 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();
84798479 return self.buildAlloca(ret_llvm_ty, alignment);
84808480 }
84818481
......@@ -8515,7 +8515,7 @@ pub const FuncGen = struct {
85158515 const len = try o.builder.intValue(try o.lowerType(Type.usize), operand_ty.abiSize(mod));
85168516 _ = try self.wip.callMemSet(
85178517 dest_ptr,
8518 Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod)),
8518 ptr_ty.ptrAlignment(mod).toLlvm(),
85198519 if (safety) try o.builder.intValue(.i8, 0xaa) else try o.builder.undefValue(.i8),
85208520 len,
85218521 if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal,
......@@ -8646,7 +8646,7 @@ pub const FuncGen = struct {
86468646 self.sync_scope,
86478647 toLlvmAtomicOrdering(extra.successOrder()),
86488648 toLlvmAtomicOrdering(extra.failureOrder()),
8649 Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod)),
8649 ptr_ty.ptrAlignment(mod).toLlvm(),
86508650 "",
86518651 );
86528652
......@@ -8685,7 +8685,7 @@ pub const FuncGen = struct {
86858685
86868686 const access_kind: Builder.MemoryAccessKind =
86878687 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
86908690 if (llvm_abi_ty != .none) {
86918691 // operand needs widening and truncating or bitcasting.
......@@ -8741,9 +8741,10 @@ pub const FuncGen = struct {
87418741 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none;
87428742 const ordering = toLlvmAtomicOrdering(atomic_load.order);
87438743 const llvm_abi_ty = try o.getAtomicAbiType(elem_ty, false);
8744 const ptr_alignment = Builder.Alignment.fromByteUnits(
8745 info.flags.alignment.toByteUnitsOptional() orelse info.child.toType().abiAlignment(mod),
8746 );
8744 const ptr_alignment = (if (info.flags.alignment != .none)
8745 @as(InternPool.Alignment, info.flags.alignment)
8746 else
8747 info.child.toType().abiAlignment(mod)).toLlvm();
87478748 const access_kind: Builder.MemoryAccessKind =
87488749 if (info.flags.is_volatile) .@"volatile" else .normal;
87498750 const elem_llvm_ty = try o.lowerType(elem_ty);
......@@ -8807,7 +8808,7 @@ pub const FuncGen = struct {
88078808 const dest_slice = try self.resolveInst(bin_op.lhs);
88088809 const ptr_ty = self.typeOf(bin_op.lhs);
88098810 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();
88118812 const dest_ptr = try self.sliceOrArrayPtr(dest_slice, ptr_ty);
88128813 const access_kind: Builder.MemoryAccessKind =
88138814 if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal;
......@@ -8911,15 +8912,13 @@ pub const FuncGen = struct {
89118912
89128913 self.wip.cursor = .{ .block = body_block };
89138914 const elem_abi_align = elem_ty.abiAlignment(mod);
8914 const it_ptr_align = Builder.Alignment.fromByteUnits(
8915 @min(elem_abi_align, dest_ptr_align.toByteUnits() orelse std.math.maxInt(u64)),
8916 );
8915 const it_ptr_align = InternPool.Alignment.fromLlvm(dest_ptr_align).min(elem_abi_align).toLlvm();
89178916 if (isByRef(elem_ty, mod)) {
89188917 _ = try self.wip.callMemCpy(
89198918 it_ptr.toValue(),
89208919 it_ptr_align,
89218920 value,
8922 Builder.Alignment.fromByteUnits(elem_abi_align),
8921 elem_abi_align.toLlvm(),
89238922 try o.builder.intValue(llvm_usize_ty, elem_abi_size),
89248923 access_kind,
89258924 );
......@@ -8985,9 +8984,9 @@ pub const FuncGen = struct {
89858984 self.wip.cursor = .{ .block = memcpy_block };
89868985 _ = try self.wip.callMemCpy(
89878986 dest_ptr,
8988 Builder.Alignment.fromByteUnits(dest_ptr_ty.ptrAlignment(mod)),
8987 dest_ptr_ty.ptrAlignment(mod).toLlvm(),
89898988 src_ptr,
8990 Builder.Alignment.fromByteUnits(src_ptr_ty.ptrAlignment(mod)),
8989 src_ptr_ty.ptrAlignment(mod).toLlvm(),
89918990 len,
89928991 access_kind,
89938992 );
......@@ -8998,9 +8997,9 @@ pub const FuncGen = struct {
89988997
89998998 _ = try self.wip.callMemCpy(
90008999 dest_ptr,
9001 Builder.Alignment.fromByteUnits(dest_ptr_ty.ptrAlignment(mod)),
9000 dest_ptr_ty.ptrAlignment(mod).toLlvm(),
90029001 src_ptr,
9003 Builder.Alignment.fromByteUnits(src_ptr_ty.ptrAlignment(mod)),
9002 src_ptr_ty.ptrAlignment(mod).toLlvm(),
90049003 len,
90059004 access_kind,
90069005 );
......@@ -9021,7 +9020,7 @@ pub const FuncGen = struct {
90219020 _ = try self.wip.store(.normal, new_tag, union_ptr, .default);
90229021 return .none;
90239022 }
9024 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);
9023 const tag_index = @intFromBool(layout.tag_align.compare(.lt, layout.payload_align));
90259024 const tag_field_ptr = try self.wip.gepStruct(try o.lowerType(un_ty), union_ptr, tag_index, "");
90269025 // TODO alignment on this store
90279026 _ = try self.wip.store(.normal, new_tag, tag_field_ptr, .default);
......@@ -9040,13 +9039,13 @@ pub const FuncGen = struct {
90409039 const llvm_un_ty = try o.lowerType(un_ty);
90419040 if (layout.payload_size == 0)
90429041 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));
90449043 const tag_field_ptr = try self.wip.gepStruct(llvm_un_ty, union_handle, tag_index, "");
90459044 const llvm_tag_ty = llvm_un_ty.structFields(&o.builder)[tag_index];
90469045 return self.wip.load(.normal, llvm_tag_ty, tag_field_ptr, .default, "");
90479046 } else {
90489047 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));
90509049 return self.wip.extractValue(union_handle, &.{tag_index}, "");
90519050 }
90529051 }
......@@ -9605,6 +9604,7 @@ pub const FuncGen = struct {
96059604 fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
96069605 const o = self.dg.object;
96079606 const mod = o.module;
9607 const ip = &mod.intern_pool;
96089608 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
96099609 const result_ty = self.typeOfIndex(inst);
96109610 const len: usize = @intCast(result_ty.arrayLen(mod));
......@@ -9622,23 +9622,21 @@ pub const FuncGen = struct {
96229622 return vector;
96239623 },
96249624 .Struct => {
9625 if (result_ty.containerLayout(mod) == .Packed) {
9626 const struct_obj = mod.typeToStruct(result_ty).?;
9627 assert(struct_obj.haveLayout());
9628 const big_bits = struct_obj.backing_int_ty.bitSize(mod);
9625 if (mod.typeToPackedStruct(result_ty)) |struct_type| {
9626 const backing_int_ty = struct_type.backingIntType(ip).*;
9627 assert(backing_int_ty != .none);
9628 const big_bits = backing_int_ty.toType().bitSize(mod);
96299629 const int_ty = try o.builder.intType(@intCast(big_bits));
9630 const fields = struct_obj.fields.values();
96319630 comptime assert(Type.packed_struct_layout_version == 2);
96329631 var running_int = try o.builder.intValue(int_ty, 0);
96339632 var running_bits: u16 = 0;
9634 for (elements, 0..) |elem, i| {
9635 const field = fields[i];
9636 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
9633 for (elements, struct_type.field_types.get(ip)) |elem, field_ty| {
9634 if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
96379635
96389636 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));
96409638 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))
96429640 try self.wip.cast(.ptrtoint, non_int_val, small_int_ty, "")
96439641 else
96449642 try self.wip.cast(.bitcast, non_int_val, small_int_ty, "");
......@@ -9652,10 +9650,12 @@ pub const FuncGen = struct {
96529650 return running_int;
96539651 }
96549652
9653 assert(result_ty.containerLayout(mod) != .Packed);
9654
96559655 if (isByRef(result_ty, mod)) {
96569656 // TODO in debug builds init to undef so that the padding will be 0xaa
96579657 // 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();
96599659 const alloca_inst = try self.buildAlloca(llvm_result_ty, alignment);
96609660
96619661 for (elements, 0..) |elem, i| {
......@@ -9668,9 +9668,7 @@ pub const FuncGen = struct {
96689668 const field_ptr_ty = try mod.ptrType(.{
96699669 .child = self.typeOf(elem).toIntern(),
96709670 .flags = .{
9671 .alignment = InternPool.Alignment.fromNonzeroByteUnits(
9672 result_ty.structFieldAlign(i, mod),
9673 ),
9671 .alignment = result_ty.structFieldAlign(i, mod),
96749672 },
96759673 });
96769674 try self.store(field_ptr, field_ptr_ty, llvm_elem, .none);
......@@ -9694,7 +9692,7 @@ pub const FuncGen = struct {
96949692
96959693 const llvm_usize = try o.lowerType(Type.usize);
96969694 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();
96989696 const alloca_inst = try self.buildAlloca(llvm_result_ty, alignment);
96999697
97009698 const array_info = result_ty.arrayInfo(mod);
......@@ -9770,7 +9768,7 @@ pub const FuncGen = struct {
97709768 // necessarily match the format that we need, depending on which tag is active.
97719769 // We must construct the correct unnamed struct type here, in order to then set
97729770 // the fields appropriately.
9773 const alignment = Builder.Alignment.fromByteUnits(layout.abi_align);
9771 const alignment = layout.abi_align.toLlvm();
97749772 const result_ptr = try self.buildAlloca(union_llvm_ty, alignment);
97759773 const llvm_payload = try self.resolveInst(extra.init);
97769774 const field_ty = union_obj.field_types.get(ip)[extra.field_index].toType();
......@@ -9799,7 +9797,7 @@ pub const FuncGen = struct {
97999797 const tag_ty = try o.lowerType(union_obj.enum_tag_ty.toType());
98009798 var fields: [3]Builder.Type = undefined;
98019799 var fields_len: usize = 2;
9802 if (layout.tag_align >= layout.payload_align) {
9800 if (layout.tag_align.compare(.gte, layout.payload_align)) {
98039801 fields = .{ tag_ty, payload_ty, undefined };
98049802 } else {
98059803 fields = .{ payload_ty, tag_ty, undefined };
......@@ -9815,7 +9813,7 @@ pub const FuncGen = struct {
98159813 // tag and the payload.
98169814 const field_ptr_ty = try mod.ptrType(.{
98179815 .child = field_ty.toIntern(),
9818 .flags = .{ .alignment = InternPool.Alignment.fromNonzeroByteUnits(field_align) },
9816 .flags = .{ .alignment = field_align },
98199817 });
98209818 if (layout.tag_size == 0) {
98219819 const indices = [3]Builder.Value{ usize_zero, i32_zero, i32_zero };
......@@ -9827,7 +9825,7 @@ pub const FuncGen = struct {
98279825 }
98289826
98299827 {
9830 const payload_index = @intFromBool(layout.tag_align >= layout.payload_align);
9828 const payload_index = @intFromBool(layout.tag_align.compare(.gte, layout.payload_align));
98319829 const indices: [3]Builder.Value =
98329830 .{ usize_zero, try o.builder.intValue(.i32, payload_index), i32_zero };
98339831 const len: usize = if (field_size == layout.payload_size) 2 else 3;
......@@ -9836,12 +9834,12 @@ pub const FuncGen = struct {
98369834 try self.store(field_ptr, field_ptr_ty, llvm_payload, .none);
98379835 }
98389836 {
9839 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);
9837 const tag_index = @intFromBool(layout.tag_align.compare(.lt, layout.payload_align));
98409838 const indices: [2]Builder.Value = .{ usize_zero, try o.builder.intValue(.i32, tag_index) };
98419839 const field_ptr = try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, &indices, "");
98429840 const tag_ty = try o.lowerType(union_obj.enum_tag_ty.toType());
98439841 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();
98459843 _ = try self.wip.store(.normal, llvm_tag, field_ptr, tag_alignment);
98469844 }
98479845
......@@ -9978,7 +9976,7 @@ pub const FuncGen = struct {
99789976 variable_index.setMutability(.constant, &o.builder);
99799977 variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
99809978 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(),
99829980 &o.builder,
99839981 );
99849982
......@@ -10023,7 +10021,7 @@ pub const FuncGen = struct {
1002310021 // We have a pointer and we need to return a pointer to the first field.
1002410022 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();
1002710025 if (isByRef(payload_ty, mod)) {
1002810026 if (can_elide_load)
1002910027 return payload_ptr;
......@@ -10050,7 +10048,7 @@ pub const FuncGen = struct {
1005010048 const mod = o.module;
1005110049
1005210050 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();
1005410052 const alloca_inst = try self.buildAlloca(optional_llvm_ty, payload_alignment);
1005510053
1005610054 {
......@@ -10123,7 +10121,7 @@ pub const FuncGen = struct {
1012310121 .Union => {
1012410122 const layout = struct_ty.unionGetLayout(mod);
1012510123 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));
1012710125 const union_llvm_ty = try o.lowerType(struct_ty);
1012810126 return self.wip.gepStruct(union_llvm_ty, struct_ptr, payload_index, "");
1012910127 },
......@@ -10142,9 +10140,7 @@ pub const FuncGen = struct {
1014210140 const o = fg.dg.object;
1014310141 const mod = o.module;
1014410142 const pointee_llvm_ty = try o.lowerType(pointee_type);
10145 const result_align = Builder.Alignment.fromByteUnits(
10146 @max(ptr_alignment.toByteUnits() orelse 0, pointee_type.abiAlignment(mod)),
10147 );
10143 const result_align = InternPool.Alignment.fromLlvm(ptr_alignment).max(pointee_type.abiAlignment(mod)).toLlvm();
1014810144 const result_ptr = try fg.buildAlloca(pointee_llvm_ty, result_align);
1014910145 const size_bytes = pointee_type.abiSize(mod);
1015010146 _ = try fg.wip.callMemCpy(
......@@ -10168,9 +10164,11 @@ pub const FuncGen = struct {
1016810164 const elem_ty = info.child.toType();
1016910165 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none;
1017010166
10171 const ptr_alignment = Builder.Alignment.fromByteUnits(
10172 info.flags.alignment.toByteUnitsOptional() orelse elem_ty.abiAlignment(mod),
10173 );
10167 const ptr_alignment = (if (info.flags.alignment != .none)
10168 @as(InternPool.Alignment, info.flags.alignment)
10169 else
10170 elem_ty.abiAlignment(mod)).toLlvm();
10171
1017410172 const access_kind: Builder.MemoryAccessKind =
1017510173 if (info.flags.is_volatile) .@"volatile" else .normal;
1017610174
......@@ -10201,7 +10199,7 @@ pub const FuncGen = struct {
1020110199 const elem_llvm_ty = try o.lowerType(elem_ty);
1020210200
1020310201 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();
1020510203 const result_ptr = try self.buildAlloca(elem_llvm_ty, result_align);
1020610204
1020710205 const same_size_int = try o.builder.intType(@intCast(elem_bits));
......@@ -10239,7 +10237,7 @@ pub const FuncGen = struct {
1023910237 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) {
1024010238 return;
1024110239 }
10242 const ptr_alignment = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
10240 const ptr_alignment = ptr_ty.ptrAlignment(mod).toLlvm();
1024310241 const access_kind: Builder.MemoryAccessKind =
1024410242 if (info.flags.is_volatile) .@"volatile" else .normal;
1024510243
......@@ -10305,7 +10303,7 @@ pub const FuncGen = struct {
1030510303 ptr,
1030610304 ptr_alignment,
1030710305 elem,
10308 Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod)),
10306 elem_ty.abiAlignment(mod).toLlvm(),
1030910307 try o.builder.intValue(try o.lowerType(Type.usize), elem_ty.abiSize(mod)),
1031010308 access_kind,
1031110309 );
......@@ -10337,7 +10335,7 @@ pub const FuncGen = struct {
1033710335 if (!target_util.hasValgrindSupport(target)) return default_value;
1033810336
1033910337 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
1034210340 const array_llvm_ty = try o.builder.arrayType(6, llvm_usize);
1034310341 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
1071810716
1071910717fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type {
1072010718 const mod = o.module;
10719 const ip = &mod.intern_pool;
1072110720 const return_type = fn_info.return_type.toType();
1072210721 if (isScalar(mod, return_type)) {
1072310722 return o.lowerType(return_type);
......@@ -10761,12 +10760,16 @@ fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.E
1076110760 const first_non_integer = std.mem.indexOfNone(x86_64_abi.Class, &classes, &.{.integer});
1076210761 if (first_non_integer == null or classes[first_non_integer.?] == .none) {
1076310762 assert(first_non_integer orelse classes.len == types_index);
10764 if (mod.intern_pool.indexToKey(return_type.toIntern()) == .struct_type) {
10765 var struct_it = return_type.iterateStructOffsets(mod);
10766 while (struct_it.next()) |_| {}
10767 assert((std.math.divCeil(u64, struct_it.offset, 8) catch unreachable) == types_index);
10768 if (struct_it.offset % 8 > 0) types_buffer[types_index - 1] =
10769 try o.builder.intType(@intCast(struct_it.offset % 8 * 8));
10763 switch (ip.indexToKey(return_type.toIntern())) {
10764 .struct_type => |struct_type| {
10765 assert(struct_type.haveLayout(ip));
10766 const size: u64 = struct_type.size(ip).*;
10767 assert((std.math.divCeil(u64, size, 8) catch unreachable) == types_index);
10768 if (size % 8 > 0) {
10769 types_buffer[types_index - 1] = try o.builder.intType(@intCast(size % 8 * 8));
10770 }
10771 },
10772 else => {},
1077010773 }
1077110774 if (types_index == 1) return types_buffer[0];
1077210775 }
......@@ -10982,6 +10985,7 @@ const ParamTypeIterator = struct {
1098210985
1098310986 fn nextSystemV(it: *ParamTypeIterator, ty: Type) Allocator.Error!?Lowering {
1098410987 const mod = it.object.module;
10988 const ip = &mod.intern_pool;
1098510989 const classes = x86_64_abi.classifySystemV(ty, mod, .arg);
1098610990 if (classes[0] == .memory) {
1098710991 it.zig_index += 1;
......@@ -11037,12 +11041,17 @@ const ParamTypeIterator = struct {
1103711041 it.llvm_index += 1;
1103811042 return .abi_sized_int;
1103911043 }
11040 if (mod.intern_pool.indexToKey(ty.toIntern()) == .struct_type) {
11041 var struct_it = ty.iterateStructOffsets(mod);
11042 while (struct_it.next()) |_| {}
11043 assert((std.math.divCeil(u64, struct_it.offset, 8) catch unreachable) == types_index);
11044 if (struct_it.offset % 8 > 0) types_buffer[types_index - 1] =
11045 try it.object.builder.intType(@intCast(struct_it.offset % 8 * 8));
11044 switch (ip.indexToKey(ty.toIntern())) {
11045 .struct_type => |struct_type| {
11046 assert(struct_type.haveLayout(ip));
11047 const size: u64 = struct_type.size(ip).*;
11048 assert((std.math.divCeil(u64, size, 8) catch unreachable) == types_index);
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 => {},
1104611055 }
1104711056 }
1104811057 it.types_len = types_index;
......@@ -11137,8 +11146,6 @@ fn isByRef(ty: Type, mod: *Module) bool {
1113711146
1113811147 .Array, .Frame => return ty.hasRuntimeBits(mod),
1113911148 .Struct => {
11140 // Packed structs are represented to LLVM as integers.
11141 if (ty.containerLayout(mod) == .Packed) return false;
1114211149 const struct_type = switch (ip.indexToKey(ty.toIntern())) {
1114311150 .anon_struct_type => |tuple| {
1114411151 var count: usize = 0;
......@@ -11154,14 +11161,18 @@ fn isByRef(ty: Type, mod: *Module) bool {
1115411161 .struct_type => |s| s,
1115511162 else => unreachable,
1115611163 };
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| {
1116211172 count += 1;
1116311173 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;
1116511176 }
1116611177 return false;
1116711178 },
......@@ -11362,11 +11373,11 @@ fn buildAllocaInner(
1136211373}
1136311374
1136411375fn 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)));
1136611377}
1136711378
1136811379fn 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)));
1137011381}
1137111382
1137211383/// 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 {
792792 },
793793 .vector_type => return dg.todo("indirect constant of type {}", .{ty.fmt(mod)}),
794794 .struct_type => {
795 const struct_ty = mod.typeToStruct(ty).?;
796 if (struct_ty.layout == .Packed) {
795 const struct_type = mod.typeToStruct(ty).?;
796 if (struct_type.layout == .Packed) {
797797 return dg.todo("packed struct constants", .{});
798798 }
799799
800 // TODO iterate with runtime order instead so that struct field
801 // reordering can be enabled for this backend.
800802 const struct_begin = self.size;
801 for (struct_ty.fields.values(), 0..) |field, i| {
802 if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue;
803 for (struct_type.field_types.get(ip), 0..) |field_ty, i_usize| {
804 const i: u32 = @intCast(i_usize);
805 if (struct_type.fieldIsComptime(ip, i)) continue;
806 if (!field_ty.toType().hasRuntimeBits(mod)) continue;
803807
804808 const field_val = switch (aggregate.storage) {
805809 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
806 .ty = field.ty.toIntern(),
810 .ty = field_ty,
807811 .storage = .{ .u64 = bytes[i] },
808812 } }),
809813 .elems => |elems| elems[i],
810814 .repeated_elem => |elem| elem,
811815 };
812 try self.lower(field.ty, field_val.toValue());
816 try self.lower(field_ty.toType(), field_val.toValue());
813817
814818 // Add padding if required.
815819 // TODO: Add to type generation as well?
......@@ -838,7 +842,7 @@ pub const DeclGen = struct {
838842 const active_field_ty = union_obj.field_types.get(ip)[active_field].toType();
839843
840844 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
843847 if (has_tag and tag_first) {
844848 try self.lower(ty.unionTagTypeSafety(mod).?, un.tag.toValue());
......@@ -1094,7 +1098,7 @@ pub const DeclGen = struct {
10941098 val,
10951099 .UniformConstant,
10961100 false,
1097 alignment,
1101 @intCast(alignment.toByteUnits(0)),
10981102 );
10991103 log.debug("indirect constant: index = {}", .{@intFromEnum(spv_decl_index)});
11001104 try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {});
......@@ -1180,7 +1184,7 @@ pub const DeclGen = struct {
11801184 var member_names = std.BoundedArray(CacheString, 4){};
11811185
11821186 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);
11841188 const u8_ty_ref = try self.intType(.unsigned, 8); // TODO: What if Int8Type is not enabled?
11851189
11861190 if (has_tag and tag_first) {
......@@ -1333,7 +1337,7 @@ pub const DeclGen = struct {
13331337 } });
13341338 },
13351339 .Struct => {
1336 const struct_ty = switch (ip.indexToKey(ty.toIntern())) {
1340 const struct_type = switch (ip.indexToKey(ty.toIntern())) {
13371341 .anon_struct_type => |tuple| {
13381342 const member_types = try self.gpa.alloc(CacheRef, tuple.values.len);
13391343 defer self.gpa.free(member_types);
......@@ -1350,13 +1354,12 @@ pub const DeclGen = struct {
13501354 .member_types = member_types[0..member_index],
13511355 } });
13521356 },
1353 .struct_type => |struct_ty| struct_ty,
1357 .struct_type => |struct_type| struct_type,
13541358 else => unreachable,
13551359 };
13561360
1357 const struct_obj = mod.structPtrUnwrap(struct_ty.index).?;
1358 if (struct_obj.layout == .Packed) {
1359 return try self.resolveType(struct_obj.backing_int_ty, .direct);
1361 if (struct_type.layout == .Packed) {
1362 return try self.resolveType(struct_type.backingIntType(ip).toType(), .direct);
13601363 }
13611364
13621365 var member_types = std.ArrayList(CacheRef).init(self.gpa);
......@@ -1365,16 +1368,15 @@ pub const DeclGen = struct {
13651368 var member_names = std.ArrayList(CacheString).init(self.gpa);
13661369 defer member_names.deinit();
13671370
1368 var it = struct_obj.runtimeFieldIterator(mod);
1369 while (it.next()) |field_and_index| {
1370 const field = field_and_index.field;
1371 const index = field_and_index.index;
1372 const field_name = ip.stringToSlice(struct_obj.fields.keys()[index]);
1373 try member_types.append(try self.resolveType(field.ty, .indirect));
1371 var it = struct_type.iterateRuntimeOrder(ip);
1372 while (it.next()) |field_index| {
1373 const field_ty = struct_type.field_types.get(ip)[field_index];
1374 const field_name = ip.stringToSlice(struct_type.field_names.get(ip)[field_index]);
1375 try member_types.append(try self.resolveType(field_ty.toType(), .indirect));
13741376 try member_names.append(try self.spv.resolveString(field_name));
13751377 }
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
13791381 return try self.spv.resolve(.{ .struct_type = .{
13801382 .name = try self.spv.resolveString(name),
......@@ -1500,7 +1502,7 @@ pub const DeclGen = struct {
15001502 const error_align = Type.anyerror.abiAlignment(mod);
15011503 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);
15041506 return .{
15051507 .payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(mod),
15061508 .error_first = error_first,
......@@ -1662,7 +1664,7 @@ pub const DeclGen = struct {
16621664 init_val,
16631665 actual_storage_class,
16641666 final_storage_class == .Generic,
1665 @as(u32, @intCast(decl.alignment.toByteUnits(0))),
1667 @intCast(decl.alignment.toByteUnits(0)),
16661668 );
16671669 }
16681670 }
......@@ -2603,7 +2605,7 @@ pub const DeclGen = struct {
26032605 if (layout.payload_size == 0) return union_handle;
26042606
26052607 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));
26072609 return try self.extractField(tag_ty, union_handle, tag_index);
26082610 }
26092611
src/link/Coff.zig+4-4
......@@ -1118,7 +1118,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In
11181118 },
11191119 };
11201120
1121 const required_alignment = tv.ty.abiAlignment(mod);
1121 const required_alignment: u32 = @intCast(tv.ty.abiAlignment(mod).toByteUnits(0));
11221122 const atom = self.getAtomPtr(atom_index);
11231123 atom.size = @as(u32, @intCast(code.len));
11241124 atom.getSymbolPtr(self).value = try self.allocateAtom(atom_index, atom.size, required_alignment);
......@@ -1196,7 +1196,7 @@ fn updateLazySymbolAtom(
11961196 const gpa = self.base.allocator;
11971197 const mod = self.base.options.module.?;
11981198
1199 var required_alignment: u32 = undefined;
1199 var required_alignment: InternPool.Alignment = .none;
12001200 var code_buffer = std.ArrayList(u8).init(gpa);
12011201 defer code_buffer.deinit();
12021202
......@@ -1240,7 +1240,7 @@ fn updateLazySymbolAtom(
12401240 symbol.section_number = @as(coff.SectionNumber, @enumFromInt(section_index + 1));
12411241 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)));
12441244 errdefer self.freeAtom(atom_index);
12451245
12461246 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
13221322 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
13231323
13241324 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
13271327 const decl_metadata = self.decls.get(decl_index).?;
13281328 const atom_index = decl_metadata.atom;
src/link/Dwarf.zig+13-15
......@@ -341,23 +341,22 @@ pub const DeclState = struct {
341341 try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
342342 }
343343 },
344 .struct_type => |struct_type| s: {
345 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :s;
344 .struct_type => |struct_type| {
346345 // DW.AT.name, DW.FORM.string
347346 try ty.print(dbg_info_buffer.writer(), mod);
348347 try dbg_info_buffer.append(0);
349348
350 if (struct_obj.layout == .Packed) {
349 if (struct_type.layout == .Packed) {
351350 log.debug("TODO implement .debug_info for packed structs", .{});
352351 break :blk;
353352 }
354353
355354 for (
356 struct_obj.fields.keys(),
357 struct_obj.fields.values(),
358 0..,
359 ) |field_name_ip, field, field_index| {
360 if (!field.ty.hasRuntimeBits(mod)) continue;
355 struct_type.field_names.get(ip),
356 struct_type.field_types.get(ip),
357 struct_type.offsets.get(ip),
358 ) |field_name_ip, field_ty, field_off| {
359 if (!field_ty.toType().hasRuntimeBits(mod)) continue;
361360 const field_name = ip.stringToSlice(field_name_ip);
362361 // DW.AT.member
363362 try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2);
......@@ -368,9 +367,8 @@ pub const DeclState = struct {
368367 // DW.AT.type, DW.FORM.ref4
369368 var index = dbg_info_buffer.items.len;
370369 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));
372371 // DW.AT.data_member_location, DW.FORM.udata
373 const field_off = ty.structFieldOffset(field_index, mod);
374372 try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
375373 }
376374 },
......@@ -416,8 +414,8 @@ pub const DeclState = struct {
416414 .Union => {
417415 const union_obj = mod.typeToUnion(ty).?;
418416 const layout = mod.getUnionLayout(union_obj);
419 const payload_offset = if (layout.tag_align >= layout.payload_align) layout.tag_size else 0;
420 const tag_offset = if (layout.tag_align >= layout.payload_align) 0 else layout.payload_size;
417 const payload_offset = if (layout.tag_align.compare(.gte, layout.payload_align)) layout.tag_size else 0;
418 const tag_offset = if (layout.tag_align.compare(.gte, layout.payload_align)) 0 else layout.payload_size;
421419 // TODO this is temporary to match current state of unions in Zig - we don't yet have
422420 // safety checks implemented meaning the implicit tag is not yet stored and generated
423421 // for untagged unions.
......@@ -496,11 +494,11 @@ pub const DeclState = struct {
496494 .ErrorUnion => {
497495 const error_ty = ty.errorUnionSet(mod);
498496 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);
500498 const error_align = Type.anyerror.abiAlignment(mod);
501499 const abi_size = ty.abiSize(mod);
502 const payload_off = if (error_align >= payload_align) Type.anyerror.abiSize(mod) else 0;
503 const error_off = if (error_align >= payload_align) 0 else payload_ty.abiSize(mod);
500 const payload_off = if (error_align.compare(.gte, payload_align)) Type.anyerror.abiSize(mod) else 0;
501 const error_off = if (error_align.compare(.gte, payload_align)) 0 else payload_ty.abiSize(mod);
504502
505503 // DW.AT.structure_type
506504 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 {
409409 const image_base = self.calcImageBase();
410410
411411 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);
413413 const p_align: u16 = switch (self.ptr_width) {
414414 .p32 => @alignOf(elf.Elf32_Phdr),
415415 .p64 => @alignOf(elf.Elf64_Phdr),
......@@ -428,7 +428,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
428428 }
429429
430430 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);
432432 // TODO Same as for GOT
433433 try self.phdrs.append(gpa, .{
434434 .p_type = elf.PT_LOAD,
......@@ -444,7 +444,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
444444 }
445445
446446 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);
448448 const file_size = self.base.options.program_code_size_hint;
449449 const p_align = self.page_size;
450450 const off = self.findFreeSpace(file_size, p_align);
......@@ -465,7 +465,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
465465 }
466466
467467 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);
469469 const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint;
470470 // We really only need ptr alignment but since we are using PROGBITS, linux requires
471471 // page align.
......@@ -490,7 +490,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
490490 }
491491
492492 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);
494494 // TODO Find a hint about how much data need to be in rodata ?
495495 const file_size = 1024;
496496 // Same reason as for GOT
......@@ -513,7 +513,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
513513 }
514514
515515 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);
517517 // TODO Find a hint about how much data need to be in data ?
518518 const file_size = 1024;
519519 // Same reason as for GOT
......@@ -536,7 +536,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
536536 }
537537
538538 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);
540540 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
541541 const off = self.phdrs.items[self.phdr_load_rw_index.?].p_offset;
542542 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 {
556556 }
557557
558558 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);
560560 assert(self.shstrtab.buffer.items.len == 0);
561561 try self.shstrtab.buffer.append(gpa, 0); // need a 0 at position 0
562562 const off = self.findFreeSpace(self.shstrtab.buffer.items.len, 1);
......@@ -578,7 +578,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
578578 }
579579
580580 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);
582582 assert(self.strtab.buffer.items.len == 0);
583583 try self.strtab.buffer.append(gpa, 0); // need a 0 at position 0
584584 const off = self.findFreeSpace(self.strtab.buffer.items.len, 1);
......@@ -600,7 +600,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
600600 }
601601
602602 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);
604604 const phdr = &self.phdrs.items[self.phdr_load_re_index.?];
605605 try self.shdrs.append(gpa, .{
606606 .sh_name = try self.shstrtab.insert(gpa, ".text"),
......@@ -620,7 +620,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
620620 }
621621
622622 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);
624624 const phdr = &self.phdrs.items[self.phdr_got_index.?];
625625 try self.shdrs.append(gpa, .{
626626 .sh_name = try self.shstrtab.insert(gpa, ".got"),
......@@ -639,7 +639,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
639639 }
640640
641641 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);
643643 const phdr = &self.phdrs.items[self.phdr_load_ro_index.?];
644644 try self.shdrs.append(gpa, .{
645645 .sh_name = try self.shstrtab.insert(gpa, ".rodata"),
......@@ -659,7 +659,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
659659 }
660660
661661 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);
663663 const phdr = &self.phdrs.items[self.phdr_load_rw_index.?];
664664 try self.shdrs.append(gpa, .{
665665 .sh_name = try self.shstrtab.insert(gpa, ".data"),
......@@ -679,7 +679,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
679679 }
680680
681681 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);
683683 const phdr = &self.phdrs.items[self.phdr_load_zerofill_index.?];
684684 try self.shdrs.append(gpa, .{
685685 .sh_name = try self.shstrtab.insert(gpa, ".bss"),
......@@ -699,7 +699,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
699699 }
700700
701701 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);
703703 const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym);
704704 const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym);
705705 const file_size = self.base.options.symbol_count_hint * each_size;
......@@ -714,7 +714,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
714714 .sh_size = file_size,
715715 // The section header index of the associated string table.
716716 .sh_link = self.strtab_section_index.?,
717 .sh_info = @as(u32, @intCast(self.symbols.items.len)),
717 .sh_info = @intCast(self.symbols.items.len),
718718 .sh_addralign = min_align,
719719 .sh_entsize = each_size,
720720 });
......@@ -723,7 +723,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
723723
724724 if (self.dwarf) |*dw| {
725725 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);
727727 assert(dw.strtab.buffer.items.len == 0);
728728 try dw.strtab.buffer.append(gpa, 0);
729729 try self.shdrs.append(gpa, .{
......@@ -743,7 +743,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
743743 }
744744
745745 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);
747747 const file_size_hint = 200;
748748 const p_align = 1;
749749 const off = self.findFreeSpace(file_size_hint, p_align);
......@@ -768,7 +768,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
768768 }
769769
770770 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);
772772 const file_size_hint = 128;
773773 const p_align = 1;
774774 const off = self.findFreeSpace(file_size_hint, p_align);
......@@ -793,7 +793,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
793793 }
794794
795795 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);
797797 const file_size_hint = 160;
798798 const p_align = 16;
799799 const off = self.findFreeSpace(file_size_hint, p_align);
......@@ -818,7 +818,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
818818 }
819819
820820 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);
822822 const file_size_hint = 250;
823823 const p_align = 1;
824824 const off = self.findFreeSpace(file_size_hint, p_align);
......@@ -2666,12 +2666,12 @@ fn updateDeclCode(
26662666
26672667 const old_size = atom_ptr.size;
26682668 const old_vaddr = atom_ptr.value;
2669 atom_ptr.alignment = math.log2_int(u64, required_alignment);
2669 atom_ptr.alignment = required_alignment;
26702670 atom_ptr.size = code.len;
26712671
26722672 if (old_size > 0 and self.base.child_pid == null) {
26732673 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);
26752675 if (need_realloc) {
26762676 try atom_ptr.grow(self);
26772677 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.
28692869 const mod = self.base.options.module.?;
28702870 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;
28732873 var code_buffer = std.ArrayList(u8).init(gpa);
28742874 defer code_buffer.deinit();
28752875
......@@ -2918,7 +2918,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.
29182918 const atom_ptr = local_sym.atom(self).?;
29192919 atom_ptr.alive = true;
29202920 atom_ptr.name_offset = name_str_index;
2921 atom_ptr.alignment = math.log2_int(u64, required_alignment);
2921 atom_ptr.alignment = required_alignment;
29222922 atom_ptr.size = code.len;
29232923
29242924 try atom_ptr.allocate(self);
......@@ -2995,7 +2995,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
29952995 const atom_ptr = local_sym.atom(self).?;
29962996 atom_ptr.alive = true;
29972997 atom_ptr.name_offset = name_str_index;
2998 atom_ptr.alignment = math.log2_int(u64, required_alignment);
2998 atom_ptr.alignment = required_alignment;
29992999 atom_ptr.size = code.len;
30003000
30013001 try atom_ptr.allocate(self);
src/link/Elf/Atom.zig+8-9
......@@ -11,7 +11,7 @@ file_index: File.Index = 0,
1111size: u64 = 0,
1212
1313/// Alignment of this atom as a power of two.
14alignment: u8 = 0,
14alignment: Alignment = .@"1",
1515
1616/// Index of the input section.
1717input_section_index: Index = 0,
......@@ -42,6 +42,8 @@ fde_end: u32 = 0,
4242prev_index: Index = 0,
4343next_index: Index = 0,
4444
45pub const Alignment = @import("../../InternPool.zig").Alignment;
46
4547pub fn name(self: Atom, elf_file: *Elf) []const u8 {
4648 return elf_file.strtab.getAssumeExists(self.name_offset);
4749}
......@@ -112,7 +114,6 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
112114 const free_list = &meta.free_list;
113115 const last_atom_index = &meta.last_atom_index;
114116 const new_atom_ideal_capacity = Elf.padToIdeal(self.size);
115 const alignment = try std.math.powi(u64, 2, self.alignment);
116117
117118 // We use these to indicate our intention to update metadata, placing the new atom,
118119 // and possibly removing a free list node.
......@@ -136,7 +137,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
136137 const ideal_capacity_end_vaddr = std.math.add(u64, big_atom.value, ideal_capacity) catch ideal_capacity;
137138 const capacity_end_vaddr = big_atom.value + cap;
138139 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);
140141 if (new_start_vaddr < ideal_capacity_end_vaddr) {
141142 // Additional bookkeeping here to notice if this free list node
142143 // 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 {
163164 } else if (elf_file.atom(last_atom_index.*)) |last| {
164165 const ideal_capacity = Elf.padToIdeal(last.size);
165166 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);
167168 // Set up the metadata to be updated, after errors are no longer possible.
168169 atom_placement = last.atom_index;
169170 break :blk new_start_vaddr;
......@@ -192,7 +193,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
192193 elf_file.debug_aranges_section_dirty = true;
193194 }
194195 }
195 shdr.sh_addralign = @max(shdr.sh_addralign, alignment);
196 shdr.sh_addralign = @max(shdr.sh_addralign, self.alignment.toByteUnitsOptional().?);
196197
197198 // This function can also reallocate an atom.
198199 // 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 {
224225}
225226
226227pub fn grow(self: *Atom, elf_file: *Elf) !void {
227 const alignment = try std.math.powi(u64, 2, self.alignment);
228 const align_ok = std.mem.alignBackward(u64, self.value, alignment) == self.value;
229 const need_realloc = !align_ok or self.size > self.capacity(elf_file);
230 if (need_realloc) try self.allocate(elf_file);
228 if (!self.alignment.check(self.value) or self.size > self.capacity(elf_file))
229 try self.allocate(elf_file);
231230}
232231
233232pub 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,
181181 const data = try self.shdrContents(shndx);
182182 const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*;
183183 atom.size = chdr.ch_size;
184 atom.alignment = math.log2_int(u64, chdr.ch_addralign);
184 atom.alignment = Alignment.fromNonzeroByteUnits(chdr.ch_addralign);
185185 } else {
186186 atom.size = shdr.sh_size;
187 atom.alignment = math.log2_int(u64, shdr.sh_addralign);
187 atom.alignment = Alignment.fromNonzeroByteUnits(shdr.sh_addralign);
188188 }
189189}
190190
......@@ -571,7 +571,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
571571 atom.file = self.index;
572572 atom.size = this_sym.st_size;
573573 const alignment = this_sym.st_value;
574 atom.alignment = math.log2_int(u64, alignment);
574 atom.alignment = Alignment.fromNonzeroByteUnits(alignment);
575575
576576 var sh_flags: u32 = elf.SHF_ALLOC | elf.SHF_WRITE;
577577 if (is_tls) sh_flags |= elf.SHF_TLS;
......@@ -870,3 +870,4 @@ const Fde = eh_frame.Fde;
870870const File = @import("file.zig").File;
871871const StringTable = @import("../strtab.zig").StringTable;
872872const Symbol = @import("Symbol.zig");
873const Alignment = Atom.Alignment;
src/link/MachO.zig+17-18
......@@ -1425,7 +1425,7 @@ pub fn allocateSpecialSymbols(self: *MachO) !void {
14251425
14261426const CreateAtomOpts = struct {
14271427 size: u64 = 0,
1428 alignment: u32 = 0,
1428 alignment: Alignment = .@"1",
14291429};
14301430
14311431pub fn createAtom(self: *MachO, sym_index: u32, opts: CreateAtomOpts) !Atom.Index {
......@@ -1473,7 +1473,7 @@ pub fn createTentativeDefAtoms(self: *MachO) !void {
14731473
14741474 const atom_index = try self.createAtom(global.sym_index, .{
14751475 .size = size,
1476 .alignment = alignment,
1476 .alignment = @enumFromInt(alignment),
14771477 });
14781478 const atom = self.getAtomPtr(atom_index);
14791479 atom.file = global.file;
......@@ -1493,7 +1493,7 @@ pub fn createDyldPrivateAtom(self: *MachO) !void {
14931493 const sym_index = try self.allocateSymbol();
14941494 const atom_index = try self.createAtom(sym_index, .{
14951495 .size = @sizeOf(u64),
1496 .alignment = 3,
1496 .alignment = .@"8",
14971497 });
14981498 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 {
15101510 switch (self.mode) {
15111511 .zld => self.addAtomToSection(atom_index),
15121512 .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");
15141514 log.debug("allocated dyld_private atom at 0x{x}", .{sym.n_value});
15151515 var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64);
15161516 try self.writeAtom(atom_index, &buffer);
......@@ -1521,7 +1521,7 @@ pub fn createDyldPrivateAtom(self: *MachO) !void {
15211521fn createThreadLocalDescriptorAtom(self: *MachO, sym_name: []const u8, target: SymbolWithLoc) !Atom.Index {
15221522 const gpa = self.base.allocator;
15231523 const size = 3 * @sizeOf(u64);
1524 const required_alignment: u32 = 1;
1524 const required_alignment: Alignment = .@"1";
15251525 const sym_index = try self.allocateSymbol();
15261526 const atom_index = try self.createAtom(sym_index, .{});
15271527 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 {
20302030 // capacity, insert a free list node for it.
20312031}
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 {
20342034 const atom = self.getAtom(atom_index);
20352035 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);
20372037 const need_realloc = !align_ok or new_atom_size > atom.capacity(self);
20382038 if (!need_realloc) return sym.n_value;
20392039 return self.allocateAtom(atom_index, new_atom_size, alignment);
......@@ -2350,7 +2350,7 @@ fn updateLazySymbolAtom(
23502350 const gpa = self.base.allocator;
23512351 const mod = self.base.options.module.?;
23522352
2353 var required_alignment: u32 = undefined;
2353 var required_alignment: Alignment = .none;
23542354 var code_buffer = std.ArrayList(u8).init(gpa);
23552355 defer code_buffer.deinit();
23562356
......@@ -2617,7 +2617,7 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64
26172617 sym.n_desc = 0;
26182618
26192619 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
26222622 if (need_realloc) {
26232623 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 {
32043204 self.sections.set(sym.n_sect - 1, section);
32053205}
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 {
32083208 const tracy = trace(@src());
32093209 defer tracy.end();
32103210
......@@ -3247,7 +3247,7 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm
32473247 const ideal_capacity_end_vaddr = math.add(u64, sym.n_value, ideal_capacity) catch ideal_capacity;
32483248 const capacity_end_vaddr = sym.n_value + capacity;
32493249 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);
32513251 if (new_start_vaddr < ideal_capacity_end_vaddr) {
32523252 // Additional bookkeeping here to notice if this free list node
32533253 // 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
32763276 const last_symbol = last.getSymbol(self);
32773277 const ideal_capacity = if (requires_padding) padToIdeal(last.size) else last.size;
32783278 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);
32803280 atom_placement = last_index;
32813281 break :blk new_start_vaddr;
32823282 } else {
3283 break :blk mem.alignForward(u64, segment.vmaddr, alignment);
3283 break :blk alignment.forward(segment.vmaddr);
32843284 }
32853285 };
32863286
......@@ -3295,10 +3295,8 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm
32953295 self.segment_table_dirty = true;
32963296 }
32973297
3298 const align_pow = @as(u32, @intCast(math.log2(alignment)));
3299 if (header.@"align" < align_pow) {
3300 header.@"align" = align_pow;
3301 }
3298 assert(alignment != .none);
3299 header.@"align" = @min(header.@"align", @intFromEnum(alignment));
33023300 self.getAtomPtr(atom_index).size = new_atom_size;
33033301
33043302 if (atom.prev_index) |prev_index| {
......@@ -3338,7 +3336,7 @@ pub fn getGlobalSymbol(self: *MachO, name: []const u8, lib_name: ?[]const u8) !u
33383336
33393337pub fn writeSegmentHeaders(self: *MachO, writer: anytype) !void {
33403338 for (self.segments.items, 0..) |seg, i| {
3341 const indexes = self.getSectionIndexes(@as(u8, @intCast(i)));
3339 const indexes = self.getSectionIndexes(@intCast(i));
33423340 var out_seg = seg;
33433341 out_seg.cmdsize = @sizeOf(macho.segment_command_64);
33443342 out_seg.nsects = 0;
......@@ -5526,6 +5524,7 @@ const Trie = @import("MachO/Trie.zig");
55265524const Type = @import("../type.zig").Type;
55275525const TypedValue = @import("../TypedValue.zig");
55285526const Value = @import("../value.zig").Value;
5527const Alignment = Atom.Alignment;
55295528
55305529pub const DebugSymbols = @import("MachO/DebugSymbols.zig");
55315530pub 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,
2828
2929/// Alignment of this atom as a power of 2.
3030/// For instance, aligmment of 0 should be read as 2^0 = 1 byte aligned.
31alignment: u32 = 0,
31alignment: Alignment = .@"1",
3232
3333/// Points to the previous and next neighbours
3434/// TODO use the same trick as with symbols: reserve index 0 as null atom
3535next_index: ?Index = null,
3636prev_index: ?Index = null,
3737
38pub const Alignment = @import("../../InternPool.zig").Alignment;
39
3840pub const Index = u32;
3941
4042pub 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) !
382382 const out_sect_id = (try Atom.getOutputSection(macho_file, sect)) orelse continue;
383383 if (sect.size == 0) continue;
384384
385 const sect_id = @as(u8, @intCast(id));
385 const sect_id: u8 = @intCast(id);
386386 const sym_index = self.getSectionAliasSymbolIndex(sect_id);
387387 const atom_index = try self.createAtomFromSubsection(
388388 macho_file,
......@@ -391,7 +391,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) !
391391 sym_index,
392392 1,
393393 sect.size,
394 sect.@"align",
394 Alignment.fromLog2Units(sect.@"align"),
395395 out_sect_id,
396396 );
397397 macho_file.addAtomToSection(atom_index);
......@@ -470,7 +470,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) !
470470 sym_index,
471471 1,
472472 atom_size,
473 sect.@"align",
473 Alignment.fromLog2Units(sect.@"align"),
474474 out_sect_id,
475475 );
476476 if (!sect.isZerofill()) {
......@@ -494,10 +494,10 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) !
494494 else
495495 sect.addr + sect.size - addr;
496496
497 const atom_align = if (addr > 0)
497 const atom_align = Alignment.fromLog2Units(if (addr > 0)
498498 @min(@ctz(addr), sect.@"align")
499499 else
500 sect.@"align";
500 sect.@"align");
501501
502502 const atom_index = try self.createAtomFromSubsection(
503503 macho_file,
......@@ -532,7 +532,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) !
532532 sect_start_index,
533533 sect_loc.len,
534534 sect.size,
535 sect.@"align",
535 Alignment.fromLog2Units(sect.@"align"),
536536 out_sect_id,
537537 );
538538 if (!sect.isZerofill()) {
......@@ -551,11 +551,14 @@ fn createAtomFromSubsection(
551551 inner_sym_index: u32,
552552 inner_nsyms_trailing: u32,
553553 size: u64,
554 alignment: u32,
554 alignment: Alignment,
555555 out_sect_id: u8,
556556) !Atom.Index {
557557 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 });
559562 const atom = macho_file.getAtomPtr(atom_index);
560563 atom.inner_sym_index = inner_sym_index;
561564 atom.inner_nsyms_trailing = inner_nsyms_trailing;
......@@ -1115,3 +1118,4 @@ const MachO = @import("../MachO.zig");
11151118const Platform = @import("load_commands.zig").Platform;
11161119const SymbolWithLoc = MachO.SymbolWithLoc;
11171120const 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 {
104104
105105 while (true) {
106106 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
109109 const sym = macho_file.getSymbolPtr(atom.getSymbolWithLoc());
110110 sym.n_value = offset;
......@@ -112,7 +112,7 @@ pub fn createThunks(macho_file: *MachO, sect_id: u8) !void {
112112
113113 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
117117 allocated.putAssumeCapacityNoClobber(group_end, {});
118118
......@@ -196,7 +196,7 @@ fn allocateThunk(
196196
197197 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
201201 if (end_atom_index == atom_index) break;
202202
......@@ -326,7 +326,10 @@ fn isReachable(
326326
327327fn createThunkAtom(macho_file: *MachO) !Atom.Index {
328328 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 });
330333 const sym = macho_file.getSymbolPtr(.{ .sym_index = sym_index });
331334 sym.n_type = macho.N_SECT;
332335 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 {
985985
986986 while (true) {
987987 const atom = macho_file.getAtom(atom_index);
988 const atom_alignment = try math.powi(u32, 2, atom.alignment);
989 const atom_offset = mem.alignForward(u64, header.size, atom_alignment);
988 const atom_offset = atom.alignment.forward(header.size);
990989 const padding = atom_offset - header.size;
991990
992991 const sym = macho_file.getSymbolPtr(atom.getSymbolWithLoc());
993992 sym.n_value = atom_offset;
994993
995994 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| {
999 atom_index = next_index;
1000 } else break;
997 atom_index = atom.next_index orelse break;
1001998 }
1002999 }
10031000
src/link/Plan9.zig+1-1
......@@ -1106,7 +1106,7 @@ fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Ind
11061106 const gpa = self.base.allocator;
11071107 const mod = self.base.options.module.?;
11081108
1109 var required_alignment: u32 = undefined;
1109 var required_alignment: InternPool.Alignment = .none;
11101110 var code_buffer = std.ArrayList(u8).init(gpa);
11111111 defer code_buffer.deinit();
11121112
src/link/Wasm.zig+23-21
......@@ -187,8 +187,10 @@ debug_pubtypes_atom: ?Atom.Index = null,
187187/// rather than by the linker.
188188synthetic_functions: std.ArrayListUnmanaged(Atom.Index) = .{},
189189
190pub const Alignment = types.Alignment;
191
190192pub const Segment = struct {
191 alignment: u32,
193 alignment: Alignment,
192194 size: u32,
193195 offset: u32,
194196 flags: u32,
......@@ -1490,7 +1492,7 @@ fn finishUpdateDecl(wasm: *Wasm, decl_index: Module.Decl.Index, code: []const u8
14901492 try atom.code.appendSlice(wasm.base.allocator, code);
14911493 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);
14941496 if (code.len == 0) return;
14951497 atom.alignment = decl.getAlignment(mod);
14961498}
......@@ -2050,7 +2052,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
20502052 };
20512053
20522054 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
20552057 try wasm.appendAtomAtIndex(final_index, atom_index);
20562058}
......@@ -2121,7 +2123,7 @@ fn allocateAtoms(wasm: *Wasm) !void {
21212123 }
21222124 }
21232125 }
2124 offset = std.mem.alignForward(u32, offset, atom.alignment);
2126 offset = @intCast(atom.alignment.forward(offset));
21252127 atom.offset = offset;
21262128 log.debug("Atom '{s}' allocated from 0x{x:0>8} to 0x{x:0>8} size={d}", .{
21272129 symbol_loc.getName(wasm),
......@@ -2132,7 +2134,7 @@ fn allocateAtoms(wasm: *Wasm) !void {
21322134 offset += atom.size;
21332135 atom_index = atom.prev orelse break;
21342136 }
2135 segment.size = std.mem.alignForward(u32, offset, segment.alignment);
2137 segment.size = @intCast(segment.alignment.forward(offset));
21362138 }
21372139}
21382140
......@@ -2351,7 +2353,7 @@ fn createSyntheticFunction(
23512353 .offset = 0,
23522354 .sym_index = loc.index,
23532355 .file = null,
2354 .alignment = 1,
2356 .alignment = .@"1",
23552357 .next = null,
23562358 .prev = null,
23572359 .code = function_body.moveToUnmanaged(),
......@@ -2382,11 +2384,11 @@ pub fn createFunction(
23822384 const atom_index = @as(Atom.Index, @intCast(wasm.managed_atoms.items.len));
23832385 const atom = try wasm.managed_atoms.addOne(wasm.base.allocator);
23842386 atom.* = .{
2385 .size = @as(u32, @intCast(function_body.items.len)),
2387 .size = @intCast(function_body.items.len),
23862388 .offset = 0,
23872389 .sym_index = loc.index,
23882390 .file = null,
2389 .alignment = 1,
2391 .alignment = .@"1",
23902392 .next = null,
23912393 .prev = null,
23922394 .code = function_body.moveToUnmanaged(),
......@@ -2734,8 +2736,8 @@ fn setupMemory(wasm: *Wasm) !void {
27342736 const page_size = std.wasm.page_size; // 64kb
27352737 // Use the user-provided stack size or else we use 1MB by default
27362738 const stack_size = wasm.base.options.stack_size_override orelse page_size * 16;
2737 const stack_alignment = 16; // wasm's stack alignment as specified by tool-convention
2738 const heap_alignment = 16; // wasm's heap alignment as specified by tool-convention
2739 const stack_alignment: Alignment = .@"16"; // wasm's stack alignment as specified by tool-convention
2740 const heap_alignment: Alignment = .@"16"; // wasm's heap alignment as specified by tool-convention
27392741
27402742 // Always place the stack at the start by default
27412743 // unless the user specified the global-base flag
......@@ -2748,7 +2750,7 @@ fn setupMemory(wasm: *Wasm) !void {
27482750 const is_obj = wasm.base.options.output_mode == .Obj;
27492751
27502752 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);
27522754 memory_ptr += stack_size;
27532755 // We always put the stack pointer global at index 0
27542756 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 {
27582760 var data_seg_it = wasm.data_segments.iterator();
27592761 while (data_seg_it.next()) |entry| {
27602762 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
27632765 // set TLS-related symbols
27642766 if (mem.eql(u8, entry.key_ptr.*, ".tdata")) {
......@@ -2768,7 +2770,7 @@ fn setupMemory(wasm: *Wasm) !void {
27682770 }
27692771 if (wasm.findGlobalSymbol("__tls_align")) |loc| {
27702772 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().?);
27722774 }
27732775 if (wasm.findGlobalSymbol("__tls_base")) |loc| {
27742776 const sym = loc.getSymbol(wasm);
......@@ -2795,7 +2797,7 @@ fn setupMemory(wasm: *Wasm) !void {
27952797 }
27962798
27972799 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);
27992801 memory_ptr += stack_size;
28002802 wasm.wasm_globals.items[0].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr))));
28012803 }
......@@ -2804,7 +2806,7 @@ fn setupMemory(wasm: *Wasm) !void {
28042806 // We must set its virtual address so it can be used in relocations.
28052807 if (wasm.findGlobalSymbol("__heap_base")) |loc| {
28062808 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));
28082810 }
28092811
28102812 // Setup the max amount of pages
......@@ -2879,7 +2881,7 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32
28792881 flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE);
28802882 }
28812883 try wasm.segments.append(wasm.base.allocator, .{
2882 .alignment = 1,
2884 .alignment = .@"1",
28832885 .size = 0,
28842886 .offset = 0,
28852887 .flags = flags,
......@@ -2954,7 +2956,7 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32
29542956/// Appends a new segment with default field values
29552957fn appendDummySegment(wasm: *Wasm) !void {
29562958 try wasm.segments.append(wasm.base.allocator, .{
2957 .alignment = 1,
2959 .alignment = .@"1",
29582960 .size = 0,
29592961 .offset = 0,
29602962 .flags = 0,
......@@ -3011,7 +3013,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void {
30113013 // the pointers into the list using addends which are appended to the relocation.
30123014 const names_atom_index = try wasm.createAtom();
30133015 const names_atom = wasm.getAtomPtr(names_atom_index);
3014 names_atom.alignment = 1;
3016 names_atom.alignment = .@"1";
30153017 const sym_name = try wasm.string_table.put(wasm.base.allocator, "__zig_err_names");
30163018 const names_symbol = &wasm.symbols.items[names_atom.sym_index];
30173019 names_symbol.* = .{
......@@ -3085,7 +3087,7 @@ pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) !
30853087 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
30863088 };
30873089
3088 atom.alignment = 1; // debug sections are always 1-byte-aligned
3090 atom.alignment = .@"1"; // debug sections are always 1-byte-aligned
30893091 return atom_index;
30903092}
30913093
......@@ -4724,12 +4726,12 @@ fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.ArrayList(u8)) !void {
47244726 for (wasm.segment_info.values()) |segment_info| {
47254727 log.debug("Emit segment: {s} align({d}) flags({b})", .{
47264728 segment_info.name,
4727 @ctz(segment_info.alignment),
4729 segment_info.alignment,
47284730 segment_info.flags,
47294731 });
47304732 try leb.writeULEB128(writer, @as(u32, @intCast(segment_info.name.len)));
47314733 try writer.writeAll(segment_info.name);
4732 try leb.writeULEB128(writer, @ctz(segment_info.alignment));
4734 try leb.writeULEB128(writer, segment_info.alignment.toLog2Units());
47334735 try leb.writeULEB128(writer, segment_info.flags);
47344736 }
47354737
src/link/Wasm/Atom.zig+2-2
......@@ -19,7 +19,7 @@ relocs: std.ArrayListUnmanaged(types.Relocation) = .{},
1919/// Contains the binary data of an atom, which can be non-relocated
2020code: std.ArrayListUnmanaged(u8) = .{},
2121/// For code this is 1, for data this is set to the highest value of all segments
22alignment: u32,
22alignment: Wasm.Alignment,
2323/// Offset into the section where the atom lives, this already accounts
2424/// for alignment.
2525offset: u32,
......@@ -43,7 +43,7 @@ pub const Index = u32;
4343
4444/// Represents a default empty wasm `Atom`
4545pub const empty: Atom = .{
46 .alignment = 1,
46 .alignment = .@"1",
4747 .file = null,
4848 .next = null,
4949 .offset = 0,
src/link/Wasm/Object.zig+7-9
......@@ -8,6 +8,7 @@ const types = @import("types.zig");
88const std = @import("std");
99const Wasm = @import("../Wasm.zig");
1010const Symbol = @import("Symbol.zig");
11const Alignment = types.Alignment;
1112
1213const Allocator = std.mem.Allocator;
1314const leb = std.leb;
......@@ -88,12 +89,9 @@ const RelocatableData = struct {
8889 /// meta data of the given object file.
8990 /// NOTE: Alignment is encoded as a power of 2, so we shift the symbol's
9091 /// alignment to retrieve the natural alignment.
91 pub fn getAlignment(relocatable_data: RelocatableData, object: *const Object) u32 {
92 if (relocatable_data.type != .data) return 1;
93 const data_alignment = 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));
92 pub fn getAlignment(relocatable_data: RelocatableData, object: *const Object) Alignment {
93 if (relocatable_data.type != .data) return .@"1";
94 return object.segment_info[relocatable_data.index].alignment;
9795 }
9896
9997 /// Returns the symbol kind that corresponds to the relocatable section
......@@ -671,7 +669,7 @@ fn Parser(comptime ReaderType: type) type {
671669 try reader.readNoEof(name);
672670 segment.* = .{
673671 .name = name,
674 .alignment = try leb.readULEB128(u32, reader),
672 .alignment = @enumFromInt(try leb.readULEB128(u32, reader)),
675673 .flags = try leb.readULEB128(u32, reader),
676674 };
677675 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
919917 continue; // found unknown section, so skip parsing into atom as we do not know how to handle it.
920918 };
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);
923921 const atom = try wasm_bin.managed_atoms.addOne(gpa);
924922 atom.* = Atom.empty;
925923 atom.file = object_index;
......@@ -984,7 +982,7 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b
984982
985983 const segment: *Wasm.Segment = &wasm_bin.segments.items[final_index];
986984 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);
988986 }
989987
990988 try wasm_bin.appendAtomAtIndex(final_index, atom_index);
src/link/Wasm/types.zig+3-1
......@@ -109,11 +109,13 @@ pub const SubsectionType = enum(u8) {
109109 WASM_SYMBOL_TABLE = 8,
110110};
111111
112pub const Alignment = @import("../../InternPool.zig").Alignment;
113
112114pub const Segment = struct {
113115 /// Segment's name, encoded as UTF-8 bytes.
114116 name: []const u8,
115117 /// The required alignment of the segment, encoded as a power of 2
116 alignment: u32,
118 alignment: Alignment,
117119 /// Bitfield containing flags for a segment
118120 flags: u32,
119121
src/target.zig+7-6
......@@ -1,6 +1,7 @@
11const std = @import("std");
22const Type = @import("type.zig").Type;
33const AddressSpace = std.builtin.AddressSpace;
4const Alignment = @import("InternPool.zig").Alignment;
45
56pub const ArchOsAbi = struct {
67 arch: std.Target.Cpu.Arch,
......@@ -595,13 +596,13 @@ pub fn llvmMachineAbi(target: std.Target) ?[:0]const u8 {
595596}
596597
597598/// 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 {
599600 return switch (target.cpu.arch) {
600 .arm, .armeb => 4,
601 .aarch64, .aarch64_32, .aarch64_be => 4,
602 .sparc, .sparcel, .sparc64 => 4,
603 .riscv64 => 2,
604 else => 1,
601 .arm, .armeb => .@"4",
602 .aarch64, .aarch64_32, .aarch64_be => .@"4",
603 .sparc, .sparcel, .sparc64 => .@"4",
604 .riscv64 => .@"2",
605 else => .@"1",
605606 };
606607}
607608
src/type.zig+261-390
......@@ -9,6 +9,7 @@ const target_util = @import("target.zig");
99const TypedValue = @import("TypedValue.zig");
1010const Sema = @import("Sema.zig");
1111const InternPool = @import("InternPool.zig");
12const Alignment = InternPool.Alignment;
1213
1314/// Both types and values are canonically represented by a single 32-bit integer
1415/// which is an index into an `InternPool` data structure.
......@@ -196,7 +197,9 @@ pub const Type = struct {
196197 info.packed_offset.host_size != 0 or
197198 info.flags.vector_index != .none)
198199 {
199 const alignment = info.flags.alignment.toByteUnitsOptional() orelse
200 const alignment = if (info.flags.alignment != .none)
201 info.flags.alignment
202 else
200203 info.child.toType().abiAlignment(mod);
201204 try writer.print("align({d}", .{alignment});
202205
......@@ -315,8 +318,8 @@ pub const Type = struct {
315318 .generic_poison => unreachable,
316319 },
317320 .struct_type => |struct_type| {
318 if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| {
319 const decl = mod.declPtr(struct_obj.owner_decl);
321 if (struct_type.decl.unwrap()) |decl_index| {
322 const decl = mod.declPtr(decl_index);
320323 try decl.renderFullyQualifiedName(mod, writer);
321324 } else if (struct_type.namespace.unwrap()) |namespace_index| {
322325 const namespace = mod.namespacePtr(namespace_index);
......@@ -561,24 +564,20 @@ pub const Type = struct {
561564 .generic_poison => unreachable,
562565 },
563566 .struct_type => |struct_type| {
564 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse {
565 // This struct has no fields.
566 return false;
567 };
568 if (struct_obj.status == .field_types_wip) {
567 if (struct_type.assumeRuntimeBitsIfFieldTypesWip(ip)) {
569568 // In this case, we guess that hasRuntimeBits() for this type is true,
570569 // and then later if our guess was incorrect, we emit a compile error.
571 struct_obj.assumed_runtime_bits = true;
572570 return true;
573571 }
574572 switch (strat) {
575573 .sema => |sema| _ = try sema.resolveTypeFields(ty),
576 .eager => assert(struct_obj.haveFieldTypes()),
577 .lazy => if (!struct_obj.haveFieldTypes()) return error.NeedLazy,
574 .eager => assert(struct_type.haveFieldTypes(ip)),
575 .lazy => if (!struct_type.haveFieldTypes(ip)) return error.NeedLazy,
578576 }
579 for (struct_obj.fields.values()) |field| {
580 if (field.is_comptime) continue;
581 if (try field.ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat))
577 for (0..struct_type.field_types.len) |i| {
578 if (struct_type.comptime_bits.getBit(ip, i)) continue;
579 const field_ty = struct_type.field_types.get(ip)[i].toType();
580 if (try field_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat))
582581 return true;
583582 } else {
584583 return false;
......@@ -728,11 +727,8 @@ pub const Type = struct {
728727 => false,
729728 },
730729 .struct_type => |struct_type| {
731 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse {
732 // Struct with no fields has a well-defined layout of no bits.
733 return true;
734 };
735 return struct_obj.layout != .Auto;
730 // Struct with no fields have a well-defined layout of no bits.
731 return struct_type.layout != .Auto or struct_type.field_types.len == 0;
736732 },
737733 .union_type => |union_type| switch (union_type.flagsPtr(ip).runtime_tag) {
738734 .none, .safety => union_type.flagsPtr(ip).layout != .Auto,
......@@ -806,22 +802,23 @@ pub const Type = struct {
806802 return mod.intern_pool.isNoReturn(ty.toIntern());
807803 }
808804
809 /// Returns 0 if the pointer is naturally aligned and the element type is 0-bit.
810 pub fn ptrAlignment(ty: Type, mod: *Module) u32 {
805 /// Returns `none` if the pointer is naturally aligned and the element type is 0-bit.
806 pub fn ptrAlignment(ty: Type, mod: *Module) Alignment {
811807 return ptrAlignmentAdvanced(ty, mod, null) catch unreachable;
812808 }
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 {
815811 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
816812 .ptr_type => |ptr_type| {
817 if (ptr_type.flags.alignment.toByteUnitsOptional()) |a| {
818 return @as(u32, @intCast(a));
819 } else if (opt_sema) |sema| {
813 if (ptr_type.flags.alignment != .none)
814 return ptr_type.flags.alignment;
815
816 if (opt_sema) |sema| {
820817 const res = try ptr_type.child.toType().abiAlignmentAdvanced(mod, .{ .sema = sema });
821818 return res.scalar;
822 } else {
823 return (ptr_type.child.toType().abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar;
824819 }
820
821 return (ptr_type.child.toType().abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar;
825822 },
826823 .opt_type => |child| child.toType().ptrAlignmentAdvanced(mod, opt_sema),
827824 else => unreachable,
......@@ -836,8 +833,8 @@ pub const Type = struct {
836833 };
837834 }
838835
839 /// Returns 0 for 0-bit types.
840 pub fn abiAlignment(ty: Type, mod: *Module) u32 {
836 /// Returns `none` for 0-bit types.
837 pub fn abiAlignment(ty: Type, mod: *Module) Alignment {
841838 return (ty.abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar;
842839 }
843840
......@@ -846,12 +843,12 @@ pub const Type = struct {
846843 pub fn lazyAbiAlignment(ty: Type, mod: *Module) !Value {
847844 switch (try ty.abiAlignmentAdvanced(mod, .lazy)) {
848845 .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().?),
850847 }
851848 }
852849
853850 pub const AbiAlignmentAdvanced = union(enum) {
854 scalar: u32,
851 scalar: Alignment,
855852 val: Value,
856853 };
857854
......@@ -881,36 +878,36 @@ pub const Type = struct {
881878 };
882879
883880 switch (ty.toIntern()) {
884 .empty_struct_type => return AbiAlignmentAdvanced{ .scalar = 0 },
881 .empty_struct_type => return AbiAlignmentAdvanced{ .scalar = .none },
885882 else => switch (ip.indexToKey(ty.toIntern())) {
886883 .int_type => |int_type| {
887 if (int_type.bits == 0) return AbiAlignmentAdvanced{ .scalar = 0 };
888 return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(int_type.bits, target) };
884 if (int_type.bits == 0) return AbiAlignmentAdvanced{ .scalar = .none };
885 return .{ .scalar = intAbiAlignment(int_type.bits, target) };
889886 },
890887 .ptr_type, .anyframe_type => {
891 return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) };
888 return .{ .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)) };
892889 },
893890 .array_type => |array_type| {
894891 return array_type.child.toType().abiAlignmentAdvanced(mod, strat);
895892 },
896893 .vector_type => |vector_type| {
897894 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);
899896 const bytes = ((bits * vector_type.len) + 7) / 8;
900897 const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes);
901 return AbiAlignmentAdvanced{ .scalar = alignment };
898 return .{ .scalar = Alignment.fromByteUnits(alignment) };
902899 },
903900
904901 .opt_type => return abiAlignmentAdvancedOptional(ty, mod, strat),
905902 .error_union_type => |info| return abiAlignmentAdvancedErrorUnion(ty, mod, strat, info.payload_type.toType()),
906903
907904 // 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
910907 // represents machine code; not a pointer
911 .func_type => |func_type| return AbiAlignmentAdvanced{
912 .scalar = if (func_type.alignment.toByteUnitsOptional()) |a|
913 @as(u32, @intCast(a))
908 .func_type => |func_type| return .{
909 .scalar = if (func_type.alignment != .none)
910 func_type.alignment
914911 else
915912 target_util.defaultFunctionAlignment(target),
916913 },
......@@ -926,47 +923,49 @@ pub const Type = struct {
926923 .call_modifier,
927924 .prefetch_options,
928925 .anyopaque,
929 => return AbiAlignmentAdvanced{ .scalar = 1 },
926 => return .{ .scalar = .@"1" },
930927
931928 .usize,
932929 .isize,
933930 .export_options,
934931 .extern_options,
935 => return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) },
936
937 .c_char => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.char) },
938 .c_short => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.short) },
939 .c_ushort => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ushort) },
940 .c_int => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.int) },
941 .c_uint => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.uint) },
942 .c_long => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.long) },
943 .c_ulong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ulong) },
944 .c_longlong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longlong) },
945 .c_ulonglong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ulonglong) },
946 .c_longdouble => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) },
947
948 .f16 => return AbiAlignmentAdvanced{ .scalar = 2 },
949 .f32 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.float) },
932 => return .{
933 .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)),
934 },
935
936 .c_char => return .{ .scalar = cTypeAlign(target, .char) },
937 .c_short => return .{ .scalar = cTypeAlign(target, .short) },
938 .c_ushort => return .{ .scalar = cTypeAlign(target, .ushort) },
939 .c_int => return .{ .scalar = cTypeAlign(target, .int) },
940 .c_uint => return .{ .scalar = cTypeAlign(target, .uint) },
941 .c_long => return .{ .scalar = cTypeAlign(target, .long) },
942 .c_ulong => return .{ .scalar = cTypeAlign(target, .ulong) },
943 .c_longlong => return .{ .scalar = cTypeAlign(target, .longlong) },
944 .c_ulonglong => return .{ .scalar = cTypeAlign(target, .ulonglong) },
945 .c_longdouble => return .{ .scalar = cTypeAlign(target, .longdouble) },
946
947 .f16 => return .{ .scalar = .@"2" },
948 .f32 => return .{ .scalar = cTypeAlign(target, .float) },
950949 .f64 => switch (target.c_type_bit_size(.double)) {
951 64 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.double) },
952 else => return AbiAlignmentAdvanced{ .scalar = 8 },
950 64 => return .{ .scalar = cTypeAlign(target, .double) },
951 else => return .{ .scalar = .@"8" },
953952 },
954953 .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) },
956955 else => {
957956 const u80_ty: Type = .{ .ip_index = .u80_type };
958 return AbiAlignmentAdvanced{ .scalar = abiAlignment(u80_ty, mod) };
957 return .{ .scalar = abiAlignment(u80_ty, mod) };
959958 },
960959 },
961960 .f128 => switch (target.c_type_bit_size(.longdouble)) {
962 128 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) },
963 else => return AbiAlignmentAdvanced{ .scalar = 16 },
961 128 => return .{ .scalar = cTypeAlign(target, .longdouble) },
962 else => return .{ .scalar = .@"16" },
964963 },
965964
966965 // TODO revisit this when we have the concept of the error tag type
967966 .anyerror,
968967 .adhoc_inferred_error_set,
969 => return AbiAlignmentAdvanced{ .scalar = 2 },
968 => return .{ .scalar = .@"2" },
970969
971970 .void,
972971 .type,
......@@ -976,89 +975,57 @@ pub const Type = struct {
976975 .undefined,
977976 .enum_literal,
978977 .type_info,
979 => return AbiAlignmentAdvanced{ .scalar = 0 },
978 => return .{ .scalar = .none },
980979
981980 .noreturn => unreachable,
982981 .generic_poison => unreachable,
983982 },
984983 .struct_type => |struct_type| {
985 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse
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) {
984 if (struct_type.layout == .Packed) {
1006985 switch (strat) {
1007986 .sema => |sema| try sema.resolveTypeLayout(ty),
1008 .lazy => if (!struct_obj.haveLayout()) return .{ .val = (try mod.intern(.{ .int = .{
1009 .ty = .comptime_int_type,
1010 .storage = .{ .lazy_align = ty.toIntern() },
1011 } })).toValue() },
987 .lazy => if (struct_type.backingIntType(ip).* == .none) return .{
988 .val = (try mod.intern(.{ .int = .{
989 .ty = .comptime_int_type,
990 .storage = .{ .lazy_align = ty.toIntern() },
991 } })).toValue(),
992 },
1012993 .eager => {},
1013994 }
1014 assert(struct_obj.haveLayout());
1015 return AbiAlignmentAdvanced{ .scalar = struct_obj.backing_int_ty.abiAlignment(mod) };
995 assert(struct_type.backingIntType(ip).* != .none);
996 return .{ .scalar = struct_type.backingIntType(ip).toType().abiAlignment(mod) };
1016997 }
1017998
1018 const fields = ty.structFields(mod);
1019 var big_align: u32 = 0;
1020 for (fields.values()) |field| {
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;
999 const flags = struct_type.flagsPtr(ip).*;
1000 if (flags.layout_resolved)
1001 return .{ .scalar = flags.alignment };
10281002
1029 const field_align = @as(u32, @intCast(field.abi_align.toByteUnitsOptional() orelse
1030 switch (try field.ty.abiAlignmentAdvanced(mod, strat)) {
1031 .scalar => |a| a,
1032 .val => switch (strat) {
1033 .eager => unreachable, // struct layout not resolved
1034 .sema => unreachable, // handled above
1035 .lazy => return .{ .val = (try mod.intern(.{ .int = .{
1036 .ty = .comptime_int_type,
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);
1003 switch (strat) {
1004 .eager => unreachable, // struct layout not resolved
1005 .sema => |sema| {
1006 if (flags.field_types_wip) {
1007 // We'll guess "pointer-aligned", if the struct has an
1008 // underaligned pointer field then some allocations
1009 // might require explicit alignment.
1010 return .{ .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)) };
10491011 }
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() },
10511019 }
1052 return AbiAlignmentAdvanced{ .scalar = big_align };
10531020 },
10541021 .anon_struct_type => |tuple| {
1055 var big_align: u32 = 0;
1022 var big_align: Alignment = .none;
10561023 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
10571024 if (val != .none) continue; // comptime field
10581025 if (!(field_ty.toType().hasRuntimeBits(mod))) continue;
10591026
10601027 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),
10621029 .val => switch (strat) {
10631030 .eager => unreachable, // field type alignment not resolved
10641031 .sema => unreachable, // passed to abiAlignmentAdvanced above
......@@ -1069,7 +1036,7 @@ pub const Type = struct {
10691036 },
10701037 }
10711038 }
1072 return AbiAlignmentAdvanced{ .scalar = big_align };
1039 return .{ .scalar = big_align };
10731040 },
10741041
10751042 .union_type => |union_type| {
......@@ -1078,7 +1045,7 @@ pub const Type = struct {
10781045 // We'll guess "pointer-aligned", if the union has an
10791046 // underaligned pointer field then some allocations
10801047 // might require explicit alignment.
1081 return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) };
1048 return .{ .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)) };
10821049 }
10831050 _ = try sema.resolveTypeFields(ty);
10841051 }
......@@ -1095,13 +1062,13 @@ pub const Type = struct {
10951062 if (union_obj.hasTag(ip)) {
10961063 return abiAlignmentAdvanced(union_obj.enum_tag_ty.toType(), mod, strat);
10971064 } else {
1098 return AbiAlignmentAdvanced{
1099 .scalar = @intFromBool(union_obj.flagsPtr(ip).layout == .Extern),
1065 return .{
1066 .scalar = Alignment.fromByteUnits(@intFromBool(union_obj.flagsPtr(ip).layout == .Extern)),
11001067 };
11011068 }
11021069 }
11031070
1104 var max_align: u32 = 0;
1071 var max_align: Alignment = .none;
11051072 if (union_obj.hasTag(ip)) max_align = union_obj.enum_tag_ty.toType().abiAlignment(mod);
11061073 for (0..union_obj.field_names.len) |field_index| {
11071074 const field_ty = union_obj.field_types.get(ip)[field_index].toType();
......@@ -1117,8 +1084,9 @@ pub const Type = struct {
11171084 else => |e| return e,
11181085 })) continue;
11191086
1120 const field_align_bytes: u32 = @intCast(field_align.toByteUnitsOptional() orelse
1121 switch (try field_ty.abiAlignmentAdvanced(mod, strat)) {
1087 const field_align_bytes: Alignment = if (field_align != .none)
1088 field_align
1089 else switch (try field_ty.abiAlignmentAdvanced(mod, strat)) {
11221090 .scalar => |a| a,
11231091 .val => switch (strat) {
11241092 .eager => unreachable, // struct layout not resolved
......@@ -1128,13 +1096,15 @@ pub const Type = struct {
11281096 .storage = .{ .lazy_align = ty.toIntern() },
11291097 } })).toValue() },
11301098 },
1131 });
1132 max_align = @max(max_align, field_align_bytes);
1099 };
1100 max_align = max_align.max(field_align_bytes);
11331101 }
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),
11351107 },
1136 .opaque_type => return AbiAlignmentAdvanced{ .scalar = 1 },
1137 .enum_type => |enum_type| return AbiAlignmentAdvanced{ .scalar = enum_type.tag_ty.toType().abiAlignment(mod) },
11381108
11391109 // values, not types
11401110 .undef,
......@@ -1179,20 +1149,15 @@ pub const Type = struct {
11791149 } })).toValue() },
11801150 else => |e| return e,
11811151 })) {
1182 return AbiAlignmentAdvanced{ .scalar = code_align };
1152 return .{ .scalar = code_align };
11831153 }
1184 return AbiAlignmentAdvanced{ .scalar = @max(
1185 code_align,
1154 return .{ .scalar = code_align.max(
11861155 (try payload_ty.abiAlignmentAdvanced(mod, strat)).scalar,
11871156 ) };
11881157 },
11891158 .lazy => {
11901159 switch (try payload_ty.abiAlignmentAdvanced(mod, strat)) {
1191 .scalar => |payload_align| {
1192 return AbiAlignmentAdvanced{
1193 .scalar = @max(code_align, payload_align),
1194 };
1195 },
1160 .scalar => |payload_align| return .{ .scalar = code_align.max(payload_align) },
11961161 .val => {},
11971162 }
11981163 return .{ .val = (try mod.intern(.{ .int = .{
......@@ -1212,9 +1177,11 @@ pub const Type = struct {
12121177 const child_type = ty.optionalChild(mod);
12131178
12141179 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 },
12161183 .ErrorSet => return abiAlignmentAdvanced(Type.anyerror, mod, strat),
1217 .NoReturn => return AbiAlignmentAdvanced{ .scalar = 0 },
1184 .NoReturn => return .{ .scalar = .none },
12181185 else => {},
12191186 }
12201187
......@@ -1227,12 +1194,12 @@ pub const Type = struct {
12271194 } })).toValue() },
12281195 else => |e| return e,
12291196 })) {
1230 return AbiAlignmentAdvanced{ .scalar = 1 };
1197 return .{ .scalar = .@"1" };
12311198 }
12321199 return child_type.abiAlignmentAdvanced(mod, strat);
12331200 },
12341201 .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") },
12361203 .val => return .{ .val = (try mod.intern(.{ .int = .{
12371204 .ty = .comptime_int_type,
12381205 .storage = .{ .lazy_align = ty.toIntern() },
......@@ -1310,8 +1277,7 @@ pub const Type = struct {
13101277 .storage = .{ .lazy_size = ty.toIntern() },
13111278 } })).toValue() },
13121279 };
1313 const elem_bits_u64 = try vector_type.child.toType().bitSizeAdvanced(mod, opt_sema);
1314 const elem_bits = @as(u32, @intCast(elem_bits_u64));
1280 const elem_bits = try vector_type.child.toType().bitSizeAdvanced(mod, opt_sema);
13151281 const total_bits = elem_bits * vector_type.len;
13161282 const total_bytes = (total_bits + 7) / 8;
13171283 const alignment = switch (try ty.abiAlignmentAdvanced(mod, strat)) {
......@@ -1321,8 +1287,7 @@ pub const Type = struct {
13211287 .storage = .{ .lazy_size = ty.toIntern() },
13221288 } })).toValue() },
13231289 };
1324 const result = std.mem.alignForward(u32, total_bytes, alignment);
1325 return AbiSizeAdvanced{ .scalar = result };
1290 return AbiSizeAdvanced{ .scalar = alignment.forward(total_bytes) };
13261291 },
13271292
13281293 .opt_type => return ty.abiSizeAdvancedOptional(mod, strat),
......@@ -1360,16 +1325,16 @@ pub const Type = struct {
13601325 };
13611326
13621327 var size: u64 = 0;
1363 if (code_align > payload_align) {
1328 if (code_align.compare(.gt, payload_align)) {
13641329 size += code_size;
1365 size = std.mem.alignForward(u64, size, payload_align);
1330 size = payload_align.forward(size);
13661331 size += payload_size;
1367 size = std.mem.alignForward(u64, size, code_align);
1332 size = code_align.forward(size);
13681333 } else {
13691334 size += payload_size;
1370 size = std.mem.alignForward(u64, size, code_align);
1335 size = code_align.forward(size);
13711336 size += code_size;
1372 size = std.mem.alignForward(u64, size, payload_align);
1337 size = payload_align.forward(size);
13731338 }
13741339 return AbiSizeAdvanced{ .scalar = size };
13751340 },
......@@ -1435,41 +1400,43 @@ pub const Type = struct {
14351400 .noreturn => unreachable,
14361401 .generic_poison => unreachable,
14371402 },
1438 .struct_type => |struct_type| switch (ty.containerLayout(mod)) {
1439 .Packed => {
1440 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse
1441 return AbiSizeAdvanced{ .scalar = 0 };
1442
1443 switch (strat) {
1444 .sema => |sema| try sema.resolveTypeLayout(ty),
1445 .lazy => if (!struct_obj.haveLayout()) return .{ .val = (try mod.intern(.{ .int = .{
1446 .ty = .comptime_int_type,
1447 .storage = .{ .lazy_size = ty.toIntern() },
1448 } })).toValue() },
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() };
1403 .struct_type => |struct_type| {
1404 switch (strat) {
1405 .sema => |sema| try sema.resolveTypeLayout(ty),
1406 .lazy => switch (struct_type.layout) {
1407 .Packed => {
1408 if (struct_type.backingIntType(ip).* == .none) return .{
1409 .val = (try mod.intern(.{ .int = .{
1410 .ty = .comptime_int_type,
1411 .storage = .{ .lazy_size = ty.toIntern() },
1412 } })).toValue(),
1413 };
14641414 },
1465 .eager => {},
1466 }
1467 const field_count = ty.structFieldCount(mod);
1468 if (field_count == 0) {
1469 return AbiSizeAdvanced{ .scalar = 0 };
1470 }
1471 return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, mod) };
1472 },
1415 .Auto, .Extern => {
1416 if (!struct_type.haveLayout(ip)) return .{
1417 .val = (try mod.intern(.{ .int = .{
1418 .ty = .comptime_int_type,
1419 .storage = .{ .lazy_size = ty.toIntern() },
1420 } })).toValue(),
1421 };
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 }
14731440 },
14741441 .anon_struct_type => |tuple| {
14751442 switch (strat) {
......@@ -1565,20 +1532,19 @@ pub const Type = struct {
15651532 // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
15661533 // to the child type's ABI alignment.
15671534 return AbiSizeAdvanced{
1568 .scalar = child_ty.abiAlignment(mod) + payload_size,
1535 .scalar = child_ty.abiAlignment(mod).toByteUnits(0) + payload_size,
15691536 };
15701537 }
15711538
15721539 fn intAbiSize(bits: u16, target: Target) u64 {
1573 const alignment = intAbiAlignment(bits, target);
1574 return std.mem.alignForward(u64, @as(u16, @intCast((@as(u17, bits) + 7) / 8)), alignment);
1540 return intAbiAlignment(bits, target).forward(@as(u16, @intCast((@as(u17, bits) + 7) / 8)));
15751541 }
15761542
1577 fn intAbiAlignment(bits: u16, target: Target) u32 {
1578 return @min(
1543 fn intAbiAlignment(bits: u16, target: Target) Alignment {
1544 return Alignment.fromByteUnits(@min(
15791545 std.math.ceilPowerOfTwoPromote(u16, @as(u16, @intCast((@as(u17, bits) + 7) / 8))),
15801546 target.maxIntAlignment(),
1581 );
1547 ));
15821548 }
15831549
15841550 pub fn bitSize(ty: Type, mod: *Module) u64 {
......@@ -1610,7 +1576,7 @@ pub const Type = struct {
16101576 const len = array_type.len + @intFromBool(array_type.sentinel != .none);
16111577 if (len == 0) return 0;
16121578 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));
16141580 if (elem_size == 0) return 0;
16151581 const elem_bit_size = try bitSizeAdvanced(elem_ty, mod, opt_sema);
16161582 return (len - 1) * 8 * elem_size + elem_bit_size;
......@@ -1675,26 +1641,24 @@ pub const Type = struct {
16751641 .enum_literal => unreachable,
16761642 .generic_poison => unreachable,
16771643
1678 .atomic_order => unreachable, // missing call to resolveTypeFields
1679 .atomic_rmw_op => unreachable, // missing call to resolveTypeFields
1680 .calling_convention => unreachable, // missing call to resolveTypeFields
1681 .address_space => unreachable, // missing call to resolveTypeFields
1682 .float_mode => unreachable, // missing call to resolveTypeFields
1683 .reduce_op => unreachable, // missing call to resolveTypeFields
1684 .call_modifier => unreachable, // missing call to resolveTypeFields
1685 .prefetch_options => unreachable, // missing call to resolveTypeFields
1686 .export_options => unreachable, // missing call to resolveTypeFields
1687 .extern_options => unreachable, // missing call to resolveTypeFields
1688 .type_info => unreachable, // missing call to resolveTypeFields
1644 .atomic_order => unreachable,
1645 .atomic_rmw_op => unreachable,
1646 .calling_convention => unreachable,
1647 .address_space => unreachable,
1648 .float_mode => unreachable,
1649 .reduce_op => unreachable,
1650 .call_modifier => unreachable,
1651 .prefetch_options => unreachable,
1652 .export_options => unreachable,
1653 .extern_options => unreachable,
1654 .type_info => unreachable,
16891655 },
16901656 .struct_type => |struct_type| {
1691 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return 0;
1692 if (struct_obj.layout != .Packed) {
1693 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
1657 if (struct_type.layout == .Packed) {
1658 if (opt_sema) |sema| _ = try sema.resolveTypeLayout(ty);
1659 return try struct_type.backingIntType(ip).*.toType().bitSizeAdvanced(mod, opt_sema);
16941660 }
1695 if (opt_sema) |sema| _ = try sema.resolveTypeLayout(ty);
1696 assert(struct_obj.haveLayout());
1697 return try struct_obj.backing_int_ty.bitSizeAdvanced(mod, opt_sema);
1661 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
16981662 },
16991663
17001664 .anon_struct_type => {
......@@ -1749,13 +1713,7 @@ pub const Type = struct {
17491713 pub fn layoutIsResolved(ty: Type, mod: *Module) bool {
17501714 const ip = &mod.intern_pool;
17511715 return switch (ip.indexToKey(ty.toIntern())) {
1752 .struct_type => |struct_type| {
1753 if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| {
1754 return struct_obj.haveLayout();
1755 } else {
1756 return true;
1757 }
1758 },
1716 .struct_type => |struct_type| struct_type.haveLayout(ip),
17591717 .union_type => |union_type| union_type.haveLayout(ip),
17601718 .array_type => |array_type| {
17611719 if ((array_type.len + @intFromBool(array_type.sentinel != .none)) == 0) return true;
......@@ -2020,10 +1978,7 @@ pub const Type = struct {
20201978 pub fn containerLayout(ty: Type, mod: *Module) std.builtin.Type.ContainerLayout {
20211979 const ip = &mod.intern_pool;
20221980 return switch (ip.indexToKey(ty.toIntern())) {
2023 .struct_type => |struct_type| {
2024 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return .Auto;
2025 return struct_obj.layout;
2026 },
1981 .struct_type => |struct_type| struct_type.layout,
20271982 .anon_struct_type => .Auto,
20281983 .union_type => |union_type| union_type.flagsPtr(ip).layout,
20291984 else => unreachable,
......@@ -2136,10 +2091,6 @@ pub const Type = struct {
21362091 return switch (ip.indexToKey(ty.toIntern())) {
21372092 .vector_type => |vector_type| vector_type.len,
21382093 .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 },
21432094 .anon_struct_type => |tuple| tuple.types.len,
21442095
21452096 else => unreachable,
......@@ -2214,6 +2165,7 @@ pub const Type = struct {
22142165
22152166 /// Asserts the type is an integer, enum, error set, or vector of one of them.
22162167 pub fn intInfo(starting_ty: Type, mod: *Module) InternPool.Key.IntType {
2168 const ip = &mod.intern_pool;
22172169 const target = mod.getTarget();
22182170 var ty = starting_ty;
22192171
......@@ -2233,13 +2185,9 @@ pub const Type = struct {
22332185 .c_ulong_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulong) },
22342186 .c_longlong_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.longlong) },
22352187 .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())) {
22372189 .int_type => |int_type| return int_type,
2238 .struct_type => |struct_type| {
2239 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
2240 assert(struct_obj.layout == .Packed);
2241 ty = struct_obj.backing_int_ty;
2242 },
2190 .struct_type => |t| ty = t.backingIntType(ip).*.toType(),
22432191 .enum_type => |enum_type| ty = enum_type.tag_ty.toType(),
22442192 .vector_type => |vector_type| ty = vector_type.child.toType(),
22452193
......@@ -2503,33 +2451,28 @@ pub const Type = struct {
25032451 .generic_poison => unreachable,
25042452 },
25052453 .struct_type => |struct_type| {
2506 if (mod.structPtrUnwrap(struct_type.index)) |s| {
2507 assert(s.haveFieldTypes());
2508 const field_vals = try mod.gpa.alloc(InternPool.Index, s.fields.count());
2509 defer mod.gpa.free(field_vals);
2510 for (field_vals, s.fields.values()) |*field_val, field| {
2511 if (field.is_comptime) {
2512 field_val.* = field.default_val;
2513 continue;
2514 }
2515 if (try field.ty.onePossibleValue(mod)) |field_opv| {
2516 field_val.* = try field_opv.intern(field.ty, mod);
2517 } else return null;
2454 assert(struct_type.haveFieldTypes(ip));
2455 if (struct_type.knownNonOpv(ip))
2456 return null;
2457 const field_vals = try mod.gpa.alloc(InternPool.Index, struct_type.field_types.len);
2458 defer mod.gpa.free(field_vals);
2459 for (field_vals, 0..) |*field_val, i_usize| {
2460 const i: u32 = @intCast(i_usize);
2461 if (struct_type.fieldIsComptime(ip, i)) {
2462 field_val.* = struct_type.field_inits.get(ip)[i];
2463 continue;
25182464 }
2519
2520 // In this case the struct has no runtime-known fields and
2521 // therefore has one possible value.
2522 return (try mod.intern(.{ .aggregate = .{
2523 .ty = ty.toIntern(),
2524 .storage = .{ .elems = field_vals },
2525 } })).toValue();
2465 const field_ty = struct_type.field_types.get(ip)[i].toType();
2466 if (try field_ty.onePossibleValue(mod)) |field_opv| {
2467 field_val.* = try field_opv.intern(field_ty, mod);
2468 } else return null;
25262469 }
25272470
2528 // In this case the struct has no fields at all and
2471 // In this case the struct has no runtime-known fields and
25292472 // therefore has one possible value.
25302473 return (try mod.intern(.{ .aggregate = .{
25312474 .ty = ty.toIntern(),
2532 .storage = .{ .elems = &.{} },
2475 .storage = .{ .elems = field_vals },
25332476 } })).toValue();
25342477 },
25352478
......@@ -2715,18 +2658,20 @@ pub const Type = struct {
27152658 => true,
27162659 },
27172660 .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
27182666 // A struct with no fields is not comptime-only.
2719 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false;
2720 switch (struct_obj.requires_comptime) {
2721 .wip, .unknown => {
2722 // Return false to avoid incorrect dependency loops.
2723 // This will be handled correctly once merged with
2724 // `Sema.typeRequiresComptime`.
2725 return false;
2726 },
2727 .no => return false,
2728 .yes => return true,
2729 }
2667 return switch (struct_type.flagsPtr(ip).requires_comptime) {
2668 // Return false to avoid incorrect dependency loops.
2669 // This will be handled correctly once merged with
2670 // `Sema.typeRequiresComptime`.
2671 .wip, .unknown => false,
2672 .no => false,
2673 .yes => true,
2674 };
27302675 },
27312676
27322677 .anon_struct_type => |tuple| {
......@@ -2982,37 +2927,19 @@ pub const Type = struct {
29822927 return enum_type.tagValueIndex(ip, int_tag);
29832928 }
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
29962930 pub fn structFieldName(ty: Type, field_index: usize, mod: *Module) InternPool.NullTerminatedString {
29972931 const ip = &mod.intern_pool;
29982932 return switch (ip.indexToKey(ty.toIntern())) {
2999 .struct_type => |struct_type| {
3000 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
3001 assert(struct_obj.haveFieldTypes());
3002 return struct_obj.fields.keys()[field_index];
3003 },
2933 .struct_type => |struct_type| struct_type.field_names.get(ip)[field_index],
30042934 .anon_struct_type => |anon_struct| anon_struct.names.get(ip)[field_index],
30052935 else => unreachable,
30062936 };
30072937 }
30082938
30092939 pub fn structFieldCount(ty: Type, mod: *Module) usize {
3010 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
3011 .struct_type => |struct_type| {
3012 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return 0;
3013 assert(struct_obj.haveFieldTypes());
3014 return struct_obj.fields.count();
3015 },
2940 const ip = &mod.intern_pool;
2941 return switch (ip.indexToKey(ty.toIntern())) {
2942 .struct_type => |struct_type| struct_type.field_types.len,
30162943 .anon_struct_type => |anon_struct| anon_struct.types.len,
30172944 else => unreachable,
30182945 };
......@@ -3022,11 +2949,7 @@ pub const Type = struct {
30222949 pub fn structFieldType(ty: Type, index: usize, mod: *Module) Type {
30232950 const ip = &mod.intern_pool;
30242951 return switch (ip.indexToKey(ty.toIntern())) {
3025 .struct_type => |struct_type| {
3026 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
3027 assert(struct_obj.haveFieldTypes());
3028 return struct_obj.fields.values()[index].ty;
3029 },
2952 .struct_type => |struct_type| struct_type.field_types.get(ip)[index].toType(),
30302953 .union_type => |union_type| {
30312954 const union_obj = ip.loadUnionType(union_type);
30322955 return union_obj.field_types.get(ip)[index].toType();
......@@ -3036,13 +2959,14 @@ pub const Type = struct {
30362959 };
30372960 }
30382961
3039 pub fn structFieldAlign(ty: Type, index: usize, mod: *Module) u32 {
2962 pub fn structFieldAlign(ty: Type, index: usize, mod: *Module) Alignment {
30402963 const ip = &mod.intern_pool;
30412964 switch (ip.indexToKey(ty.toIntern())) {
30422965 .struct_type => |struct_type| {
3043 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
3044 assert(struct_obj.layout != .Packed);
3045 return struct_obj.fields.values()[index].alignment(mod, struct_obj.layout);
2966 assert(struct_type.layout != .Packed);
2967 const explicit_align = struct_type.field_aligns.get(ip)[index];
2968 const field_ty = struct_type.field_types.get(ip)[index].toType();
2969 return mod.structFieldAlignment(explicit_align, field_ty, struct_type.layout);
30462970 },
30472971 .anon_struct_type => |anon_struct| {
30482972 return anon_struct.types.get(ip)[index].toType().abiAlignment(mod);
......@@ -3059,8 +2983,7 @@ pub const Type = struct {
30592983 const ip = &mod.intern_pool;
30602984 switch (ip.indexToKey(ty.toIntern())) {
30612985 .struct_type => |struct_type| {
3062 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
3063 const val = struct_obj.fields.values()[index].default_val;
2986 const val = struct_type.field_inits.get(ip)[index];
30642987 // TODO: avoid using `unreachable` to indicate this.
30652988 if (val == .none) return Value.@"unreachable";
30662989 return val.toValue();
......@@ -3079,12 +3002,10 @@ pub const Type = struct {
30793002 const ip = &mod.intern_pool;
30803003 switch (ip.indexToKey(ty.toIntern())) {
30813004 .struct_type => |struct_type| {
3082 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
3083 const field = struct_obj.fields.values()[index];
3084 if (field.is_comptime) {
3085 return field.default_val.toValue();
3005 if (struct_type.comptime_bits.getBit(ip, index)) {
3006 return struct_type.field_inits.get(ip)[index].toValue();
30863007 } else {
3087 return field.ty.onePossibleValue(mod);
3008 return struct_type.field_types.get(ip)[index].toType().onePossibleValue(mod);
30883009 }
30893010 },
30903011 .anon_struct_type => |tuple| {
......@@ -3102,30 +3023,25 @@ pub const Type = struct {
31023023 pub fn structFieldIsComptime(ty: Type, index: usize, mod: *Module) bool {
31033024 const ip = &mod.intern_pool;
31043025 return switch (ip.indexToKey(ty.toIntern())) {
3105 .struct_type => |struct_type| {
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 },
3026 .struct_type => |struct_type| struct_type.fieldIsComptime(ip, index),
31113027 .anon_struct_type => |anon_struct| anon_struct.values.get(ip)[index] != .none,
31123028 else => unreachable,
31133029 };
31143030 }
31153031
31163032 pub fn packedStructFieldByteOffset(ty: Type, field_index: usize, mod: *Module) u32 {
3117 const struct_type = mod.intern_pool.indexToKey(ty.toIntern()).struct_type;
3118 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
3119 assert(struct_obj.layout == .Packed);
3033 const ip = &mod.intern_pool;
3034 const struct_type = ip.indexToKey(ty.toIntern()).struct_type;
3035 assert(struct_type.layout == .Packed);
31203036 comptime assert(Type.packed_struct_layout_version == 2);
31213037
31223038 var bit_offset: u16 = undefined;
31233039 var elem_size_bits: u16 = undefined;
31243040 var running_bits: u16 = 0;
3125 for (struct_obj.fields.values(), 0..) |f, i| {
3126 if (!f.ty.hasRuntimeBits(mod)) continue;
3041 for (struct_type.field_types.get(ip), 0..) |field_ty, i| {
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));
31293045 if (i == field_index) {
31303046 bit_offset = running_bits;
31313047 elem_size_bits = field_bits;
......@@ -3141,68 +3057,19 @@ pub const Type = struct {
31413057 offset: u64,
31423058 };
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
31863060 /// Supports structs and unions.
31873061 pub fn structFieldOffset(ty: Type, index: usize, mod: *Module) u64 {
31883062 const ip = &mod.intern_pool;
31893063 switch (ip.indexToKey(ty.toIntern())) {
31903064 .struct_type => |struct_type| {
3191 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
3192 assert(struct_obj.haveLayout());
3193 assert(struct_obj.layout != .Packed);
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));
3065 assert(struct_type.haveLayout(ip));
3066 assert(struct_type.layout != .Packed);
3067 return struct_type.offsets.get(ip)[index];
32013068 },
32023069
32033070 .anon_struct_type => |tuple| {
32043071 var offset: u64 = 0;
3205 var big_align: u32 = 0;
3072 var big_align: Alignment = .none;
32063073
32073074 for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, field_val, i| {
32083075 if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) {
......@@ -3212,12 +3079,12 @@ pub const Type = struct {
32123079 }
32133080
32143081 const field_align = field_ty.toType().abiAlignment(mod);
3215 big_align = @max(big_align, field_align);
3216 offset = std.mem.alignForward(u64, offset, field_align);
3082 big_align = big_align.max(field_align);
3083 offset = field_align.forward(offset);
32173084 if (i == index) return offset;
32183085 offset += field_ty.toType().abiSize(mod);
32193086 }
3220 offset = std.mem.alignForward(u64, offset, @max(big_align, 1));
3087 offset = big_align.max(.@"1").forward(offset);
32213088 return offset;
32223089 },
32233090
......@@ -3226,9 +3093,9 @@ pub const Type = struct {
32263093 return 0;
32273094 const union_obj = ip.loadUnionType(union_type);
32283095 const layout = mod.getUnionLayout(union_obj);
3229 if (layout.tag_align >= layout.payload_align) {
3096 if (layout.tag_align.compare(.gte, layout.payload_align)) {
32303097 // {Tag, Payload}
3231 return std.mem.alignForward(u64, layout.tag_size, layout.payload_align);
3098 return layout.payload_align.forward(layout.tag_size);
32323099 } else {
32333100 // {Payload, Tag}
32343101 return 0;
......@@ -3246,8 +3113,7 @@ pub const Type = struct {
32463113 pub fn declSrcLocOrNull(ty: Type, mod: *Module) ?Module.SrcLoc {
32473114 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
32483115 .struct_type => |struct_type| {
3249 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
3250 return struct_obj.srcLoc(mod);
3116 return mod.declPtr(struct_type.decl.unwrap() orelse return null).srcLoc(mod);
32513117 },
32523118 .union_type => |union_type| {
32533119 return mod.declPtr(union_type.decl).srcLoc(mod);
......@@ -3264,10 +3130,7 @@ pub const Type = struct {
32643130
32653131 pub fn getOwnerDeclOrNull(ty: Type, mod: *Module) ?Module.Decl.Index {
32663132 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
3267 .struct_type => |struct_type| {
3268 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return null;
3269 return struct_obj.owner_decl;
3270 },
3133 .struct_type => |struct_type| struct_type.decl.unwrap(),
32713134 .union_type => |union_type| union_type.decl,
32723135 .opaque_type => |opaque_type| opaque_type.decl,
32733136 .enum_type => |enum_type| enum_type.decl,
......@@ -3280,10 +3143,12 @@ pub const Type = struct {
32803143 }
32813144
32823145 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())) {
32843148 .struct_type => |struct_type| {
3285 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false;
3286 return struct_obj.is_tuple;
3149 if (struct_type.layout == .Packed) return false;
3150 if (struct_type.decl == .none) return false;
3151 return struct_type.flagsPtr(ip).is_tuple;
32873152 },
32883153 .anon_struct_type => |anon_struct| anon_struct.names.len == 0,
32893154 else => false,
......@@ -3299,10 +3164,12 @@ pub const Type = struct {
32993164 }
33003165
33013166 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())) {
33033169 .struct_type => |struct_type| {
3304 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false;
3305 return struct_obj.is_tuple;
3170 if (struct_type.layout == .Packed) return false;
3171 if (struct_type.decl == .none) return false;
3172 return struct_type.flagsPtr(ip).is_tuple;
33063173 },
33073174 .anon_struct_type => true,
33083175 else => false,
......@@ -3391,3 +3258,7 @@ pub const Type = struct {
33913258 /// to packed struct layout to find out all the places in the codebase you need to edit!
33923259 pub const packed_struct_layout_version = 2;
33933260};
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 {
462462 if (opt_sema) |sema| try sema.resolveTypeLayout(ty.toType());
463463 const x = switch (int.storage) {
464464 else => unreachable,
465 .lazy_align => ty.toType().abiAlignment(mod),
465 .lazy_align => ty.toType().abiAlignment(mod).toByteUnits(0),
466466 .lazy_size => ty.toType().abiSize(mod),
467467 };
468468 return BigIntMutable.init(&space.limbs, x).toConst();
......@@ -523,9 +523,9 @@ pub const Value = struct {
523523 .u64 => |x| x,
524524 .i64 => |x| std.math.cast(u64, x),
525525 .lazy_align => |ty| if (opt_sema) |sema|
526 (try ty.toType().abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar
526 (try ty.toType().abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar.toByteUnits(0)
527527 else
528 ty.toType().abiAlignment(mod),
528 ty.toType().abiAlignment(mod).toByteUnits(0),
529529 .lazy_size => |ty| if (opt_sema) |sema|
530530 (try ty.toType().abiSizeAdvanced(mod, .{ .sema = sema })).scalar
531531 else
......@@ -569,9 +569,9 @@ pub const Value = struct {
569569 .int => |int| switch (int.storage) {
570570 .big_int => |big_int| big_int.to(i64) catch unreachable,
571571 .i64 => |x| x,
572 .u64 => |x| @as(i64, @intCast(x)),
573 .lazy_align => |ty| @as(i64, @intCast(ty.toType().abiAlignment(mod))),
574 .lazy_size => |ty| @as(i64, @intCast(ty.toType().abiSize(mod))),
572 .u64 => |x| @intCast(x),
573 .lazy_align => |ty| @intCast(ty.toType().abiAlignment(mod).toByteUnits(0)),
574 .lazy_size => |ty| @intCast(ty.toType().abiSize(mod)),
575575 },
576576 else => unreachable,
577577 },
......@@ -612,10 +612,11 @@ pub const Value = struct {
612612 const target = mod.getTarget();
613613 const endian = target.cpu.arch.endian();
614614 if (val.isUndef(mod)) {
615 const size = @as(usize, @intCast(ty.abiSize(mod)));
615 const size: usize = @intCast(ty.abiSize(mod));
616616 @memset(buffer[0..size], 0xaa);
617617 return;
618618 }
619 const ip = &mod.intern_pool;
619620 switch (ty.zigTypeTag(mod)) {
620621 .Void => {},
621622 .Bool => {
......@@ -656,40 +657,44 @@ pub const Value = struct {
656657 const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8;
657658 return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0);
658659 },
659 .Struct => switch (ty.containerLayout(mod)) {
660 .Auto => return error.IllDefinedMemoryLayout,
661 .Extern => for (ty.structFields(mod).values(), 0..) |field, i| {
662 const off = @as(usize, @intCast(ty.structFieldOffset(i, mod)));
663 const field_val = switch (val.ip_index) {
664 .none => switch (val.tag()) {
665 .bytes => {
666 buffer[off] = val.castTag(.bytes).?.data[i];
667 continue;
668 },
669 .aggregate => val.castTag(.aggregate).?.data[i],
670 .repeated => val.castTag(.repeated).?.data,
671 else => unreachable,
672 },
673 else => switch (mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage) {
674 .bytes => |bytes| {
675 buffer[off] = bytes[i];
676 continue;
660 .Struct => {
661 const struct_type = mod.typeToStruct(ty) orelse return error.IllDefinedMemoryLayout;
662 switch (struct_type.layout) {
663 .Auto => return error.IllDefinedMemoryLayout,
664 .Extern => for (0..struct_type.field_types.len) |i| {
665 const off: usize = @intCast(ty.structFieldOffset(i, mod));
666 const field_val = switch (val.ip_index) {
667 .none => switch (val.tag()) {
668 .bytes => {
669 buffer[off] = val.castTag(.bytes).?.data[i];
670 continue;
671 },
672 .aggregate => val.castTag(.aggregate).?.data[i],
673 .repeated => val.castTag(.repeated).?.data,
674 else => unreachable,
677675 },
678 .elems => |elems| elems[i],
679 .repeated_elem => |elem| elem,
680 }.toValue(),
681 };
682 try writeToMemory(field_val, field.ty, mod, buffer[off..]);
683 },
684 .Packed => {
685 const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8;
686 return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0);
687 },
676 else => switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
677 .bytes => |bytes| {
678 buffer[off] = bytes[i];
679 continue;
680 },
681 .elems => |elems| elems[i],
682 .repeated_elem => |elem| elem,
683 }.toValue(),
684 };
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 }
688693 },
689694 .ErrorSet => {
690695 // TODO revisit this when we have the concept of the error tag type
691696 const Int = u16;
692 const name = switch (mod.intern_pool.indexToKey(val.toIntern())) {
697 const name = switch (ip.indexToKey(val.toIntern())) {
693698 .err => |err| err.name,
694699 .error_union => |error_union| error_union.val.err_name,
695700 else => unreachable,
......@@ -790,24 +795,24 @@ pub const Value = struct {
790795 bits += elem_bit_size;
791796 }
792797 },
793 .Struct => switch (ty.containerLayout(mod)) {
794 .Auto => unreachable, // Sema is supposed to have emitted a compile error already
795 .Extern => unreachable, // Handled in non-packed writeToMemory
796 .Packed => {
797 var bits: u16 = 0;
798 const fields = ty.structFields(mod).values();
799 const storage = ip.indexToKey(val.toIntern()).aggregate.storage;
800 for (fields, 0..) |field, i| {
801 const field_bits = @as(u16, @intCast(field.ty.bitSize(mod)));
802 const field_val = switch (storage) {
803 .bytes => unreachable,
804 .elems => |elems| elems[i],
805 .repeated_elem => |elem| elem,
806 };
807 try field_val.toValue().writeToPackedMemory(field.ty, mod, buffer, bit_offset + bits);
808 bits += field_bits;
809 }
810 },
798 .Struct => {
799 const struct_type = ip.indexToKey(ty.toIntern()).struct_type;
800 // Sema is supposed to have emitted a compile error already in the case of Auto,
801 // and Extern is handled in non-packed writeToMemory.
802 assert(struct_type.layout == .Packed);
803 var bits: u16 = 0;
804 const storage = ip.indexToKey(val.toIntern()).aggregate.storage;
805 for (0..struct_type.field_types.len) |i| {
806 const field_ty = struct_type.field_types.get(ip)[i].toType();
807 const field_bits: u16 = @intCast(field_ty.bitSize(mod));
808 const field_val = switch (storage) {
809 .bytes => unreachable,
810 .elems => |elems| elems[i],
811 .repeated_elem => |elem| elem,
812 };
813 try field_val.toValue().writeToPackedMemory(field_ty, mod, buffer, bit_offset + bits);
814 bits += field_bits;
815 }
811816 },
812817 .Union => {
813818 const union_obj = mod.typeToUnion(ty).?;
......@@ -852,6 +857,7 @@ pub const Value = struct {
852857 buffer: []const u8,
853858 arena: Allocator,
854859 ) Allocator.Error!Value {
860 const ip = &mod.intern_pool;
855861 const target = mod.getTarget();
856862 const endian = target.cpu.arch.endian();
857863 switch (ty.zigTypeTag(mod)) {
......@@ -926,25 +932,29 @@ pub const Value = struct {
926932 const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8;
927933 return readFromPackedMemory(ty, mod, buffer[0..byte_count], 0, arena);
928934 },
929 .Struct => switch (ty.containerLayout(mod)) {
930 .Auto => unreachable, // Sema is supposed to have emitted a compile error already
931 .Extern => {
932 const fields = ty.structFields(mod).values();
933 const field_vals = try arena.alloc(InternPool.Index, fields.len);
934 for (field_vals, fields, 0..) |*field_val, field, i| {
935 const off = @as(usize, @intCast(ty.structFieldOffset(i, mod)));
936 const sz = @as(usize, @intCast(field.ty.abiSize(mod)));
937 field_val.* = try (try readFromMemory(field.ty, mod, buffer[off..(off + sz)], arena)).intern(field.ty, mod);
938 }
939 return (try mod.intern(.{ .aggregate = .{
940 .ty = ty.toIntern(),
941 .storage = .{ .elems = field_vals },
942 } })).toValue();
943 },
944 .Packed => {
945 const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8;
946 return readFromPackedMemory(ty, mod, buffer[0..byte_count], 0, arena);
947 },
935 .Struct => {
936 const struct_type = mod.typeToStruct(ty).?;
937 switch (struct_type.layout) {
938 .Auto => unreachable, // Sema is supposed to have emitted a compile error already
939 .Extern => {
940 const field_types = struct_type.field_types;
941 const field_vals = try arena.alloc(InternPool.Index, field_types.len);
942 for (field_vals, 0..) |*field_val, i| {
943 const field_ty = field_types.get(ip)[i].toType();
944 const off: usize = @intCast(ty.structFieldOffset(i, mod));
945 const sz: usize = @intCast(field_ty.abiSize(mod));
946 field_val.* = try (try readFromMemory(field_ty, mod, buffer[off..(off + sz)], arena)).intern(field_ty, mod);
947 }
948 return (try mod.intern(.{ .aggregate = .{
949 .ty = ty.toIntern(),
950 .storage = .{ .elems = field_vals },
951 } })).toValue();
952 },
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 }
948958 },
949959 .ErrorSet => {
950960 // TODO revisit this when we have the concept of the error tag type
......@@ -992,6 +1002,7 @@ pub const Value = struct {
9921002 bit_offset: usize,
9931003 arena: Allocator,
9941004 ) Allocator.Error!Value {
1005 const ip = &mod.intern_pool;
9951006 const target = mod.getTarget();
9961007 const endian = target.cpu.arch.endian();
9971008 switch (ty.zigTypeTag(mod)) {
......@@ -1070,23 +1081,22 @@ pub const Value = struct {
10701081 .storage = .{ .elems = elems },
10711082 } })).toValue();
10721083 },
1073 .Struct => switch (ty.containerLayout(mod)) {
1074 .Auto => unreachable, // Sema is supposed to have emitted a compile error already
1075 .Extern => unreachable, // Handled by non-packed readFromMemory
1076 .Packed => {
1077 var bits: u16 = 0;
1078 const fields = ty.structFields(mod).values();
1079 const field_vals = try arena.alloc(InternPool.Index, fields.len);
1080 for (fields, 0..) |field, i| {
1081 const field_bits = @as(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);
1083 bits += field_bits;
1084 }
1085 return (try mod.intern(.{ .aggregate = .{
1086 .ty = ty.toIntern(),
1087 .storage = .{ .elems = field_vals },
1088 } })).toValue();
1089 },
1084 .Struct => {
1085 // Sema is supposed to have emitted a compile error already for Auto layout structs,
1086 // and Extern is handled by non-packed readFromMemory.
1087 const struct_type = mod.typeToPackedStruct(ty).?;
1088 var bits: u16 = 0;
1089 const field_vals = try arena.alloc(InternPool.Index, struct_type.field_types.len);
1090 for (field_vals, 0..) |*field_val, i| {
1091 const field_ty = struct_type.field_types.get(ip)[i].toType();
1092 const field_bits: u16 = @intCast(field_ty.bitSize(mod));
1093 field_val.* = try (try readFromPackedMemory(field_ty, mod, buffer, bit_offset + bits, arena)).intern(field_ty, mod);
1094 bits += field_bits;
1095 }
1096 return (try mod.intern(.{ .aggregate = .{
1097 .ty = ty.toIntern(),
1098 .storage = .{ .elems = field_vals },
1099 } })).toValue();
10901100 },
10911101 .Pointer => {
10921102 assert(!ty.isSlice(mod)); // No well defined layout.
......@@ -1105,18 +1115,18 @@ pub const Value = struct {
11051115 pub fn toFloat(val: Value, comptime T: type, mod: *Module) T {
11061116 return switch (mod.intern_pool.indexToKey(val.toIntern())) {
11071117 .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)),
11091119 inline .u64, .i64 => |x| {
11101120 if (T == f80) {
11111121 @panic("TODO we can't lower this properly on non-x86 llvm backend yet");
11121122 }
1113 return @as(T, @floatFromInt(x));
1123 return @floatFromInt(x);
11141124 },
1115 .lazy_align => |ty| @as(T, @floatFromInt(ty.toType().abiAlignment(mod))),
1116 .lazy_size => |ty| @as(T, @floatFromInt(ty.toType().abiSize(mod))),
1125 .lazy_align => |ty| @floatFromInt(ty.toType().abiAlignment(mod).toByteUnits(0)),
1126 .lazy_size => |ty| @floatFromInt(ty.toType().abiSize(mod)),
11171127 },
11181128 .float => |float| switch (float.storage) {
1119 inline else => |x| @as(T, @floatCast(x)),
1129 inline else => |x| @floatCast(x),
11201130 },
11211131 else => unreachable,
11221132 };
......@@ -1875,9 +1885,9 @@ pub const Value = struct {
18751885 },
18761886 inline .u64, .i64 => |x| floatFromIntInner(x, float_ty, mod),
18771887 .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);
18791889 } else {
1880 return floatFromIntInner(ty.toType().abiAlignment(mod), float_ty, mod);
1890 return floatFromIntInner(ty.toType().abiAlignment(mod).toByteUnits(0), float_ty, mod);
18811891 },
18821892 .lazy_size => |ty| if (opt_sema) |sema| {
18831893 return floatFromIntInner((try ty.toType().abiSizeAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod);
......@@ -1892,11 +1902,11 @@ pub const Value = struct {
18921902 fn floatFromIntInner(x: anytype, dest_ty: Type, mod: *Module) !Value {
18931903 const target = mod.getTarget();
18941904 const storage: InternPool.Key.Float.Storage = switch (dest_ty.floatBits(target)) {
1895 16 => .{ .f16 = @as(f16, @floatFromInt(x)) },
1896 32 => .{ .f32 = @as(f32, @floatFromInt(x)) },
1897 64 => .{ .f64 = @as(f64, @floatFromInt(x)) },
1898 80 => .{ .f80 = @as(f80, @floatFromInt(x)) },
1899 128 => .{ .f128 = @as(f128, @floatFromInt(x)) },
1905 16 => .{ .f16 = @floatFromInt(x) },
1906 32 => .{ .f32 = @floatFromInt(x) },
1907 64 => .{ .f64 = @floatFromInt(x) },
1908 80 => .{ .f80 = @floatFromInt(x) },
1909 128 => .{ .f128 = @floatFromInt(x) },
19001910 else => unreachable,
19011911 };
19021912 return (try mod.intern(.{ .float = .{