authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-22 09:38:41-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-09-22 09:38:41-07:00
loga8d2ed806558cc1472f3a532169a4994abe17833
treed41c8344573283da5e5be48e06d4c73662e25ddc
parent0345d7866347c9066b0646f9e46be9a068dcfaa3
parent221295b7db97c78ffce39e64dd6cafd8ad0b3f9a
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #17172 from ziglang/ip-structs

compiler: move struct types into InternPool proper

41 files changed, 3608 insertions(+), 2878 deletions(-)

src/AstGen.zig+24-7
......@@ -4758,6 +4758,9 @@ fn structDeclInner(
47584758 .known_non_opv = false,
47594759 .known_comptime_only = false,
47604760 .is_tuple = false,
4761 .any_comptime_fields = false,
4762 .any_default_inits = false,
4763 .any_aligned_fields = false,
47614764 });
47624765 return indexToRef(decl_inst);
47634766 }
......@@ -4881,6 +4884,9 @@ fn structDeclInner(
48814884
48824885 var known_non_opv = false;
48834886 var known_comptime_only = false;
4887 var any_comptime_fields = false;
4888 var any_aligned_fields = false;
4889 var any_default_inits = false;
48844890 for (container_decl.ast.members) |member_node| {
48854891 var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {
48864892 .decl => continue,
......@@ -4910,13 +4916,13 @@ fn structDeclInner(
49104916 const have_value = member.ast.value_expr != 0;
49114917 const is_comptime = member.comptime_token != null;
49124918
4913 if (is_comptime and layout == .Packed) {
4914 return astgen.failTok(member.comptime_token.?, "packed struct fields cannot be marked comptime", .{});
4915 } else if (is_comptime and layout == .Extern) {
4916 return astgen.failTok(member.comptime_token.?, "extern struct fields cannot be marked comptime", .{});
4917 }
4918
4919 if (!is_comptime) {
4919 if (is_comptime) {
4920 switch (layout) {
4921 .Packed => return astgen.failTok(member.comptime_token.?, "packed struct fields cannot be marked comptime", .{}),
4922 .Extern => return astgen.failTok(member.comptime_token.?, "extern struct fields cannot be marked comptime", .{}),
4923 .Auto => any_comptime_fields = true,
4924 }
4925 } else {
49204926 known_non_opv = known_non_opv or
49214927 nodeImpliesMoreThanOnePossibleValue(tree, member.ast.type_expr);
49224928 known_comptime_only = known_comptime_only or
......@@ -4942,6 +4948,7 @@ fn structDeclInner(
49424948 if (layout == .Packed) {
49434949 try astgen.appendErrorNode(member.ast.align_expr, "unable to override alignment of packed struct fields", .{});
49444950 }
4951 any_aligned_fields = true;
49454952 const align_ref = try expr(&block_scope, &namespace.base, coerced_align_ri, member.ast.align_expr);
49464953 if (!block_scope.endsWithNoReturn()) {
49474954 _ = try block_scope.addBreak(.break_inline, decl_inst, align_ref);
......@@ -4955,6 +4962,7 @@ fn structDeclInner(
49554962 }
49564963
49574964 if (have_value) {
4965 any_default_inits = true;
49584966 const ri: ResultInfo = .{ .rl = if (field_type == .none) .none else .{ .coerced_ty = field_type } };
49594967
49604968 const default_inst = try expr(&block_scope, &namespace.base, ri, member.ast.value_expr);
......@@ -4982,6 +4990,9 @@ fn structDeclInner(
49824990 .known_non_opv = known_non_opv,
49834991 .known_comptime_only = known_comptime_only,
49844992 .is_tuple = is_tuple,
4993 .any_comptime_fields = any_comptime_fields,
4994 .any_default_inits = any_default_inits,
4995 .any_aligned_fields = any_aligned_fields,
49854996 });
49864997
49874998 wip_members.finishBits(bits_per_field);
......@@ -12080,6 +12091,9 @@ const GenZir = struct {
1208012091 known_non_opv: bool,
1208112092 known_comptime_only: bool,
1208212093 is_tuple: bool,
12094 any_comptime_fields: bool,
12095 any_default_inits: bool,
12096 any_aligned_fields: bool,
1208312097 }) !void {
1208412098 const astgen = gz.astgen;
1208512099 const gpa = astgen.gpa;
......@@ -12117,6 +12131,9 @@ const GenZir = struct {
1211712131 .is_tuple = args.is_tuple,
1211812132 .name_strategy = gz.anon_name_strategy,
1211912133 .layout = args.layout,
12134 .any_comptime_fields = args.any_comptime_fields,
12135 .any_default_inits = args.any_default_inits,
12136 .any_aligned_fields = args.any_aligned_fields,
1212012137 }),
1212112138 .operand = payload_index,
1212212139 } },
src/InternPool.zig+911-195
......@@ -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,291 @@ 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: OptionalMapIndex,
382
383 pub const ComptimeBits = struct {
384 start: u32,
385 /// This is the number of u32 elements, not the number of struct fields.
386 len: u32,
387
388 pub fn get(this: @This(), ip: *const InternPool) []u32 {
389 return ip.extra.items[this.start..][0..this.len];
390 }
391
392 pub fn getBit(this: @This(), ip: *const InternPool, i: usize) bool {
393 if (this.len == 0) return false;
394 return @as(u1, @truncate(this.get(ip)[i / 32] >> @intCast(i % 32))) != 0;
395 }
396
397 pub fn setBit(this: @This(), ip: *const InternPool, i: usize) void {
398 this.get(ip)[i / 32] |= @as(u32, 1) << @intCast(i % 32);
399 }
400
401 pub fn clearBit(this: @This(), ip: *const InternPool, i: usize) void {
402 this.get(ip)[i / 32] &= ~(@as(u32, 1) << @intCast(i % 32));
403 }
404 };
405
406 pub const Offsets = struct {
407 start: u32,
408 len: u32,
409
410 pub fn get(this: @This(), ip: *const InternPool) []u32 {
411 return @ptrCast(ip.extra.items[this.start..][0..this.len]);
412 }
413 };
414
415 pub const RuntimeOrder = enum(u32) {
416 /// Placeholder until layout is resolved.
417 unresolved = std.math.maxInt(u32) - 0,
418 /// Field not present at runtime
419 omitted = std.math.maxInt(u32) - 1,
420 _,
421
422 pub const Slice = struct {
423 start: u32,
424 len: u32,
425
426 pub fn get(slice: Slice, ip: *const InternPool) []RuntimeOrder {
427 return @ptrCast(ip.extra.items[slice.start..][0..slice.len]);
428 }
429 };
430
431 pub fn toInt(i: @This()) ?u32 {
432 return switch (i) {
433 .omitted => null,
434 .unresolved => unreachable,
435 else => @intFromEnum(i),
436 };
437 }
438 };
439
440 /// Look up field index based on field name.
441 pub fn nameIndex(self: StructType, ip: *const InternPool, name: NullTerminatedString) ?u32 {
442 const names_map = self.names_map.unwrap() orelse {
443 const i = name.toUnsigned(ip) orelse return null;
444 if (i >= self.field_types.len) return null;
445 return i;
446 };
447 const map = &ip.maps.items[@intFromEnum(names_map)];
448 const adapter: NullTerminatedString.Adapter = .{ .strings = self.field_names.get(ip) };
449 const field_index = map.getIndexAdapted(name, adapter) orelse return null;
450 return @intCast(field_index);
451 }
452
453 /// Returns the already-existing field with the same name, if any.
454 pub fn addFieldName(
455 self: @This(),
456 ip: *InternPool,
457 name: NullTerminatedString,
458 ) ?u32 {
459 return ip.addFieldName(self.names_map.unwrap().?, self.field_names.start, name);
460 }
461
462 pub fn fieldAlign(s: @This(), ip: *const InternPool, i: usize) Alignment {
463 if (s.field_aligns.len == 0) return .none;
464 return s.field_aligns.get(ip)[i];
465 }
466
467 pub fn fieldInit(s: @This(), ip: *const InternPool, i: usize) Index {
468 if (s.field_inits.len == 0) return .none;
469 return s.field_inits.get(ip)[i];
470 }
471
472 /// Returns `none` in the case the struct is a tuple.
473 pub fn fieldName(s: @This(), ip: *const InternPool, i: usize) OptionalNullTerminatedString {
474 if (s.field_names.len == 0) return .none;
475 return s.field_names.get(ip)[i].toOptional();
476 }
477
478 pub fn fieldIsComptime(s: @This(), ip: *const InternPool, i: usize) bool {
479 return s.comptime_bits.getBit(ip, i);
480 }
481
482 pub fn setFieldComptime(s: @This(), ip: *InternPool, i: usize) void {
483 s.comptime_bits.setBit(ip, i);
484 }
485
486 /// Reads the non-opv flag calculated during AstGen. Used to short-circuit more
487 /// complicated logic.
488 pub fn knownNonOpv(s: @This(), ip: *InternPool) bool {
489 return switch (s.layout) {
490 .Packed => false,
491 .Auto, .Extern => s.flagsPtr(ip).known_non_opv,
492 };
493 }
494
495 /// The returned pointer expires with any addition to the `InternPool`.
496 /// Asserts the struct is not packed.
497 pub fn flagsPtr(self: @This(), ip: *InternPool) *Tag.TypeStruct.Flags {
498 assert(self.layout != .Packed);
499 const flags_field_index = std.meta.fieldIndex(Tag.TypeStruct, "flags").?;
500 return @ptrCast(&ip.extra.items[self.extra_index + flags_field_index]);
501 }
502
503 pub fn assumeRuntimeBitsIfFieldTypesWip(s: @This(), ip: *InternPool) bool {
504 if (s.layout == .Packed) return false;
505 const flags_ptr = s.flagsPtr(ip);
506 if (flags_ptr.field_types_wip) {
507 flags_ptr.assumed_runtime_bits = true;
508 return true;
509 }
510 return false;
511 }
512
513 pub fn setTypesWip(s: @This(), ip: *InternPool) bool {
514 if (s.layout == .Packed) return false;
515 const flags_ptr = s.flagsPtr(ip);
516 if (flags_ptr.field_types_wip) return true;
517 flags_ptr.field_types_wip = true;
518 return false;
519 }
520
521 pub fn clearTypesWip(s: @This(), ip: *InternPool) void {
522 if (s.layout == .Packed) return;
523 s.flagsPtr(ip).field_types_wip = false;
524 }
525
526 pub fn setLayoutWip(s: @This(), ip: *InternPool) bool {
527 if (s.layout == .Packed) return false;
528 const flags_ptr = s.flagsPtr(ip);
529 if (flags_ptr.layout_wip) return true;
530 flags_ptr.layout_wip = true;
531 return false;
532 }
533
534 pub fn clearLayoutWip(s: @This(), ip: *InternPool) void {
535 if (s.layout == .Packed) return;
536 s.flagsPtr(ip).layout_wip = false;
537 }
538
539 pub fn setAlignmentWip(s: @This(), ip: *InternPool) bool {
540 if (s.layout == .Packed) return false;
541 const flags_ptr = s.flagsPtr(ip);
542 if (flags_ptr.alignment_wip) return true;
543 flags_ptr.alignment_wip = true;
544 return false;
545 }
546
547 pub fn clearAlignmentWip(s: @This(), ip: *InternPool) void {
548 if (s.layout == .Packed) return;
549 s.flagsPtr(ip).alignment_wip = false;
550 }
551
552 pub fn setFullyResolved(s: @This(), ip: *InternPool) bool {
553 if (s.layout == .Packed) return true;
554 const flags_ptr = s.flagsPtr(ip);
555 if (flags_ptr.fully_resolved) return true;
556 flags_ptr.fully_resolved = true;
557 return false;
558 }
559
560 pub fn clearFullyResolved(s: @This(), ip: *InternPool) void {
561 s.flagsPtr(ip).fully_resolved = false;
562 }
563
564 /// The returned pointer expires with any addition to the `InternPool`.
565 /// Asserts the struct is not packed.
566 pub fn size(self: @This(), ip: *InternPool) *u32 {
567 assert(self.layout != .Packed);
568 const size_field_index = std.meta.fieldIndex(Tag.TypeStruct, "size").?;
569 return @ptrCast(&ip.extra.items[self.extra_index + size_field_index]);
570 }
571
572 /// The backing integer type of the packed struct. Whether zig chooses
573 /// this type or the user specifies it, it is stored here. This will be
574 /// set to `none` until the layout is resolved.
575 /// Asserts the struct is packed.
576 pub fn backingIntType(s: @This(), ip: *const InternPool) *Index {
577 assert(s.layout == .Packed);
578 const field_index = std.meta.fieldIndex(Tag.TypeStructPacked, "backing_int_ty").?;
579 return @ptrCast(&ip.extra.items[s.extra_index + field_index]);
580 }
581
582 /// Asserts the struct is not packed.
583 pub fn setZirIndex(s: @This(), ip: *InternPool, new_zir_index: Zir.Inst.Index) void {
584 assert(s.layout != .Packed);
585 const field_index = std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?;
586 ip.extra.items[s.extra_index + field_index] = new_zir_index;
587 }
588
589 pub fn haveFieldTypes(s: @This(), ip: *const InternPool) bool {
590 const types = s.field_types.get(ip);
591 return types.len == 0 or types[0] != .none;
592 }
593
594 pub fn haveLayout(s: @This(), ip: *InternPool) bool {
595 return switch (s.layout) {
596 .Packed => s.backingIntType(ip).* != .none,
597 .Auto, .Extern => s.flagsPtr(ip).layout_resolved,
598 };
599 }
600
601 pub fn isTuple(s: @This(), ip: *InternPool) bool {
602 return s.layout != .Packed and s.flagsPtr(ip).is_tuple;
603 }
604
605 pub fn hasReorderedFields(s: @This()) bool {
606 return s.layout == .Auto;
607 }
608
609 pub const RuntimeOrderIterator = struct {
610 ip: *InternPool,
611 field_index: u32,
612 struct_type: InternPool.Key.StructType,
613
614 pub fn next(it: *@This()) ?u32 {
615 var i = it.field_index;
616
617 if (i >= it.struct_type.field_types.len)
618 return null;
619
620 if (it.struct_type.hasReorderedFields()) {
621 it.field_index += 1;
622 return it.struct_type.runtime_order.get(it.ip)[i].toInt();
623 }
624
625 while (it.struct_type.fieldIsComptime(it.ip, i)) {
626 i += 1;
627 if (i >= it.struct_type.field_types.len)
628 return null;
629 }
630
631 it.field_index = i + 1;
632 return i;
633 }
634 };
635
636 /// Iterates over non-comptime fields in the order they are laid out in memory at runtime.
637 /// May or may not include zero-bit fields.
638 /// Asserts the struct is not packed.
639 pub fn iterateRuntimeOrder(s: @This(), ip: *InternPool) RuntimeOrderIterator {
640 assert(s.layout != .Packed);
641 return .{
642 .ip = ip,
643 .field_index = 0,
644 .struct_type = s,
645 };
646 }
373647 };
374648
375649 pub const AnonStructType = struct {
......@@ -382,6 +656,17 @@ pub const Key = union(enum) {
382656 pub fn isTuple(self: AnonStructType) bool {
383657 return self.names.len == 0;
384658 }
659
660 pub fn fieldName(
661 self: AnonStructType,
662 ip: *const InternPool,
663 index: u32,
664 ) OptionalNullTerminatedString {
665 if (self.names.len == 0)
666 return .none;
667
668 return self.names.get(ip)[index].toOptional();
669 }
385670 };
386671
387672 /// Serves two purposes:
......@@ -870,7 +1155,6 @@ pub const Key = union(enum) {
8701155 .simple_type,
8711156 .simple_value,
8721157 .opt,
873 .struct_type,
8741158 .undef,
8751159 .err,
8761160 .enum_literal,
......@@ -893,6 +1177,7 @@ pub const Key = union(enum) {
8931177 .enum_type,
8941178 .variable,
8951179 .union_type,
1180 .struct_type,
8961181 => |x| Hash.hash(seed, asBytes(&x.decl)),
8971182
8981183 .int => |int| {
......@@ -969,11 +1254,11 @@ pub const Key = union(enum) {
9691254
9701255 if (child == .u8_type) {
9711256 switch (aggregate.storage) {
972 .bytes => |bytes| for (bytes[0..@as(usize, @intCast(len))]) |byte| {
1257 .bytes => |bytes| for (bytes[0..@intCast(len)]) |byte| {
9731258 std.hash.autoHash(&hasher, KeyTag.int);
9741259 std.hash.autoHash(&hasher, byte);
9751260 },
976 .elems => |elems| for (elems[0..@as(usize, @intCast(len))]) |elem| {
1261 .elems => |elems| for (elems[0..@intCast(len)]) |elem| {
9771262 const elem_key = ip.indexToKey(elem);
9781263 std.hash.autoHash(&hasher, @as(KeyTag, elem_key));
9791264 switch (elem_key) {
......@@ -1123,10 +1408,6 @@ pub const Key = union(enum) {
11231408 const b_info = b.opt;
11241409 return std.meta.eql(a_info, b_info);
11251410 },
1126 .struct_type => |a_info| {
1127 const b_info = b.struct_type;
1128 return std.meta.eql(a_info, b_info);
1129 },
11301411 .un => |a_info| {
11311412 const b_info = b.un;
11321413 return std.meta.eql(a_info, b_info);
......@@ -1298,6 +1579,10 @@ pub const Key = union(enum) {
12981579 const b_info = b.union_type;
12991580 return a_info.decl == b_info.decl;
13001581 },
1582 .struct_type => |a_info| {
1583 const b_info = b.struct_type;
1584 return a_info.decl == b_info.decl;
1585 },
13011586 .aggregate => |a_info| {
13021587 const b_info = b.aggregate;
13031588 if (a_info.ty != b_info.ty) return false;
......@@ -1433,6 +1718,8 @@ pub const Key = union(enum) {
14331718 }
14341719};
14351720
1721pub const RequiresComptime = enum(u2) { no, yes, unknown, wip };
1722
14361723// Unlike `Tag.TypeUnion` which is an encoding, and `Key.UnionType` which is a
14371724// minimal hashmap key, this type is a convenience type that contains info
14381725// needed by semantic analysis.
......@@ -1474,8 +1761,6 @@ pub const UnionType = struct {
14741761 }
14751762 };
14761763
1477 pub const RequiresComptime = enum(u2) { no, yes, unknown, wip };
1478
14791764 pub const Status = enum(u3) {
14801765 none,
14811766 field_types_wip,
......@@ -1814,9 +2099,11 @@ pub const Index = enum(u32) {
18142099 type_enum_nonexhaustive: DataIsExtraIndexOfEnumExplicit,
18152100 simple_type: struct { data: SimpleType },
18162101 type_opaque: struct { data: *Key.OpaqueType },
1817 type_struct: struct { data: Module.Struct.OptionalIndex },
2102 type_struct: struct { data: *Tag.TypeStruct },
18182103 type_struct_ns: struct { data: Module.Namespace.Index },
18192104 type_struct_anon: DataIsExtraIndexOfTypeStructAnon,
2105 type_struct_packed: struct { data: *Tag.TypeStructPacked },
2106 type_struct_packed_inits: struct { data: *Tag.TypeStructPacked },
18202107 type_tuple_anon: DataIsExtraIndexOfTypeStructAnon,
18212108 type_union: struct { data: *Tag.TypeUnion },
18222109 type_function: struct {
......@@ -2241,17 +2528,22 @@ pub const Tag = enum(u8) {
22412528 /// An opaque type.
22422529 /// data is index of Key.OpaqueType in extra.
22432530 type_opaque,
2244 /// A struct type.
2245 /// data is Module.Struct.OptionalIndex
2246 /// The `none` tag is used to represent `@TypeOf(.{})`.
2531 /// A non-packed struct type.
2532 /// data is 0 or extra index of `TypeStruct`.
2533 /// data == 0 represents `@TypeOf(.{})`.
22472534 type_struct,
2248 /// A struct type that has only a namespace; no fields, and there is no
2249 /// Module.Struct object allocated for it.
2535 /// A non-packed struct type that has only a namespace; no fields.
22502536 /// data is Module.Namespace.Index.
22512537 type_struct_ns,
22522538 /// An AnonStructType which stores types, names, and values for fields.
22532539 /// data is extra index of `TypeStructAnon`.
22542540 type_struct_anon,
2541 /// A packed struct, no fields have any init values.
2542 /// data is extra index of `TypeStructPacked`.
2543 type_struct_packed,
2544 /// A packed struct, one or more fields have init values.
2545 /// data is extra index of `TypeStructPacked`.
2546 type_struct_packed_inits,
22552547 /// An AnonStructType which has only types and values for fields.
22562548 /// data is extra index of `TypeStructAnon`.
22572549 type_tuple_anon,
......@@ -2461,9 +2753,10 @@ pub const Tag = enum(u8) {
24612753 .type_enum_nonexhaustive => EnumExplicit,
24622754 .simple_type => unreachable,
24632755 .type_opaque => OpaqueType,
2464 .type_struct => unreachable,
2756 .type_struct => TypeStruct,
24652757 .type_struct_ns => unreachable,
24662758 .type_struct_anon => TypeStructAnon,
2759 .type_struct_packed, .type_struct_packed_inits => TypeStructPacked,
24672760 .type_tuple_anon => TypeStructAnon,
24682761 .type_union => TypeUnion,
24692762 .type_function => TypeFunction,
......@@ -2634,11 +2927,90 @@ pub const Tag = enum(u8) {
26342927 any_aligned_fields: bool,
26352928 layout: std.builtin.Type.ContainerLayout,
26362929 status: UnionType.Status,
2637 requires_comptime: UnionType.RequiresComptime,
2930 requires_comptime: RequiresComptime,
26382931 assumed_runtime_bits: bool,
26392932 _: u21 = 0,
26402933 };
26412934 };
2935
2936 /// Trailing:
2937 /// 0. type: Index for each fields_len
2938 /// 1. name: NullTerminatedString for each fields_len
2939 /// 2. init: Index for each fields_len // if tag is type_struct_packed_inits
2940 pub const TypeStructPacked = struct {
2941 decl: Module.Decl.Index,
2942 zir_index: Zir.Inst.Index,
2943 fields_len: u32,
2944 namespace: Module.Namespace.OptionalIndex,
2945 backing_int_ty: Index,
2946 names_map: MapIndex,
2947 };
2948
2949 /// At first I thought of storing the denormalized data externally, such as...
2950 ///
2951 /// * runtime field order
2952 /// * calculated field offsets
2953 /// * size and alignment of the struct
2954 ///
2955 /// ...since these can be computed based on the other data here. However,
2956 /// this data does need to be memoized, and therefore stored in memory
2957 /// while the compiler is running, in order to avoid O(N^2) logic in many
2958 /// places. Since the data can be stored compactly in the InternPool
2959 /// representation, it is better for memory usage to store denormalized data
2960 /// here, and potentially also better for performance as well. It's also simpler
2961 /// than coming up with some other scheme for the data.
2962 ///
2963 /// Trailing:
2964 /// 0. type: Index for each field in declared order
2965 /// 1. if not is_tuple:
2966 /// names_map: MapIndex,
2967 /// name: NullTerminatedString // for each field in declared order
2968 /// 2. if any_default_inits:
2969 /// init: Index // for each field in declared order
2970 /// 3. if has_namespace:
2971 /// namespace: Module.Namespace.Index
2972 /// 4. if any_aligned_fields:
2973 /// align: Alignment // for each field in declared order
2974 /// 5. if any_comptime_fields:
2975 /// field_is_comptime_bits: u32 // minimal number of u32s needed, LSB is field 0
2976 /// 6. if not is_extern:
2977 /// field_index: RuntimeOrder // for each field in runtime order
2978 /// 7. field_offset: u32 // for each field in declared order, undef until layout_resolved
2979 pub const TypeStruct = struct {
2980 decl: Module.Decl.Index,
2981 zir_index: Zir.Inst.Index,
2982 fields_len: u32,
2983 flags: Flags,
2984 size: u32,
2985
2986 pub const Flags = packed struct(u32) {
2987 is_extern: bool,
2988 known_non_opv: bool,
2989 requires_comptime: RequiresComptime,
2990 is_tuple: bool,
2991 assumed_runtime_bits: bool,
2992 has_namespace: bool,
2993 any_comptime_fields: bool,
2994 any_default_inits: bool,
2995 any_aligned_fields: bool,
2996 /// `undefined` until the layout_resolved
2997 alignment: Alignment,
2998 /// Dependency loop detection when resolving struct alignment.
2999 alignment_wip: bool,
3000 /// Dependency loop detection when resolving field types.
3001 field_types_wip: bool,
3002 /// Dependency loop detection when resolving struct layout.
3003 layout_wip: bool,
3004 /// Determines whether `size`, `alignment`, runtime field order, and
3005 /// field offets are populated.
3006 layout_resolved: bool,
3007 // The types and all its fields have had their layout resolved. Even through pointer,
3008 // which `layout_resolved` does not ensure.
3009 fully_resolved: bool,
3010
3011 _: u11 = 0,
3012 };
3013 };
26423014};
26433015
26443016/// State that is mutable during semantic analysis. This data is not used for
......@@ -2764,20 +3136,26 @@ pub const SimpleValue = enum(u32) {
27643136
27653137/// Stored as a power-of-two, with one special value to indicate none.
27663138pub const Alignment = enum(u6) {
3139 @"1" = 0,
3140 @"2" = 1,
3141 @"4" = 2,
3142 @"8" = 3,
3143 @"16" = 4,
3144 @"32" = 5,
27673145 none = std.math.maxInt(u6),
27683146 _,
27693147
27703148 pub fn toByteUnitsOptional(a: Alignment) ?u64 {
27713149 return switch (a) {
27723150 .none => null,
2773 _ => @as(u64, 1) << @intFromEnum(a),
3151 else => @as(u64, 1) << @intFromEnum(a),
27743152 };
27753153 }
27763154
27773155 pub fn toByteUnits(a: Alignment, default: u64) u64 {
27783156 return switch (a) {
27793157 .none => default,
2780 _ => @as(u64, 1) << @intFromEnum(a),
3158 else => @as(u64, 1) << @intFromEnum(a),
27813159 };
27823160 }
27833161
......@@ -2792,16 +3170,95 @@ pub const Alignment = enum(u6) {
27923170 return fromByteUnits(n);
27933171 }
27943172
3173 pub fn toLog2Units(a: Alignment) u6 {
3174 assert(a != .none);
3175 return @intFromEnum(a);
3176 }
3177
3178 /// This is just a glorified `@enumFromInt` but using it can help
3179 /// document the intended conversion.
3180 /// The parameter uses a u32 for convenience at the callsite.
3181 pub fn fromLog2Units(a: u32) Alignment {
3182 assert(a != @intFromEnum(Alignment.none));
3183 return @enumFromInt(a);
3184 }
3185
27953186 pub fn order(lhs: Alignment, rhs: Alignment) std.math.Order {
2796 assert(lhs != .none and rhs != .none);
3187 assert(lhs != .none);
3188 assert(rhs != .none);
27973189 return std.math.order(@intFromEnum(lhs), @intFromEnum(rhs));
27983190 }
27993191
3192 /// Relaxed comparison. We have this as default because a lot of callsites
3193 /// were upgraded from directly using comparison operators on byte units,
3194 /// with the `none` value represented by zero.
3195 /// Prefer `compareStrict` if possible.
3196 pub fn compare(lhs: Alignment, op: std.math.CompareOperator, rhs: Alignment) bool {
3197 return std.math.compare(lhs.toRelaxedCompareUnits(), op, rhs.toRelaxedCompareUnits());
3198 }
3199
3200 pub fn compareStrict(lhs: Alignment, op: std.math.CompareOperator, rhs: Alignment) bool {
3201 assert(lhs != .none);
3202 assert(rhs != .none);
3203 return std.math.compare(@intFromEnum(lhs), op, @intFromEnum(rhs));
3204 }
3205
3206 /// Treats `none` as zero.
3207 /// This matches previous behavior of using `@max` directly on byte units.
3208 /// Prefer `maxStrict` if possible.
3209 pub fn max(lhs: Alignment, rhs: Alignment) Alignment {
3210 if (lhs == .none) return rhs;
3211 if (rhs == .none) return lhs;
3212 return maxStrict(lhs, rhs);
3213 }
3214
3215 pub fn maxStrict(lhs: Alignment, rhs: Alignment) Alignment {
3216 assert(lhs != .none);
3217 assert(rhs != .none);
3218 return @enumFromInt(@max(@intFromEnum(lhs), @intFromEnum(rhs)));
3219 }
3220
3221 /// Treats `none` as zero.
3222 /// This matches previous behavior of using `@min` directly on byte units.
3223 /// Prefer `minStrict` if possible.
3224 pub fn min(lhs: Alignment, rhs: Alignment) Alignment {
3225 if (lhs == .none) return lhs;
3226 if (rhs == .none) return rhs;
3227 return minStrict(lhs, rhs);
3228 }
3229
3230 pub fn minStrict(lhs: Alignment, rhs: Alignment) Alignment {
3231 assert(lhs != .none);
3232 assert(rhs != .none);
3233 return @enumFromInt(@min(@intFromEnum(lhs), @intFromEnum(rhs)));
3234 }
3235
3236 /// Align an address forwards to this alignment.
3237 pub fn forward(a: Alignment, addr: u64) u64 {
3238 assert(a != .none);
3239 const x = (@as(u64, 1) << @intFromEnum(a)) - 1;
3240 return (addr + x) & ~x;
3241 }
3242
3243 /// Align an address backwards to this alignment.
3244 pub fn backward(a: Alignment, addr: u64) u64 {
3245 assert(a != .none);
3246 const x = (@as(u64, 1) << @intFromEnum(a)) - 1;
3247 return addr & ~x;
3248 }
3249
3250 /// Check if an address is aligned to this amount.
3251 pub fn check(a: Alignment, addr: u64) bool {
3252 assert(a != .none);
3253 return @ctz(addr) >= @intFromEnum(a);
3254 }
3255
28003256 /// An array of `Alignment` objects existing within the `extra` array.
28013257 /// This type exists to provide a struct with lifetime that is
28023258 /// not invalidated when items are added to the `InternPool`.
28033259 pub const Slice = struct {
28043260 start: u32,
3261 /// This is the number of alignment values, not the number of u32 elements.
28053262 len: u32,
28063263
28073264 pub fn get(slice: Slice, ip: *const InternPool) []Alignment {
......@@ -2811,6 +3268,23 @@ pub const Alignment = enum(u6) {
28113268 return @ptrCast(bytes[0..slice.len]);
28123269 }
28133270 };
3271
3272 pub fn toRelaxedCompareUnits(a: Alignment) u8 {
3273 const n: u8 = @intFromEnum(a);
3274 assert(n <= @intFromEnum(Alignment.none));
3275 if (n == @intFromEnum(Alignment.none)) return 0;
3276 return n + 1;
3277 }
3278
3279 const LlvmBuilderAlignment = @import("codegen/llvm/Builder.zig").Alignment;
3280
3281 pub fn toLlvm(this: @This()) LlvmBuilderAlignment {
3282 return @enumFromInt(@intFromEnum(this));
3283 }
3284
3285 pub fn fromLlvm(other: LlvmBuilderAlignment) @This() {
3286 return @enumFromInt(@intFromEnum(other));
3287 }
28143288};
28153289
28163290/// Used for non-sentineled arrays that have length fitting in u32, as well as
......@@ -3065,9 +3539,6 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
30653539 ip.limbs.deinit(gpa);
30663540 ip.string_bytes.deinit(gpa);
30673541
3068 ip.structs_free_list.deinit(gpa);
3069 ip.allocated_structs.deinit(gpa);
3070
30713542 ip.decls_free_list.deinit(gpa);
30723543 ip.allocated_decls.deinit(gpa);
30733544
......@@ -3149,24 +3620,43 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
31493620 },
31503621
31513622 .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 },
3623
3624 .type_struct => .{ .struct_type = if (data == 0) .{
3625 .extra_index = 0,
3626 .namespace = .none,
3627 .decl = .none,
3628 .zir_index = @as(u32, undefined),
3629 .layout = .Auto,
3630 .field_names = .{ .start = 0, .len = 0 },
3631 .field_types = .{ .start = 0, .len = 0 },
3632 .field_inits = .{ .start = 0, .len = 0 },
3633 .field_aligns = .{ .start = 0, .len = 0 },
3634 .runtime_order = .{ .start = 0, .len = 0 },
3635 .comptime_bits = .{ .start = 0, .len = 0 },
3636 .offsets = .{ .start = 0, .len = 0 },
3637 .names_map = undefined,
3638 } else extraStructType(ip, data) },
3639
31633640 .type_struct_ns => .{ .struct_type = .{
3164 .index = .none,
3641 .extra_index = 0,
31653642 .namespace = @as(Module.Namespace.Index, @enumFromInt(data)).toOptional(),
3643 .decl = .none,
3644 .zir_index = @as(u32, undefined),
3645 .layout = .Auto,
3646 .field_names = .{ .start = 0, .len = 0 },
3647 .field_types = .{ .start = 0, .len = 0 },
3648 .field_inits = .{ .start = 0, .len = 0 },
3649 .field_aligns = .{ .start = 0, .len = 0 },
3650 .runtime_order = .{ .start = 0, .len = 0 },
3651 .comptime_bits = .{ .start = 0, .len = 0 },
3652 .offsets = .{ .start = 0, .len = 0 },
3653 .names_map = undefined,
31663654 } },
31673655
31683656 .type_struct_anon => .{ .anon_struct_type = extraTypeStructAnon(ip, data) },
31693657 .type_tuple_anon => .{ .anon_struct_type = extraTypeTupleAnon(ip, data) },
3658 .type_struct_packed => .{ .struct_type = extraPackedStructType(ip, data, false) },
3659 .type_struct_packed_inits => .{ .struct_type = extraPackedStructType(ip, data, true) },
31703660 .type_union => .{ .union_type = extraUnionType(ip, data) },
31713661
31723662 .type_enum_auto => {
......@@ -3441,7 +3931,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
34413931 .func_decl => .{ .func = ip.extraFuncDecl(data) },
34423932 .func_coerced => .{ .func = ip.extraFuncCoerced(data) },
34433933 .only_possible_value => {
3444 const ty = @as(Index, @enumFromInt(data));
3934 const ty: Index = @enumFromInt(data);
34453935 const ty_item = ip.items.get(@intFromEnum(ty));
34463936 return switch (ty_item.tag) {
34473937 .type_array_big => {
......@@ -3454,20 +3944,33 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
34543944 .storage = .{ .elems = sentinel[0..@intFromBool(sentinel[0] != .none)] },
34553945 } };
34563946 },
3457 .type_array_small, .type_vector => .{ .aggregate = .{
3458 .ty = ty,
3459 .storage = .{ .elems = &.{} },
3460 } },
3461 // TODO: migrate structs to properly use the InternPool rather
3462 // than using the SegmentedList trick, then the struct type will
3463 // have a slice of comptime values that can be used here for when
3464 // the struct has one possible value due to all fields comptime (same
3465 // as the tuple case below).
3466 .type_struct, .type_struct_ns => .{ .aggregate = .{
3947 .type_array_small,
3948 .type_vector,
3949 .type_struct_ns,
3950 .type_struct_packed,
3951 => .{ .aggregate = .{
34673952 .ty = ty,
34683953 .storage = .{ .elems = &.{} },
34693954 } },
34703955
3956 // There is only one possible value precisely due to the
3957 // fact that this values slice is fully populated!
3958 .type_struct => {
3959 const info = extraStructType(ip, ty_item.data);
3960 return .{ .aggregate = .{
3961 .ty = ty,
3962 .storage = .{ .elems = @ptrCast(info.field_inits.get(ip)) },
3963 } };
3964 },
3965
3966 .type_struct_packed_inits => {
3967 const info = extraPackedStructType(ip, ty_item.data, true);
3968 return .{ .aggregate = .{
3969 .ty = ty,
3970 .storage = .{ .elems = @ptrCast(info.field_inits.get(ip)) },
3971 } };
3972 },
3973
34713974 // There is only one possible value precisely due to the
34723975 // fact that this values slice is fully populated!
34733976 .type_struct_anon, .type_tuple_anon => {
......@@ -3476,7 +3979,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
34763979 const values = ip.extra.items[type_struct_anon.end + fields_len ..][0..fields_len];
34773980 return .{ .aggregate = .{
34783981 .ty = ty,
3479 .storage = .{ .elems = @as([]const Index, @ptrCast(values)) },
3982 .storage = .{ .elems = @ptrCast(values) },
34803983 } };
34813984 },
34823985
......@@ -3490,7 +3993,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
34903993 },
34913994 .bytes => {
34923995 const extra = ip.extraData(Bytes, data);
3493 const len = @as(u32, @intCast(ip.aggregateTypeLenIncludingSentinel(extra.ty)));
3996 const len: u32 = @intCast(ip.aggregateTypeLenIncludingSentinel(extra.ty));
34943997 return .{ .aggregate = .{
34953998 .ty = extra.ty,
34963999 .storage = .{ .bytes = ip.string_bytes.items[@intFromEnum(extra.bytes)..][0..len] },
......@@ -3498,8 +4001,8 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
34984001 },
34994002 .aggregate => {
35004003 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]));
4004 const len: u32 = @intCast(ip.aggregateTypeLenIncludingSentinel(extra.data.ty));
4005 const fields: []const Index = @ptrCast(ip.extra.items[extra.end..][0..len]);
35034006 return .{ .aggregate = .{
35044007 .ty = extra.data.ty,
35054008 .storage = .{ .elems = fields },
......@@ -3603,6 +4106,109 @@ fn extraTypeTupleAnon(ip: *const InternPool, extra_index: u32) Key.AnonStructTyp
36034106 };
36044107}
36054108
4109fn extraStructType(ip: *const InternPool, extra_index: u32) Key.StructType {
4110 const s = ip.extraDataTrail(Tag.TypeStruct, extra_index);
4111 const fields_len = s.data.fields_len;
4112
4113 var index = s.end;
4114
4115 const field_types = t: {
4116 const types: Index.Slice = .{ .start = index, .len = fields_len };
4117 index += fields_len;
4118 break :t types;
4119 };
4120 const names_map, const field_names: NullTerminatedString.Slice = t: {
4121 if (s.data.flags.is_tuple) break :t .{ .none, .{ .start = 0, .len = 0 } };
4122 const names_map: MapIndex = @enumFromInt(ip.extra.items[index]);
4123 index += 1;
4124 const names: NullTerminatedString.Slice = .{ .start = index, .len = fields_len };
4125 index += fields_len;
4126 break :t .{ names_map.toOptional(), names };
4127 };
4128 const field_inits: Index.Slice = t: {
4129 if (!s.data.flags.any_default_inits) break :t .{ .start = 0, .len = 0 };
4130 const inits: Index.Slice = .{ .start = index, .len = fields_len };
4131 index += fields_len;
4132 break :t inits;
4133 };
4134 const namespace = t: {
4135 if (!s.data.flags.has_namespace) break :t .none;
4136 const namespace: Module.Namespace.Index = @enumFromInt(ip.extra.items[index]);
4137 index += 1;
4138 break :t namespace.toOptional();
4139 };
4140 const field_aligns: Alignment.Slice = t: {
4141 if (!s.data.flags.any_aligned_fields) break :t .{ .start = 0, .len = 0 };
4142 const aligns: Alignment.Slice = .{ .start = index, .len = fields_len };
4143 index += (fields_len + 3) / 4;
4144 break :t aligns;
4145 };
4146 const comptime_bits: Key.StructType.ComptimeBits = t: {
4147 if (!s.data.flags.any_comptime_fields) break :t .{ .start = 0, .len = 0 };
4148 const comptime_bits: Key.StructType.ComptimeBits = .{ .start = index, .len = fields_len };
4149 index += (fields_len + 31) / 32;
4150 break :t comptime_bits;
4151 };
4152 const runtime_order: Key.StructType.RuntimeOrder.Slice = t: {
4153 if (s.data.flags.is_extern) break :t .{ .start = 0, .len = 0 };
4154 const ro: Key.StructType.RuntimeOrder.Slice = .{ .start = index, .len = fields_len };
4155 index += fields_len;
4156 break :t ro;
4157 };
4158 const offsets = t: {
4159 const offsets: Key.StructType.Offsets = .{ .start = index, .len = fields_len };
4160 index += fields_len;
4161 break :t offsets;
4162 };
4163 return .{
4164 .extra_index = extra_index,
4165 .decl = s.data.decl.toOptional(),
4166 .zir_index = s.data.zir_index,
4167 .layout = if (s.data.flags.is_extern) .Extern else .Auto,
4168 .field_types = field_types,
4169 .names_map = names_map,
4170 .field_names = field_names,
4171 .field_inits = field_inits,
4172 .namespace = namespace,
4173 .field_aligns = field_aligns,
4174 .comptime_bits = comptime_bits,
4175 .runtime_order = runtime_order,
4176 .offsets = offsets,
4177 };
4178}
4179
4180fn extraPackedStructType(ip: *const InternPool, extra_index: u32, inits: bool) Key.StructType {
4181 const type_struct_packed = ip.extraDataTrail(Tag.TypeStructPacked, extra_index);
4182 const fields_len = type_struct_packed.data.fields_len;
4183 return .{
4184 .extra_index = extra_index,
4185 .decl = type_struct_packed.data.decl.toOptional(),
4186 .namespace = type_struct_packed.data.namespace,
4187 .zir_index = type_struct_packed.data.zir_index,
4188 .layout = .Packed,
4189 .field_types = .{
4190 .start = type_struct_packed.end,
4191 .len = fields_len,
4192 },
4193 .field_names = .{
4194 .start = type_struct_packed.end + fields_len,
4195 .len = fields_len,
4196 },
4197 .field_inits = if (inits) .{
4198 .start = type_struct_packed.end + fields_len + fields_len,
4199 .len = fields_len,
4200 } else .{
4201 .start = 0,
4202 .len = 0,
4203 },
4204 .field_aligns = .{ .start = 0, .len = 0 },
4205 .runtime_order = .{ .start = 0, .len = 0 },
4206 .comptime_bits = .{ .start = 0, .len = 0 },
4207 .offsets = .{ .start = 0, .len = 0 },
4208 .names_map = type_struct_packed.data.names_map.toOptional(),
4209 };
4210}
4211
36064212fn extraFuncType(ip: *const InternPool, extra_index: u32) Key.FuncType {
36074213 const type_function = ip.extraDataTrail(Tag.TypeFunction, extra_index);
36084214 var index: usize = type_function.end;
......@@ -3831,8 +4437,9 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
38314437 .error_set_type => |error_set_type| {
38324438 assert(error_set_type.names_map == .none);
38334439 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));
4440 const names = error_set_type.names.get(ip);
4441 const names_map = try ip.addMap(gpa, names.len);
4442 addStringsToMap(ip, names_map, names);
38364443 const names_len = error_set_type.names.len;
38374444 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.ErrorSet).Struct.fields.len + names_len);
38384445 ip.items.appendAssumeCapacity(.{
......@@ -3877,21 +4484,8 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
38774484 });
38784485 },
38794486
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
4487 .struct_type => unreachable, // use getStructType() instead
38934488 .anon_struct_type => unreachable, // use getAnonStructType() instead
3894
38954489 .union_type => unreachable, // use getUnionType() instead
38964490
38974491 .opaque_type => |opaque_type| {
......@@ -3994,7 +4588,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
39944588 },
39954589 .struct_type => |struct_type| {
39964590 assert(ptr.addr == .field);
3997 assert(base_index.index < ip.structPtrUnwrapConst(struct_type.index).?.fields.count());
4591 assert(base_index.index < struct_type.field_types.len);
39984592 },
39994593 .union_type => |union_key| {
40004594 const union_type = ip.loadUnionType(union_key);
......@@ -4388,12 +4982,9 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
43884982 assert(ip.typeOf(elem) == child);
43894983 }
43904984 },
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());
4985 .struct_type => |t| {
4986 for (aggregate.storage.values(), t.field_types.get(ip)) |elem, field_ty| {
4987 assert(ip.typeOf(elem) == field_ty);
43974988 }
43984989 },
43994990 .anon_struct_type => |anon_struct_type| {
......@@ -4635,6 +5226,138 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, ini: UnionTypeInit) Allocat
46355226 return @enumFromInt(ip.items.len - 1);
46365227}
46375228
5229pub const StructTypeInit = struct {
5230 decl: Module.Decl.Index,
5231 namespace: Module.Namespace.OptionalIndex,
5232 layout: std.builtin.Type.ContainerLayout,
5233 zir_index: Zir.Inst.Index,
5234 fields_len: u32,
5235 known_non_opv: bool,
5236 requires_comptime: RequiresComptime,
5237 is_tuple: bool,
5238 any_comptime_fields: bool,
5239 any_default_inits: bool,
5240 any_aligned_fields: bool,
5241};
5242
5243pub fn getStructType(
5244 ip: *InternPool,
5245 gpa: Allocator,
5246 ini: StructTypeInit,
5247) Allocator.Error!Index {
5248 const adapter: KeyAdapter = .{ .intern_pool = ip };
5249 const key: Key = .{
5250 .struct_type = .{
5251 // Only the decl matters for hashing and equality purposes.
5252 .decl = ini.decl.toOptional(),
5253
5254 .extra_index = undefined,
5255 .namespace = undefined,
5256 .zir_index = undefined,
5257 .layout = undefined,
5258 .field_names = undefined,
5259 .field_types = undefined,
5260 .field_inits = undefined,
5261 .field_aligns = undefined,
5262 .runtime_order = undefined,
5263 .comptime_bits = undefined,
5264 .offsets = undefined,
5265 .names_map = undefined,
5266 },
5267 };
5268 const gop = try ip.map.getOrPutAdapted(gpa, key, adapter);
5269 if (gop.found_existing) return @enumFromInt(gop.index);
5270 errdefer _ = ip.map.pop();
5271
5272 const names_map = try ip.addMap(gpa, ini.fields_len);
5273 errdefer _ = ip.maps.pop();
5274
5275 const is_extern = switch (ini.layout) {
5276 .Auto => false,
5277 .Extern => true,
5278 .Packed => {
5279 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.TypeStructPacked).Struct.fields.len +
5280 ini.fields_len + // types
5281 ini.fields_len + // names
5282 ini.fields_len); // inits
5283 try ip.items.append(gpa, .{
5284 .tag = if (ini.any_default_inits) .type_struct_packed_inits else .type_struct_packed,
5285 .data = ip.addExtraAssumeCapacity(Tag.TypeStructPacked{
5286 .decl = ini.decl,
5287 .zir_index = ini.zir_index,
5288 .fields_len = ini.fields_len,
5289 .namespace = ini.namespace,
5290 .backing_int_ty = .none,
5291 .names_map = names_map,
5292 }),
5293 });
5294 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
5295 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(OptionalNullTerminatedString.none), ini.fields_len);
5296 if (ini.any_default_inits) {
5297 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
5298 }
5299 return @enumFromInt(ip.items.len - 1);
5300 },
5301 };
5302
5303 const align_elements_len = if (ini.any_aligned_fields) (ini.fields_len + 3) / 4 else 0;
5304 const align_element: u32 = @bitCast([1]u8{@intFromEnum(Alignment.none)} ** 4);
5305 const comptime_elements_len = if (ini.any_comptime_fields) (ini.fields_len + 31) / 32 else 0;
5306
5307 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.TypeStruct).Struct.fields.len +
5308 (ini.fields_len * 5) + // types, names, inits, runtime order, offsets
5309 align_elements_len + comptime_elements_len +
5310 2); // names_map + namespace
5311 try ip.items.append(gpa, .{
5312 .tag = .type_struct,
5313 .data = ip.addExtraAssumeCapacity(Tag.TypeStruct{
5314 .decl = ini.decl,
5315 .zir_index = ini.zir_index,
5316 .fields_len = ini.fields_len,
5317 .size = std.math.maxInt(u32),
5318 .flags = .{
5319 .is_extern = is_extern,
5320 .known_non_opv = ini.known_non_opv,
5321 .requires_comptime = ini.requires_comptime,
5322 .is_tuple = ini.is_tuple,
5323 .assumed_runtime_bits = false,
5324 .has_namespace = ini.namespace != .none,
5325 .any_comptime_fields = ini.any_comptime_fields,
5326 .any_default_inits = ini.any_default_inits,
5327 .any_aligned_fields = ini.any_aligned_fields,
5328 .alignment = .none,
5329 .alignment_wip = false,
5330 .field_types_wip = false,
5331 .layout_wip = false,
5332 .layout_resolved = false,
5333 .fully_resolved = false,
5334 },
5335 }),
5336 });
5337 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
5338 if (!ini.is_tuple) {
5339 ip.extra.appendAssumeCapacity(@intFromEnum(names_map));
5340 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(OptionalNullTerminatedString.none), ini.fields_len);
5341 }
5342 if (ini.any_default_inits) {
5343 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), ini.fields_len);
5344 }
5345 if (ini.namespace.unwrap()) |namespace| {
5346 ip.extra.appendAssumeCapacity(@intFromEnum(namespace));
5347 }
5348 if (ini.any_aligned_fields) {
5349 ip.extra.appendNTimesAssumeCapacity(align_element, align_elements_len);
5350 }
5351 if (ini.any_comptime_fields) {
5352 ip.extra.appendNTimesAssumeCapacity(0, comptime_elements_len);
5353 }
5354 if (ini.layout == .Auto) {
5355 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Key.StructType.RuntimeOrder.unresolved), ini.fields_len);
5356 }
5357 ip.extra.appendNTimesAssumeCapacity(std.math.maxInt(u32), ini.fields_len);
5358 return @enumFromInt(ip.items.len - 1);
5359}
5360
46385361pub const AnonStructTypeInit = struct {
46395362 types: []const Index,
46405363 /// This may be empty, indicating this is a tuple.
......@@ -4997,10 +5720,11 @@ pub fn getErrorSetType(
49975720 });
49985721 errdefer ip.items.len -= 1;
49995722
5000 const names_map = try ip.addMap(gpa);
5723 const names_map = try ip.addMap(gpa, names.len);
5724 assert(names_map == predicted_names_map);
50015725 errdefer _ = ip.maps.pop();
50025726
5003 try addStringsToMap(ip, gpa, names_map, names);
5727 addStringsToMap(ip, names_map, names);
50045728
50055729 return @enumFromInt(ip.items.len - 1);
50065730}
......@@ -5299,19 +6023,9 @@ pub const IncompleteEnumType = struct {
52996023 pub fn addFieldName(
53006024 self: @This(),
53016025 ip: *InternPool,
5302 gpa: Allocator,
53036026 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;
6027 ) ?u32 {
6028 return ip.addFieldName(self.names_map, self.names_start, name);
53156029 }
53166030
53176031 /// Returns the already-existing field with the same value, if any.
......@@ -5319,17 +6033,14 @@ pub const IncompleteEnumType = struct {
53196033 pub fn addFieldValue(
53206034 self: @This(),
53216035 ip: *InternPool,
5322 gpa: Allocator,
53236036 value: Index,
5324 ) Allocator.Error!?u32 {
6037 ) ?u32 {
53256038 assert(ip.typeOf(value) == @as(Index, @enumFromInt(ip.extra.items[self.tag_ty_index])));
53266039 const map = &ip.maps.items[@intFromEnum(self.values_map.unwrap().?)];
53276040 const field_index = map.count();
53286041 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);
6042 const adapter: Index.Adapter = .{ .indexes = @ptrCast(indexes) };
6043 const gop = map.getOrPutAssumeCapacityAdapted(value, adapter);
53336044 if (gop.found_existing) return @intCast(gop.index);
53346045 ip.extra.items[self.values_start + field_index] = @intFromEnum(value);
53356046 return null;
......@@ -5370,7 +6081,7 @@ fn getIncompleteEnumAuto(
53706081 const gop = try ip.map.getOrPutAdapted(gpa, enum_type.toKey(), adapter);
53716082 assert(!gop.found_existing);
53726083
5373 const names_map = try ip.addMap(gpa);
6084 const names_map = try ip.addMap(gpa, enum_type.fields_len);
53746085
53756086 const extra_fields_len: u32 = @typeInfo(EnumAuto).Struct.fields.len;
53766087 try ip.extra.ensureUnusedCapacity(gpa, extra_fields_len + enum_type.fields_len);
......@@ -5390,7 +6101,7 @@ fn getIncompleteEnumAuto(
53906101 });
53916102 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), enum_type.fields_len);
53926103 return .{
5393 .index = @as(Index, @enumFromInt(ip.items.len - 1)),
6104 .index = @enumFromInt(ip.items.len - 1),
53946105 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?,
53956106 .names_map = names_map,
53966107 .names_start = extra_index + extra_fields_len,
......@@ -5412,9 +6123,9 @@ fn getIncompleteEnumExplicit(
54126123 const gop = try ip.map.getOrPutAdapted(gpa, enum_type.toKey(), adapter);
54136124 assert(!gop.found_existing);
54146125
5415 const names_map = try ip.addMap(gpa);
6126 const names_map = try ip.addMap(gpa, enum_type.fields_len);
54166127 const values_map: OptionalMapIndex = if (!enum_type.has_values) .none else m: {
5417 const values_map = try ip.addMap(gpa);
6128 const values_map = try ip.addMap(gpa, enum_type.fields_len);
54186129 break :m values_map.toOptional();
54196130 };
54206131
......@@ -5441,7 +6152,7 @@ fn getIncompleteEnumExplicit(
54416152 // This is both fields and values (if present).
54426153 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), reserved_len);
54436154 return .{
5444 .index = @as(Index, @enumFromInt(ip.items.len - 1)),
6155 .index = @enumFromInt(ip.items.len - 1),
54456156 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumExplicit, "int_tag_type").?,
54466157 .names_map = names_map,
54476158 .names_start = extra_index + extra_fields_len,
......@@ -5484,8 +6195,8 @@ pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Erro
54846195
54856196 switch (ini.tag_mode) {
54866197 .auto => {
5487 const names_map = try ip.addMap(gpa);
5488 try addStringsToMap(ip, gpa, names_map, ini.names);
6198 const names_map = try ip.addMap(gpa, ini.names.len);
6199 addStringsToMap(ip, names_map, ini.names);
54896200
54906201 const fields_len: u32 = @intCast(ini.names.len);
54916202 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumAuto).Struct.fields.len +
......@@ -5514,12 +6225,12 @@ pub fn finishGetEnum(
55146225 ini: GetEnumInit,
55156226 tag: Tag,
55166227) Allocator.Error!Index {
5517 const names_map = try ip.addMap(gpa);
5518 try addStringsToMap(ip, gpa, names_map, ini.names);
6228 const names_map = try ip.addMap(gpa, ini.names.len);
6229 addStringsToMap(ip, names_map, ini.names);
55196230
55206231 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);
6232 const values_map = try ip.addMap(gpa, ini.values.len);
6233 addIndexesToMap(ip, values_map, ini.values);
55236234 break :m values_map.toOptional();
55246235 };
55256236 const fields_len: u32 = @intCast(ini.names.len);
......@@ -5553,35 +6264,35 @@ pub fn getAssumeExists(ip: *const InternPool, key: Key) Index {
55536264
55546265fn addStringsToMap(
55556266 ip: *InternPool,
5556 gpa: Allocator,
55576267 map_index: MapIndex,
55586268 strings: []const NullTerminatedString,
5559) Allocator.Error!void {
6269) void {
55606270 const map = &ip.maps.items[@intFromEnum(map_index)];
55616271 const adapter: NullTerminatedString.Adapter = .{ .strings = strings };
55626272 for (strings) |string| {
5563 const gop = try map.getOrPutAdapted(gpa, string, adapter);
6273 const gop = map.getOrPutAssumeCapacityAdapted(string, adapter);
55646274 assert(!gop.found_existing);
55656275 }
55666276}
55676277
55686278fn addIndexesToMap(
55696279 ip: *InternPool,
5570 gpa: Allocator,
55716280 map_index: MapIndex,
55726281 indexes: []const Index,
5573) Allocator.Error!void {
6282) void {
55746283 const map = &ip.maps.items[@intFromEnum(map_index)];
55756284 const adapter: Index.Adapter = .{ .indexes = indexes };
55766285 for (indexes) |index| {
5577 const gop = try map.getOrPutAdapted(gpa, index, adapter);
6286 const gop = map.getOrPutAssumeCapacityAdapted(index, adapter);
55786287 assert(!gop.found_existing);
55796288 }
55806289}
55816290
5582fn addMap(ip: *InternPool, gpa: Allocator) Allocator.Error!MapIndex {
6291fn addMap(ip: *InternPool, gpa: Allocator, cap: usize) Allocator.Error!MapIndex {
55836292 const ptr = try ip.maps.addOne(gpa);
6293 errdefer _ = ip.maps.pop();
55846294 ptr.* = .{};
6295 try ptr.ensureTotalCapacity(gpa, cap);
55856296 return @enumFromInt(ip.maps.items.len - 1);
55866297}
55876298
......@@ -5632,8 +6343,9 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {
56326343 Tag.TypePointer.Flags,
56336344 Tag.TypeFunction.Flags,
56346345 Tag.TypePointer.PackedOffset,
5635 Tag.Variable.Flags,
56366346 Tag.TypeUnion.Flags,
6347 Tag.TypeStruct.Flags,
6348 Tag.Variable.Flags,
56376349 => @bitCast(@field(extra, field.name)),
56386350
56396351 else => @compileError("bad field type: " ++ @typeName(field.type)),
......@@ -5705,6 +6417,7 @@ fn extraDataTrail(ip: *const InternPool, comptime T: type, index: usize) struct
57056417 Tag.TypeFunction.Flags,
57066418 Tag.TypePointer.PackedOffset,
57076419 Tag.TypeUnion.Flags,
6420 Tag.TypeStruct.Flags,
57086421 Tag.Variable.Flags,
57096422 FuncAnalysis,
57106423 => @bitCast(int32),
......@@ -6093,8 +6806,7 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
60936806 const new_elem_ty = switch (ip.indexToKey(new_ty)) {
60946807 inline .array_type, .vector_type => |seq_type| seq_type.child,
60956808 .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(),
6809 .struct_type => |struct_type| struct_type.field_types.get(ip)[i],
60986810 else => unreachable,
60996811 };
61006812 elem.* = try ip.getCoerced(gpa, elem.*, new_elem_ty);
......@@ -6206,25 +6918,6 @@ pub fn getCoercedInts(ip: *InternPool, gpa: Allocator, int: Key.Int, new_ty: Ind
62066918 } });
62076919}
62086920
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
62286921pub fn indexToFuncType(ip: *const InternPool, val: Index) ?Key.FuncType {
62296922 assert(val != .none);
62306923 const tags = ip.items.items(.tag);
......@@ -6337,20 +7030,16 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
63377030 const items_size = (1 + 4) * ip.items.len;
63387031 const extra_size = 4 * ip.extra.items.len;
63397032 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));
63437033 const decls_size = ip.allocated_decls.len * @sizeOf(Module.Decl);
63447034
63457035 // 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;
7036 const total_size = @sizeOf(InternPool) + items_size + extra_size + limbs_size + decls_size;
63477037
63487038 std.debug.print(
63497039 \\InternPool size: {d} bytes
63507040 \\ {d} items: {d} bytes
63517041 \\ {d} extra: {d} bytes
63527042 \\ {d} limbs: {d} bytes
6353 \\ {d} structs: {d} bytes
63547043 \\ {d} decls: {d} bytes
63557044 \\
63567045 , .{
......@@ -6361,8 +7050,6 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
63617050 extra_size,
63627051 ip.limbs.items.len,
63637052 limbs_size,
6364 ip.allocated_structs.len,
6365 structs_size,
63667053 ip.allocated_decls.len,
63677054 decls_size,
63687055 });
......@@ -6399,17 +7086,40 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
63997086 .type_enum_auto => @sizeOf(EnumAuto),
64007087 .type_opaque => @sizeOf(Key.OpaqueType),
64017088 .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));
7089 const info = ip.extraData(Tag.TypeStruct, data);
7090 var ints: usize = @typeInfo(Tag.TypeStruct).Struct.fields.len;
7091 ints += info.fields_len; // types
7092 if (!info.flags.is_tuple) {
7093 ints += 1; // names_map
7094 ints += info.fields_len; // names
7095 }
7096 if (info.flags.any_default_inits)
7097 ints += info.fields_len; // inits
7098 ints += @intFromBool(info.flags.has_namespace); // namespace
7099 if (info.flags.any_aligned_fields)
7100 ints += (info.fields_len + 3) / 4; // aligns
7101 if (info.flags.any_comptime_fields)
7102 ints += (info.fields_len + 31) / 32; // comptime bits
7103 if (!info.flags.is_extern)
7104 ints += info.fields_len; // runtime order
7105 ints += info.fields_len; // offsets
7106 break :b @sizeOf(u32) * ints;
64077107 },
64087108 .type_struct_ns => @sizeOf(Module.Namespace),
64097109 .type_struct_anon => b: {
64107110 const info = ip.extraData(TypeStructAnon, data);
64117111 break :b @sizeOf(TypeStructAnon) + (@sizeOf(u32) * 3 * info.fields_len);
64127112 },
7113 .type_struct_packed => b: {
7114 const info = ip.extraData(Tag.TypeStructPacked, data);
7115 break :b @sizeOf(u32) * (@typeInfo(Tag.TypeStructPacked).Struct.fields.len +
7116 info.fields_len + info.fields_len);
7117 },
7118 .type_struct_packed_inits => b: {
7119 const info = ip.extraData(Tag.TypeStructPacked, data);
7120 break :b @sizeOf(u32) * (@typeInfo(Tag.TypeStructPacked).Struct.fields.len +
7121 info.fields_len + info.fields_len + info.fields_len);
7122 },
64137123 .type_tuple_anon => b: {
64147124 const info = ip.extraData(TypeStructAnon, data);
64157125 break :b @sizeOf(TypeStructAnon) + (@sizeOf(u32) * 2 * info.fields_len);
......@@ -6562,6 +7272,8 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
65627272 .type_struct,
65637273 .type_struct_ns,
65647274 .type_struct_anon,
7275 .type_struct_packed,
7276 .type_struct_packed_inits,
65657277 .type_tuple_anon,
65667278 .type_union,
65677279 .type_function,
......@@ -6677,18 +7389,6 @@ pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator)
66777389 try bw.flush();
66787390}
66797391
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
66927392pub fn declPtr(ip: *InternPool, index: Module.Decl.Index) *Module.Decl {
66937393 return ip.allocated_decls.at(@intFromEnum(index));
66947394}
......@@ -6701,28 +7401,6 @@ pub fn namespacePtr(ip: *InternPool, index: Module.Namespace.Index) *Module.Name
67017401 return ip.allocated_namespaces.at(@intFromEnum(index));
67027402}
67037403
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
67267404pub fn createDecl(
67277405 ip: *InternPool,
67287406 gpa: Allocator,
......@@ -6967,6 +7645,8 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
69677645 .type_struct,
69687646 .type_struct_ns,
69697647 .type_struct_anon,
7648 .type_struct_packed,
7649 .type_struct_packed_inits,
69707650 .type_tuple_anon,
69717651 .type_union,
69727652 .type_function,
......@@ -7056,7 +7736,7 @@ pub fn toEnum(ip: *const InternPool, comptime E: type, i: Index) E {
70567736
70577737pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 {
70587738 return switch (ip.indexToKey(ty)) {
7059 .struct_type => |struct_type| ip.structPtrConst(struct_type.index.unwrap() orelse return 0).fields.count(),
7739 .struct_type => |struct_type| struct_type.field_types.len,
70607740 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
70617741 .array_type => |array_type| array_type.len,
70627742 .vector_type => |vector_type| vector_type.len,
......@@ -7066,7 +7746,7 @@ pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 {
70667746
70677747pub fn aggregateTypeLenIncludingSentinel(ip: *const InternPool, ty: Index) u64 {
70687748 return switch (ip.indexToKey(ty)) {
7069 .struct_type => |struct_type| ip.structPtrConst(struct_type.index.unwrap() orelse return 0).fields.count(),
7749 .struct_type => |struct_type| struct_type.field_types.len,
70707750 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
70717751 .array_type => |array_type| array_type.len + @intFromBool(array_type.sentinel != .none),
70727752 .vector_type => |vector_type| vector_type.len,
......@@ -7301,6 +7981,8 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois
73017981 .type_struct,
73027982 .type_struct_ns,
73037983 .type_struct_anon,
7984 .type_struct_packed,
7985 .type_struct_packed_inits,
73047986 .type_tuple_anon,
73057987 => .Struct,
73067988
......@@ -7526,6 +8208,40 @@ pub fn resolveBuiltinType(ip: *InternPool, want_index: Index, resolved_index: In
75268208 .data = @intFromEnum(SimpleValue.@"unreachable"),
75278209 });
75288210 } else {
7529 // TODO: add the index to a free-list for reuse
8211 // Here we could add the index to a free-list for reuse, but since
8212 // there is so little garbage created this way it's not worth it.
75308213 }
75318214}
8215
8216pub fn anonStructFieldTypes(ip: *const InternPool, i: Index) []const Index {
8217 return ip.indexToKey(i).anon_struct_type.types;
8218}
8219
8220pub fn anonStructFieldsLen(ip: *const InternPool, i: Index) u32 {
8221 return @intCast(ip.indexToKey(i).anon_struct_type.types.len);
8222}
8223
8224/// Asserts the type is a struct.
8225pub fn structDecl(ip: *const InternPool, i: Index) Module.Decl.OptionalIndex {
8226 return switch (ip.indexToKey(i)) {
8227 .struct_type => |t| t.decl,
8228 else => unreachable,
8229 };
8230}
8231
8232/// Returns the already-existing field with the same name, if any.
8233pub fn addFieldName(
8234 ip: *InternPool,
8235 names_map: MapIndex,
8236 names_start: u32,
8237 name: NullTerminatedString,
8238) ?u32 {
8239 const map = &ip.maps.items[@intFromEnum(names_map)];
8240 const field_index = map.count();
8241 const strings = ip.extra.items[names_start..][0..field_index];
8242 const adapter: NullTerminatedString.Adapter = .{ .strings = @ptrCast(strings) };
8243 const gop = map.getOrPutAssumeCapacityAdapted(name, adapter);
8244 if (gop.found_existing) return @intCast(gop.index);
8245 ip.extra.items[names_start + field_index] = @intFromEnum(name);
8246 return null;
8247}
src/Module.zig+188-382
......@@ -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
......@@ -4055,18 +3809,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
40553809 };
40563810 defer sema.deinit();
40573811
4058 if (mod.declIsRoot(decl_index)) {
4059 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);
4066 decl.analysis = .complete;
4067 decl.generation = mod.generation;
4068 return false;
4069 }
3812 assert(!mod.declIsRoot(decl_index));
40703813
40713814 var block_scope: Sema.Block = .{
40723815 .parent = null,
......@@ -5241,14 +4984,6 @@ pub fn destroyNamespace(mod: *Module, index: Namespace.Index) void {
52414984 return mod.intern_pool.destroyNamespace(mod.gpa, index);
52424985}
52434986
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
52524987pub fn allocateNewDecl(
52534988 mod: *Module,
52544989 namespace: Namespace.Index,
......@@ -6202,7 +5937,6 @@ pub fn optionalType(mod: *Module, child_type: InternPool.Index) Allocator.Error!
62025937
62035938pub fn ptrType(mod: *Module, info: InternPool.Key.PtrType) Allocator.Error!Type {
62045939 var canon_info = info;
6205 const have_elem_layout = info.child.toType().layoutIsResolved(mod);
62065940
62075941 if (info.flags.size == .C) canon_info.flags.is_allowzero = true;
62085942
......@@ -6210,17 +5944,17 @@ pub fn ptrType(mod: *Module, info: InternPool.Key.PtrType) Allocator.Error!Type
62105944 // type, we change it to 0 here. If this causes an assertion trip because the
62115945 // pointee type needs to be resolved more, that needs to be done before calling
62125946 // 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 }
5947 if (info.flags.alignment != .none and
5948 info.flags.alignment == info.child.toType().abiAlignment(mod))
5949 {
5950 canon_info.flags.alignment = .none;
62175951 }
62185952
62195953 switch (info.flags.vector_index) {
62205954 // Canonicalize host_size. If it matches the bit size of the pointee type,
62215955 // we change it to 0 here. If this causes an assertion trip, the pointee type
62225956 // needs to be resolved before calling this ptr() function.
6223 .none => if (have_elem_layout and info.packed_offset.host_size != 0) {
5957 .none => if (info.packed_offset.host_size != 0) {
62245958 const elem_bit_size = info.child.toType().bitSize(mod);
62255959 assert(info.packed_offset.bit_offset + elem_bit_size <= info.packed_offset.host_size * 8);
62265960 if (info.packed_offset.host_size * 8 == elem_bit_size) {
......@@ -6483,7 +6217,7 @@ pub fn intBitsForValue(mod: *Module, val: Value, sign: bool) u16 {
64836217 return @as(u16, @intCast(big.bitCountTwosComp()));
64846218 },
64856219 .lazy_align => |lazy_ty| {
6486 return Type.smallestUnsignedBits(lazy_ty.toType().abiAlignment(mod)) + @intFromBool(sign);
6220 return Type.smallestUnsignedBits(lazy_ty.toType().abiAlignment(mod).toByteUnits(0)) + @intFromBool(sign);
64876221 },
64886222 .lazy_size => |lazy_ty| {
64896223 return Type.smallestUnsignedBits(lazy_ty.toType().abiSize(mod)) + @intFromBool(sign);
......@@ -6639,20 +6373,30 @@ pub fn namespaceDeclIndex(mod: *Module, namespace_index: Namespace.Index) Decl.I
66396373/// * `@TypeOf(.{})`
66406374/// * A struct which has no fields (`struct {}`).
66416375/// * Not a struct.
6642pub fn typeToStruct(mod: *Module, ty: Type) ?*Struct {
6376pub fn typeToStruct(mod: *Module, ty: Type) ?InternPool.Key.StructType {
66436377 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);
6378 return switch (mod.intern_pool.indexToKey(ty.ip_index)) {
6379 .struct_type => |t| t,
6380 else => null,
6381 };
6382}
6383
6384pub fn typeToPackedStruct(mod: *Module, ty: Type) ?InternPool.Key.StructType {
6385 if (ty.ip_index == .none) return null;
6386 return switch (mod.intern_pool.indexToKey(ty.ip_index)) {
6387 .struct_type => |t| if (t.layout == .Packed) t else null,
6388 else => null,
6389 };
66466390}
66476391
66486392/// This asserts that the union's enum tag type has been resolved.
66496393pub fn typeToUnion(mod: *Module, ty: Type) ?InternPool.UnionType {
66506394 if (ty.ip_index == .none) return null;
66516395 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 }
6396 return switch (ip.indexToKey(ty.ip_index)) {
6397 .union_type => |k| ip.loadUnionType(k),
6398 else => null,
6399 };
66566400}
66576401
66586402pub fn typeToFunc(mod: *Module, ty: Type) ?InternPool.Key.FuncType {
......@@ -6741,13 +6485,13 @@ pub fn getParamName(mod: *Module, func_index: InternPool.Index, index: u32) [:0]
67416485
67426486pub const UnionLayout = struct {
67436487 abi_size: u64,
6744 abi_align: u32,
6488 abi_align: Alignment,
67456489 most_aligned_field: u32,
67466490 most_aligned_field_size: u64,
67476491 biggest_field: u32,
67486492 payload_size: u64,
6749 payload_align: u32,
6750 tag_align: u32,
6493 payload_align: Alignment,
6494 tag_align: Alignment,
67516495 tag_size: u64,
67526496 padding: u32,
67536497};
......@@ -6759,35 +6503,37 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout {
67596503 var most_aligned_field_size: u64 = undefined;
67606504 var biggest_field: u32 = undefined;
67616505 var payload_size: u64 = 0;
6762 var payload_align: u32 = 0;
6506 var payload_align: Alignment = .@"1";
67636507 for (u.field_types.get(ip), 0..) |field_ty, i| {
67646508 if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
67656509
6766 const field_align = u.fieldAlign(ip, @intCast(i)).toByteUnitsOptional() orelse
6510 const explicit_align = u.fieldAlign(ip, @intCast(i));
6511 const field_align = if (explicit_align != .none)
6512 explicit_align
6513 else
67676514 field_ty.toType().abiAlignment(mod);
67686515 const field_size = field_ty.toType().abiSize(mod);
67696516 if (field_size > payload_size) {
67706517 payload_size = field_size;
67716518 biggest_field = @intCast(i);
67726519 }
6773 if (field_align > payload_align) {
6774 payload_align = @intCast(field_align);
6520 if (field_align.compare(.gte, payload_align)) {
6521 payload_align = field_align;
67756522 most_aligned_field = @intCast(i);
67766523 most_aligned_field_size = field_size;
67776524 }
67786525 }
6779 payload_align = @max(payload_align, 1);
67806526 const have_tag = u.flagsPtr(ip).runtime_tag.hasTag();
67816527 if (!have_tag or !u.enum_tag_ty.toType().hasRuntimeBits(mod)) {
67826528 return .{
6783 .abi_size = std.mem.alignForward(u64, payload_size, payload_align),
6529 .abi_size = payload_align.forward(payload_size),
67846530 .abi_align = payload_align,
67856531 .most_aligned_field = most_aligned_field,
67866532 .most_aligned_field_size = most_aligned_field_size,
67876533 .biggest_field = biggest_field,
67886534 .payload_size = payload_size,
67896535 .payload_align = payload_align,
6790 .tag_align = 0,
6536 .tag_align = .none,
67916537 .tag_size = 0,
67926538 .padding = 0,
67936539 };
......@@ -6795,29 +6541,29 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout {
67956541 // Put the tag before or after the payload depending on which one's
67966542 // alignment is greater.
67976543 const tag_size = u.enum_tag_ty.toType().abiSize(mod);
6798 const tag_align = @max(1, u.enum_tag_ty.toType().abiAlignment(mod));
6544 const tag_align = u.enum_tag_ty.toType().abiAlignment(mod).max(.@"1");
67996545 var size: u64 = 0;
68006546 var padding: u32 = undefined;
6801 if (tag_align >= payload_align) {
6547 if (tag_align.compare(.gte, payload_align)) {
68026548 // {Tag, Payload}
68036549 size += tag_size;
6804 size = std.mem.alignForward(u64, size, payload_align);
6550 size = payload_align.forward(size);
68056551 size += payload_size;
68066552 const prev_size = size;
6807 size = std.mem.alignForward(u64, size, tag_align);
6808 padding = @as(u32, @intCast(size - prev_size));
6553 size = tag_align.forward(size);
6554 padding = @intCast(size - prev_size);
68096555 } else {
68106556 // {Payload, Tag}
68116557 size += payload_size;
6812 size = std.mem.alignForward(u64, size, tag_align);
6558 size = tag_align.forward(size);
68136559 size += tag_size;
68146560 const prev_size = size;
6815 size = std.mem.alignForward(u64, size, payload_align);
6816 padding = @as(u32, @intCast(size - prev_size));
6561 size = payload_align.forward(size);
6562 padding = @intCast(size - prev_size);
68176563 }
68186564 return .{
68196565 .abi_size = size,
6820 .abi_align = @max(tag_align, payload_align),
6566 .abi_align = tag_align.max(payload_align),
68216567 .most_aligned_field = most_aligned_field,
68226568 .most_aligned_field_size = most_aligned_field_size,
68236569 .biggest_field = biggest_field,
......@@ -6834,17 +6580,16 @@ pub fn unionAbiSize(mod: *Module, u: InternPool.UnionType) u64 {
68346580}
68356581
68366582/// 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 {
6583pub fn unionAbiAlignment(mod: *Module, u: InternPool.UnionType) Alignment {
68396584 const ip = &mod.intern_pool;
68406585 const have_tag = u.flagsPtr(ip).runtime_tag.hasTag();
6841 var max_align: u32 = 0;
6586 var max_align: Alignment = .none;
68426587 if (have_tag) max_align = u.enum_tag_ty.toType().abiAlignment(mod);
68436588 for (u.field_types.get(ip), 0..) |field_ty, field_index| {
68446589 if (!field_ty.toType().hasRuntimeBits(mod)) continue;
68456590
68466591 const field_align = mod.unionFieldNormalAlignment(u, @intCast(field_index));
6847 max_align = @max(max_align, field_align);
6592 max_align = max_align.max(field_align);
68486593 }
68496594 return max_align;
68506595}
......@@ -6852,10 +6597,10 @@ pub fn unionAbiAlignment(mod: *Module, u: InternPool.UnionType) u32 {
68526597/// Returns the field alignment, assuming the union is not packed.
68536598/// Keep implementation in sync with `Sema.unionFieldAlignment`.
68546599/// 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 {
6600pub fn unionFieldNormalAlignment(mod: *Module, u: InternPool.UnionType, field_index: u32) Alignment {
68576601 const ip = &mod.intern_pool;
6858 if (u.fieldAlign(ip, field_index).toByteUnitsOptional()) |a| return @intCast(a);
6602 const field_align = u.fieldAlign(ip, field_index);
6603 if (field_align != .none) return field_align;
68596604 const field_ty = u.field_types.get(ip)[field_index].toType();
68606605 return field_ty.abiAlignment(mod);
68616606}
......@@ -6866,3 +6611,64 @@ pub fn unionTagFieldIndex(mod: *Module, u: InternPool.UnionType, enum_tag: Value
68666611 const enum_type = ip.indexToKey(u.enum_tag_ty).enum_type;
68676612 return enum_type.tagValueIndex(ip, enum_tag.toIntern());
68686613}
6614
6615/// Returns the field alignment of a non-packed struct in byte units.
6616/// Keep implementation in sync with `Sema.structFieldAlignment`.
6617/// asserts the layout is not packed.
6618pub fn structFieldAlignment(
6619 mod: *Module,
6620 explicit_alignment: InternPool.Alignment,
6621 field_ty: Type,
6622 layout: std.builtin.Type.ContainerLayout,
6623) Alignment {
6624 assert(layout != .Packed);
6625 if (explicit_alignment != .none) return explicit_alignment;
6626 switch (layout) {
6627 .Packed => unreachable,
6628 .Auto => {
6629 if (mod.getTarget().ofmt == .c) {
6630 return structFieldAlignmentExtern(mod, field_ty);
6631 } else {
6632 return field_ty.abiAlignment(mod);
6633 }
6634 },
6635 .Extern => return structFieldAlignmentExtern(mod, field_ty),
6636 }
6637}
6638
6639/// Returns the field alignment of an extern struct in byte units.
6640/// This logic is duplicated in Type.abiAlignmentAdvanced.
6641pub fn structFieldAlignmentExtern(mod: *Module, field_ty: Type) Alignment {
6642 const ty_abi_align = field_ty.abiAlignment(mod);
6643
6644 if (field_ty.isAbiInt(mod) and field_ty.intInfo(mod).bits >= 128) {
6645 // The C ABI requires 128 bit integer fields of structs
6646 // to be 16-bytes aligned.
6647 return ty_abi_align.max(.@"16");
6648 }
6649
6650 return ty_abi_align;
6651}
6652
6653/// TODO: avoid linear search by storing these in trailing data of packed struct types
6654/// then packedStructFieldByteOffset can be expressed in terms of bits / 8, fixing
6655/// that one too.
6656/// https://github.com/ziglang/zig/issues/17178
6657pub fn structPackedFieldBitOffset(
6658 mod: *Module,
6659 struct_type: InternPool.Key.StructType,
6660 field_index: u32,
6661) u16 {
6662 const ip = &mod.intern_pool;
6663 assert(struct_type.layout == .Packed);
6664 assert(struct_type.haveLayout(ip));
6665 var bit_sum: u64 = 0;
6666 for (0..struct_type.field_types.len) |i| {
6667 if (i == field_index) {
6668 return @intCast(bit_sum);
6669 }
6670 const field_ty = struct_type.field_types.get(ip)[i].toType();
6671 bit_sum += field_ty.bitSize(mod);
6672 }
6673 unreachable; // index out of bounds
6674}
src/Sema.zig+1020-834
......@@ -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,33 @@ 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 {
2518 if (alignment == 0) return sema.fail(block, src, "alignment must be >= 1", .{});
2514 alignment: u64,
2515) !Alignment {
2516 const result = try validateAlignAllowZero(sema, block, src, alignment);
2517 if (result == .none) return sema.fail(block, src, "alignment must be >= 1", .{});
2518 return result;
2519}
2520
2521fn validateAlignAllowZero(
2522 sema: *Sema,
2523 block: *Block,
2524 src: LazySrcLoc,
2525 alignment: u64,
2526) !Alignment {
2527 if (alignment == 0) return .none;
25192528 if (!std.math.isPowerOfTwo(alignment)) {
25202529 return sema.fail(block, src, "alignment value '{d}' is not a power of two", .{
25212530 alignment,
25222531 });
25232532 }
2533 return Alignment.fromNonzeroByteUnits(alignment);
25242534}
25252535
25262536pub fn resolveAlign(
......@@ -2619,7 +2629,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
26192629 defer trash_block.instructions.deinit(sema.gpa);
26202630 const operand = try trash_block.addBitCast(pointee_ty, .void_value);
26212631
2622 const ptr_ty = try mod.ptrType(.{
2632 const ptr_ty = try sema.ptrType(.{
26232633 .child = pointee_ty.toIntern(),
26242634 .flags = .{
26252635 .alignment = ia1.alignment,
......@@ -2650,7 +2660,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
26502660 if (alignment != .none) {
26512661 try sema.resolveTypeLayout(pointee_ty);
26522662 }
2653 const ptr_ty = try mod.ptrType(.{
2663 const ptr_ty = try sema.ptrType(.{
26542664 .child = pointee_ty.toIntern(),
26552665 .flags = .{
26562666 .alignment = alignment,
......@@ -2720,7 +2730,7 @@ fn coerceResultPtr(
27202730 }
27212731 }
27222732
2723 const ptr_ty = try mod.ptrType(.{
2733 const ptr_ty = try sema.ptrType(.{
27242734 .child = pointee_ty.toIntern(),
27252735 .flags = .{ .address_space = addr_space },
27262736 });
......@@ -2749,7 +2759,7 @@ fn coerceResultPtr(
27492759 // Array coerced to Vector where element size is not equal but coercible.
27502760 .aggregate_init => {
27512761 const ty_pl = air_datas[trash_inst].ty_pl;
2752 const ptr_operand_ty = try mod.ptrType(.{
2762 const ptr_operand_ty = try sema.ptrType(.{
27532763 .child = (try sema.analyzeAsType(block, src, ty_pl.ty)).toIntern(),
27542764 .flags = .{ .address_space = addr_space },
27552765 });
......@@ -2763,7 +2773,7 @@ fn coerceResultPtr(
27632773 .bitcast => {
27642774 const ty_op = air_datas[trash_inst].ty_op;
27652775 const operand_ty = sema.typeOf(ty_op.operand);
2766 const ptr_operand_ty = try mod.ptrType(.{
2776 const ptr_operand_ty = try sema.ptrType(.{
27672777 .child = operand_ty.toIntern(),
27682778 .flags = .{ .address_space = addr_space },
27692779 });
......@@ -2801,26 +2811,26 @@ fn coerceResultPtr(
28012811 }
28022812}
28032813
2804pub fn analyzeStructDecl(
2814pub fn getStructType(
28052815 sema: *Sema,
2806 new_decl: *Decl,
2807 inst: Zir.Inst.Index,
2808 struct_index: Module.Struct.Index,
2809) SemaError!void {
2816 decl: Module.Decl.Index,
2817 namespace: Module.Namespace.Index,
2818 zir_index: Zir.Inst.Index,
2819) !InternPool.Index {
28102820 const mod = sema.mod;
2811 const struct_obj = mod.structPtr(struct_index);
2812 const extended = sema.code.instructions.items(.data)[inst].extended;
2821 const gpa = sema.gpa;
2822 const ip = &mod.intern_pool;
2823 const extended = sema.code.instructions.items(.data)[zir_index].extended;
28132824 assert(extended.opcode == .struct_decl);
28142825 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
28152826
2816 struct_obj.known_non_opv = small.known_non_opv;
2817 if (small.known_comptime_only) {
2818 struct_obj.requires_comptime = .yes;
2819 }
2820
28212827 var extra_index: usize = extended.operand;
28222828 extra_index += @intFromBool(small.has_src_node);
2823 extra_index += @intFromBool(small.has_fields_len);
2829 const fields_len = if (small.has_fields_len) blk: {
2830 const fields_len = sema.code.extra[extra_index];
2831 extra_index += 1;
2832 break :blk fields_len;
2833 } else 0;
28242834 const decls_len = if (small.has_decls_len) blk: {
28252835 const decls_len = sema.code.extra[extra_index];
28262836 extra_index += 1;
......@@ -2837,7 +2847,23 @@ pub fn analyzeStructDecl(
28372847 }
28382848 }
28392849
2840 _ = try mod.scanNamespace(struct_obj.namespace, extra_index, decls_len, new_decl);
2850 extra_index = try mod.scanNamespace(namespace, extra_index, decls_len, mod.declPtr(decl));
2851
2852 const ty = try ip.getStructType(gpa, .{
2853 .decl = decl,
2854 .namespace = namespace.toOptional(),
2855 .zir_index = zir_index,
2856 .layout = small.layout,
2857 .known_non_opv = small.known_non_opv,
2858 .is_tuple = small.is_tuple,
2859 .fields_len = fields_len,
2860 .requires_comptime = if (small.known_comptime_only) .yes else .unknown,
2861 .any_default_inits = small.any_default_inits,
2862 .any_comptime_fields = small.any_comptime_fields,
2863 .any_aligned_fields = small.any_aligned_fields,
2864 });
2865
2866 return ty;
28412867}
28422868
28432869fn zirStructDecl(
......@@ -2847,7 +2873,7 @@ fn zirStructDecl(
28472873 inst: Zir.Inst.Index,
28482874) CompileError!Air.Inst.Ref {
28492875 const mod = sema.mod;
2850 const gpa = sema.gpa;
2876 const ip = &mod.intern_pool;
28512877 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
28522878 const src: LazySrcLoc = if (small.has_src_node) blk: {
28532879 const node_offset: i32 = @bitCast(sema.code.extra[extended.operand]);
......@@ -2874,37 +2900,21 @@ fn zirStructDecl(
28742900 const new_namespace = mod.namespacePtr(new_namespace_index);
28752901 errdefer mod.destroyNamespace(new_namespace_index);
28762902
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
28892903 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 } });
2904 const ty = try sema.getStructType(new_decl_index, new_namespace_index, inst);
28942905 if (sema.builtin_type_target_index != .none) {
2895 mod.intern_pool.resolveBuiltinType(sema.builtin_type_target_index, ty);
2906 ip.resolveBuiltinType(sema.builtin_type_target_index, ty);
28962907 break :ty sema.builtin_type_target_index;
28972908 }
28982909 break :ty ty;
28992910 };
29002911 // TODO: figure out InternPool removals for incremental compilation
2901 //errdefer mod.intern_pool.remove(struct_ty);
2912 //errdefer ip.remove(struct_ty);
29022913
29032914 new_decl.ty = Type.type;
29042915 new_decl.val = struct_ty.toValue();
29052916 new_namespace.ty = struct_ty.toType();
29062917
2907 try sema.analyzeStructDecl(new_decl, inst, struct_index);
29082918 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
29092919 try mod.finalizeAnonDecl(new_decl_index);
29102920 return decl_val;
......@@ -3196,7 +3206,7 @@ fn zirEnumDecl(
31963206 extra_index += 1;
31973207
31983208 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| {
3209 if (incomplete_enum.addFieldName(&mod.intern_pool, field_name)) |other_index| {
32003210 const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy;
32013211 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy;
32023212 const msg = msg: {
......@@ -3227,7 +3237,7 @@ fn zirEnumDecl(
32273237 };
32283238 if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) break :overflow true;
32293239 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| {
3240 if (incomplete_enum.addFieldValue(&mod.intern_pool, last_tag_val.?.toIntern())) |other_index| {
32313241 const value_src = mod.fieldSrcLoc(new_decl_index, .{
32323242 .index = field_i,
32333243 .range = .value,
......@@ -3249,7 +3259,7 @@ fn zirEnumDecl(
32493259 else
32503260 try mod.intValue(int_tag_ty, 0);
32513261 if (overflow != null) break :overflow true;
3252 if (try incomplete_enum.addFieldValue(&mod.intern_pool, gpa, last_tag_val.?.toIntern())) |other_index| {
3262 if (incomplete_enum.addFieldValue(&mod.intern_pool, last_tag_val.?.toIntern())) |other_index| {
32533263 const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy;
32543264 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy;
32553265 const msg = msg: {
......@@ -3498,7 +3508,7 @@ fn zirRetPtr(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
34983508 }
34993509
35003510 const target = sema.mod.getTarget();
3501 const ptr_type = try sema.mod.ptrType(.{
3511 const ptr_type = try sema.ptrType(.{
35023512 .child = sema.fn_ret_ty.toIntern(),
35033513 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
35043514 });
......@@ -3507,6 +3517,7 @@ fn zirRetPtr(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
35073517 // We are inlining a function call; this should be emitted as an alloc, not a ret_ptr.
35083518 // TODO when functions gain result location support, the inlining struct in
35093519 // Block should contain the return pointer, and we would pass that through here.
3520 try sema.queueFullTypeResolution(sema.fn_ret_ty);
35103521 return block.addTy(.alloc, ptr_type);
35113522 }
35123523
......@@ -3701,7 +3712,7 @@ fn zirAllocExtended(
37013712 }
37023713 const target = sema.mod.getTarget();
37033714 try sema.resolveTypeLayout(var_ty);
3704 const ptr_type = try sema.mod.ptrType(.{
3715 const ptr_type = try sema.ptrType(.{
37053716 .child = var_ty.toIntern(),
37063717 .flags = .{
37073718 .alignment = alignment,
......@@ -3810,7 +3821,7 @@ fn makePtrConst(sema: *Sema, block: *Block, alloc: Air.Inst.Ref) CompileError!Ai
38103821
38113822 var ptr_info = alloc_ty.ptrInfo(mod);
38123823 ptr_info.flags.is_const = true;
3813 const const_ptr_ty = try mod.ptrType(ptr_info);
3824 const const_ptr_ty = try sema.ptrType(ptr_info);
38143825
38153826 // Detect if a comptime value simply needs to have its type changed.
38163827 if (try sema.resolveMaybeUndefVal(alloc)) |val| {
......@@ -3852,7 +3863,7 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
38523863 return sema.analyzeComptimeAlloc(block, var_ty, .none);
38533864 }
38543865 const target = sema.mod.getTarget();
3855 const ptr_type = try sema.mod.ptrType(.{
3866 const ptr_type = try sema.ptrType(.{
38563867 .child = var_ty.toIntern(),
38573868 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
38583869 });
......@@ -3872,7 +3883,7 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
38723883 }
38733884 try sema.validateVarType(block, ty_src, var_ty, false);
38743885 const target = sema.mod.getTarget();
3875 const ptr_type = try sema.mod.ptrType(.{
3886 const ptr_type = try sema.ptrType(.{
38763887 .child = var_ty.toIntern(),
38773888 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
38783889 });
......@@ -3938,7 +3949,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
39383949 const decl = mod.declPtr(decl_index);
39393950 if (iac.is_const) _ = try decl.internValue(mod);
39403951 const final_elem_ty = decl.ty;
3941 const final_ptr_ty = try mod.ptrType(.{
3952 const final_ptr_ty = try sema.ptrType(.{
39423953 .child = final_elem_ty.toIntern(),
39433954 .flags = .{
39443955 .is_const = false,
......@@ -3971,7 +3982,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
39713982 const peer_inst_list = ia2.prongs.items(.stored_inst);
39723983 const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list, .none);
39733984
3974 const final_ptr_ty = try mod.ptrType(.{
3985 const final_ptr_ty = try sema.ptrType(.{
39753986 .child = final_elem_ty.toIntern(),
39763987 .flags = .{
39773988 .alignment = ia1.alignment,
......@@ -4093,7 +4104,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
40934104 trash_block.is_comptime = false;
40944105 defer trash_block.instructions.deinit(gpa);
40954106
4096 const mut_final_ptr_ty = try mod.ptrType(.{
4107 const mut_final_ptr_ty = try sema.ptrType(.{
40974108 .child = final_elem_ty.toIntern(),
40984109 .flags = .{
40994110 .alignment = ia1.alignment,
......@@ -4688,12 +4699,13 @@ fn validateStructInit(
46884699 // In this case the only thing we need to do is evaluate the implicit
46894700 // store instructions for default field values, and report any missing fields.
46904701 // Avoid the cost of the extra machinery for detecting a comptime struct init value.
4691 for (found_fields, 0..) |field_ptr, i| {
4702 for (found_fields, 0..) |field_ptr, i_usize| {
4703 const i: u32 = @intCast(i_usize);
46924704 if (field_ptr != 0) continue;
46934705
46944706 const default_val = struct_ty.structFieldDefaultValue(i, mod);
46954707 if (default_val.toIntern() == .unreachable_value) {
4696 if (struct_ty.isTuple(mod)) {
4708 const field_name = struct_ty.structFieldName(i, mod).unwrap() orelse {
46974709 const template = "missing tuple field with index {d}";
46984710 if (root_msg) |msg| {
46994711 try sema.errNote(block, init_src, msg, template, .{i});
......@@ -4701,8 +4713,7 @@ fn validateStructInit(
47014713 root_msg = try sema.errMsg(block, init_src, template, .{i});
47024714 }
47034715 continue;
4704 }
4705 const field_name = struct_ty.structFieldName(i, mod);
4716 };
47064717 const template = "missing struct field: {}";
47074718 const args = .{field_name.fmt(ip)};
47084719 if (root_msg) |msg| {
......@@ -4723,10 +4734,11 @@ fn validateStructInit(
47234734 }
47244735
47254736 if (root_msg) |msg| {
4726 if (mod.typeToStruct(struct_ty)) |struct_obj| {
4727 const fqn = try struct_obj.getFullyQualifiedName(mod);
4737 if (mod.typeToStruct(struct_ty)) |struct_type| {
4738 const decl = mod.declPtr(struct_type.decl.unwrap().?);
4739 const fqn = try decl.getFullyQualifiedName(mod);
47284740 try mod.errNoteNonLazy(
4729 struct_obj.srcLoc(mod),
4741 decl.srcLoc(mod),
47304742 msg,
47314743 "struct '{}' declared here",
47324744 .{fqn.fmt(ip)},
......@@ -4751,7 +4763,8 @@ fn validateStructInit(
47514763 // ends up being comptime-known.
47524764 const field_values = try sema.arena.alloc(InternPool.Index, struct_ty.structFieldCount(mod));
47534765
4754 field: for (found_fields, 0..) |field_ptr, i| {
4766 field: for (found_fields, 0..) |field_ptr, i_usize| {
4767 const i: u32 = @intCast(i_usize);
47554768 if (field_ptr != 0) {
47564769 // Determine whether the value stored to this pointer is comptime-known.
47574770 const field_ty = struct_ty.structFieldType(i, mod);
......@@ -4830,7 +4843,7 @@ fn validateStructInit(
48304843
48314844 const default_val = struct_ty.structFieldDefaultValue(i, mod);
48324845 if (default_val.toIntern() == .unreachable_value) {
4833 if (struct_ty.isTuple(mod)) {
4846 const field_name = struct_ty.structFieldName(i, mod).unwrap() orelse {
48344847 const template = "missing tuple field with index {d}";
48354848 if (root_msg) |msg| {
48364849 try sema.errNote(block, init_src, msg, template, .{i});
......@@ -4838,8 +4851,7 @@ fn validateStructInit(
48384851 root_msg = try sema.errMsg(block, init_src, template, .{i});
48394852 }
48404853 continue;
4841 }
4842 const field_name = struct_ty.structFieldName(i, mod);
4854 };
48434855 const template = "missing struct field: {}";
48444856 const args = .{field_name.fmt(ip)};
48454857 if (root_msg) |msg| {
......@@ -4853,10 +4865,11 @@ fn validateStructInit(
48534865 }
48544866
48554867 if (root_msg) |msg| {
4856 if (mod.typeToStruct(struct_ty)) |struct_obj| {
4857 const fqn = try struct_obj.getFullyQualifiedName(mod);
4868 if (mod.typeToStruct(struct_ty)) |struct_type| {
4869 const decl = mod.declPtr(struct_type.decl.unwrap().?);
4870 const fqn = try decl.getFullyQualifiedName(mod);
48584871 try mod.errNoteNonLazy(
4859 struct_obj.srcLoc(mod),
4872 decl.srcLoc(mod),
48604873 msg,
48614874 "struct '{}' declared here",
48624875 .{fqn.fmt(ip)},
......@@ -5255,14 +5268,14 @@ fn failWithBadMemberAccess(
52555268fn failWithBadStructFieldAccess(
52565269 sema: *Sema,
52575270 block: *Block,
5258 struct_obj: *Module.Struct,
5271 struct_type: InternPool.Key.StructType,
52595272 field_src: LazySrcLoc,
52605273 field_name: InternPool.NullTerminatedString,
52615274) CompileError {
52625275 const mod = sema.mod;
52635276 const gpa = sema.gpa;
5264
5265 const fqn = try struct_obj.getFullyQualifiedName(mod);
5277 const decl = mod.declPtr(struct_type.decl.unwrap().?);
5278 const fqn = try decl.getFullyQualifiedName(mod);
52665279
52675280 const msg = msg: {
52685281 const msg = try sema.errMsg(
......@@ -5272,7 +5285,7 @@ fn failWithBadStructFieldAccess(
52725285 .{ field_name.fmt(&mod.intern_pool), fqn.fmt(&mod.intern_pool) },
52735286 );
52745287 errdefer msg.destroy(gpa);
5275 try mod.errNoteNonLazy(struct_obj.srcLoc(mod), msg, "struct declared here", .{});
5288 try mod.errNoteNonLazy(decl.srcLoc(mod), msg, "struct declared here", .{});
52765289 break :msg msg;
52775290 };
52785291 return sema.failWithOwnedErrorMsg(block, msg);
......@@ -5787,9 +5800,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
57875800
57885801 try mod.semaFile(result.file);
57895802 const file_root_decl_index = result.file.root_decl.unwrap().?;
5790 const file_root_decl = mod.declPtr(file_root_decl_index);
5791 try mod.declareDeclDependency(sema.owner_decl_index, file_root_decl_index);
5792 return Air.internedToRef(file_root_decl.val.toIntern());
5803 return sema.analyzeDeclVal(parent_block, src, file_root_decl_index);
57935804}
57945805
57955806fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -8638,7 +8649,7 @@ fn analyzeOptionalPayloadPtr(
86388649 }
86398650
86408651 const child_type = opt_type.optionalChild(mod);
8641 const child_pointer = try mod.ptrType(.{
8652 const child_pointer = try sema.ptrType(.{
86428653 .child = child_type.toIntern(),
86438654 .flags = .{
86448655 .is_const = optional_ptr_ty.isConstPtr(mod),
......@@ -8707,7 +8718,7 @@ fn zirOptionalPayload(
87078718 // TODO https://github.com/ziglang/zig/issues/6597
87088719 if (true) break :t operand_ty;
87098720 const ptr_info = operand_ty.ptrInfo(mod);
8710 break :t try mod.ptrType(.{
8721 break :t try sema.ptrType(.{
87118722 .child = ptr_info.child,
87128723 .flags = .{
87138724 .alignment = ptr_info.flags.alignment,
......@@ -8825,7 +8836,7 @@ fn analyzeErrUnionPayloadPtr(
88258836
88268837 const err_union_ty = operand_ty.childType(mod);
88278838 const payload_ty = err_union_ty.errorUnionPayload(mod);
8828 const operand_pointer_ty = try mod.ptrType(.{
8839 const operand_pointer_ty = try sema.ptrType(.{
88298840 .child = payload_ty.toIntern(),
88308841 .flags = .{
88318842 .is_const = operand_ty.isConstPtr(mod),
......@@ -10680,7 +10691,7 @@ const SwitchProngAnalysis = struct {
1068010691 const union_obj = mod.typeToUnion(operand_ty).?;
1068110692 const field_ty = union_obj.field_types.get(ip)[field_index].toType();
1068210693 if (capture_byref) {
10683 const ptr_field_ty = try mod.ptrType(.{
10694 const ptr_field_ty = try sema.ptrType(.{
1068410695 .child = field_ty.toIntern(),
1068510696 .flags = .{
1068610697 .is_const = !operand_ptr_ty.ptrIsMutable(mod),
......@@ -10786,7 +10797,7 @@ const SwitchProngAnalysis = struct {
1078610797 // By-reference captures have some further restrictions which make them easier to emit
1078710798 if (capture_byref) {
1078810799 const operand_ptr_info = operand_ptr_ty.ptrInfo(mod);
10789 const capture_ptr_ty = try mod.ptrType(.{
10800 const capture_ptr_ty = try sema.ptrType(.{
1079010801 .child = capture_ty.toIntern(),
1079110802 .flags = .{
1079210803 // TODO: alignment!
......@@ -10800,7 +10811,7 @@ const SwitchProngAnalysis = struct {
1080010811 // pointer type is in-memory coercible to the capture pointer type.
1080110812 if (!same_types) {
1080210813 for (field_tys, 0..) |field_ty, i| {
10803 const field_ptr_ty = try mod.ptrType(.{
10814 const field_ptr_ty = try sema.ptrType(.{
1080410815 .child = field_ty.toIntern(),
1080510816 .flags = .{
1080610817 // TODO: alignment!
......@@ -12953,9 +12964,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1295312964 }
1295412965 },
1295512966 .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);
12967 break :hf struct_type.nameIndex(ip, field_name) != null;
1295912968 },
1296012969 .union_type => |union_type| {
1296112970 const union_obj = ip.loadUnionType(union_type);
......@@ -13025,9 +13034,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1302513034 };
1302613035 try mod.semaFile(result.file);
1302713036 const file_root_decl_index = result.file.root_decl.unwrap().?;
13028 const file_root_decl = mod.declPtr(file_root_decl_index);
13029 try mod.declareDeclDependency(sema.owner_decl_index, file_root_decl_index);
13030 return Air.internedToRef(file_root_decl.val.toIntern());
13037 return sema.analyzeDeclVal(block, operand_src, file_root_decl_index);
1303113038}
1303213039
1303313040fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -13766,12 +13773,12 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1376613773 try sema.requireRuntimeBlock(block, src, runtime_src);
1376713774
1376813775 if (ptr_addrspace) |ptr_as| {
13769 const alloc_ty = try mod.ptrType(.{
13776 const alloc_ty = try sema.ptrType(.{
1377013777 .child = result_ty.toIntern(),
1377113778 .flags = .{ .address_space = ptr_as },
1377213779 });
1377313780 const alloc = try block.addTy(.alloc, alloc_ty);
13774 const elem_ptr_ty = try mod.ptrType(.{
13781 const elem_ptr_ty = try sema.ptrType(.{
1377513782 .child = resolved_elem_ty.toIntern(),
1377613783 .flags = .{ .address_space = ptr_as },
1377713784 });
......@@ -14031,12 +14038,12 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1403114038 try sema.requireRuntimeBlock(block, src, lhs_src);
1403214039
1403314040 if (ptr_addrspace) |ptr_as| {
14034 const alloc_ty = try mod.ptrType(.{
14041 const alloc_ty = try sema.ptrType(.{
1403514042 .child = result_ty.toIntern(),
1403614043 .flags = .{ .address_space = ptr_as },
1403714044 });
1403814045 const alloc = try block.addTy(.alloc, alloc_ty);
14039 const elem_ptr_ty = try mod.ptrType(.{
14046 const elem_ptr_ty = try sema.ptrType(.{
1404014047 .child = lhs_info.elem_type.toIntern(),
1404114048 .flags = .{ .address_space = ptr_as },
1404214049 });
......@@ -15978,7 +15985,7 @@ fn analyzePtrArithmetic(
1597815985 ));
1597915986 assert(new_align != .none);
1598015987
15981 break :t try mod.ptrType(.{
15988 break :t try sema.ptrType(.{
1598215989 .child = ptr_info.child,
1598315990 .sentinel = ptr_info.sentinel,
1598415991 .flags = .{
......@@ -16881,7 +16888,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1688116888 .none, // default alignment
1688216889 );
1688316890 break :v try mod.intern(.{ .ptr = .{
16884 .ty = (try mod.ptrType(.{
16891 .ty = (try sema.ptrType(.{
1688516892 .child = param_info_ty.toIntern(),
1688616893 .flags = .{
1688716894 .size = .Slice,
......@@ -16907,7 +16914,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1690716914 // calling_convention: CallingConvention,
1690816915 (try mod.enumValueFieldIndex(callconv_ty, @intFromEnum(func_ty_info.cc))).toIntern(),
1690916916 // alignment: comptime_int,
16910 (try mod.intValue(Type.comptime_int, ty.abiAlignment(mod))).toIntern(),
16917 (try mod.intValue(Type.comptime_int, ty.abiAlignment(mod).toByteUnits(0))).toIntern(),
1691116918 // is_generic: bool,
1691216919 Value.makeBool(func_ty_info.is_generic).toIntern(),
1691316920 // is_var_args: bool,
......@@ -17200,7 +17207,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1720017207 };
1720117208
1720217209 // Build our ?[]const Error value
17203 const slice_errors_ty = try mod.ptrType(.{
17210 const slice_errors_ty = try sema.ptrType(.{
1720417211 .child = error_field_ty.toIntern(),
1720517212 .flags = .{
1720617213 .size = .Slice,
......@@ -17349,7 +17356,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1734917356 .none, // default alignment
1735017357 );
1735117358 break :v try mod.intern(.{ .ptr = .{
17352 .ty = (try mod.ptrType(.{
17359 .ty = (try sema.ptrType(.{
1735317360 .child = enum_field_ty.toIntern(),
1735417361 .flags = .{
1735517362 .size = .Slice,
......@@ -17461,7 +17468,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1746117468
1746217469 const alignment = switch (layout) {
1746317470 .Auto, .Extern => try sema.unionFieldAlignment(union_obj, @intCast(i)),
17464 .Packed => 0,
17471 .Packed => .none,
1746517472 };
1746617473
1746717474 const field_ty = union_obj.field_types.get(ip)[i];
......@@ -17471,7 +17478,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1747117478 // type: type,
1747217479 field_ty,
1747317480 // alignment: comptime_int,
17474 (try mod.intValue(Type.comptime_int, alignment)).toIntern(),
17481 (try mod.intValue(Type.comptime_int, alignment.toByteUnits(0))).toIntern(),
1747517482 };
1747617483 field_val.* = try mod.intern(.{ .aggregate = .{
1747717484 .ty = union_field_ty.toIntern(),
......@@ -17493,7 +17500,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1749317500 .none, // default alignment
1749417501 );
1749517502 break :v try mod.intern(.{ .ptr = .{
17496 .ty = (try mod.ptrType(.{
17503 .ty = (try sema.ptrType(.{
1749717504 .child = union_field_ty.toIntern(),
1749817505 .flags = .{
1749917506 .size = .Slice,
......@@ -17578,7 +17585,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1757817585 };
1757917586
1758017587 try sema.resolveTypeLayout(ty); // Getting alignment requires type layout
17581 const layout = ty.containerLayout(mod);
1758217588
1758317589 var struct_field_vals: []InternPool.Index = &.{};
1758417590 defer gpa.free(struct_field_vals);
......@@ -17633,7 +17639,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1763317639 // is_comptime: bool,
1763417640 Value.makeBool(is_comptime).toIntern(),
1763517641 // alignment: comptime_int,
17636 (try mod.intValue(Type.comptime_int, field_ty.toType().abiAlignment(mod))).toIntern(),
17642 (try mod.intValue(Type.comptime_int, field_ty.toType().abiAlignment(mod).toByteUnits(0))).toIntern(),
1763717643 };
1763817644 struct_field_val.* = try mod.intern(.{ .aggregate = .{
1763917645 .ty = struct_field_ty.toIntern(),
......@@ -17645,16 +17651,17 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1764517651 .struct_type => |s| s,
1764617652 else => unreachable,
1764717653 };
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| {
17654 struct_field_vals = try gpa.alloc(InternPool.Index, struct_type.field_types.len);
17655
17656 for (struct_field_vals, 0..) |*field_val, i| {
1765617657 // TODO: write something like getCoercedInts to avoid needing to dupe
17657 const name = try sema.arena.dupe(u8, ip.stringToSlice(name_nts));
17658 const name = if (struct_type.fieldName(ip, i).unwrap()) |name_nts|
17659 try sema.arena.dupe(u8, ip.stringToSlice(name_nts))
17660 else
17661 try std.fmt.allocPrintZ(gpa, "{d}", .{i});
17662 const field_ty = struct_type.field_types.get(ip)[i].toType();
17663 const field_init = struct_type.fieldInit(ip, i);
17664 const field_is_comptime = struct_type.fieldIsComptime(ip, i);
1765817665 const name_val = v: {
1765917666 var anon_decl = try block.startAnonDecl();
1766017667 defer anon_decl.deinit();
......@@ -17677,24 +17684,28 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1767717684 } });
1767817685 };
1767917686
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);
17687 const opt_default_val = if (field_init == .none) null else field_init.toValue();
17688 const default_val_ptr = try sema.optRefValue(block, field_ty, opt_default_val);
17689 const alignment = switch (struct_type.layout) {
17690 .Packed => .none,
17691 else => try sema.structFieldAlignment(
17692 struct_type.fieldAlign(ip, i),
17693 field_ty,
17694 struct_type.layout,
17695 ),
17696 };
1768617697
1768717698 const struct_field_fields = .{
1768817699 // name: []const u8,
1768917700 name_val,
1769017701 // type: type,
17691 field.ty.toIntern(),
17702 field_ty.toIntern(),
1769217703 // default_value: ?*const anyopaque,
1769317704 default_val_ptr.toIntern(),
1769417705 // is_comptime: bool,
17695 Value.makeBool(field.is_comptime).toIntern(),
17706 Value.makeBool(field_is_comptime).toIntern(),
1769617707 // alignment: comptime_int,
17697 (try mod.intValue(Type.comptime_int, alignment)).toIntern(),
17708 (try mod.intValue(Type.comptime_int, alignment.toByteUnits(0))).toIntern(),
1769817709 };
1769917710 field_val.* = try mod.intern(.{ .aggregate = .{
1770017711 .ty = struct_field_ty.toIntern(),
......@@ -17717,7 +17728,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1771717728 .none, // default alignment
1771817729 );
1771917730 break :v try mod.intern(.{ .ptr = .{
17720 .ty = (try mod.ptrType(.{
17731 .ty = (try sema.ptrType(.{
1772117732 .child = struct_field_ty.toIntern(),
1772217733 .flags = .{
1772317734 .size = .Slice,
......@@ -17733,11 +17744,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1773317744
1773417745 const backing_integer_val = try mod.intern(.{ .opt = .{
1773517746 .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();
17747 .val = if (mod.typeToPackedStruct(ty)) |packed_struct| val: {
17748 assert(packed_struct.backingIntType(ip).toType().isInt(mod));
17749 break :val packed_struct.backingIntType(ip).*;
1774117750 } else .none,
1774217751 } });
1774317752
......@@ -17754,6 +17763,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1775417763 break :t decl.val.toType();
1775517764 };
1775617765
17766 const layout = ty.containerLayout(mod);
17767
1775717768 const field_values = [_]InternPool.Index{
1775817769 // layout: ContainerLayout,
1775917770 (try mod.enumValueFieldIndex(container_layout_ty, @intFromEnum(layout))).toIntern(),
......@@ -17863,7 +17874,7 @@ fn typeInfoDecls(
1786317874 .none, // default alignment
1786417875 );
1786517876 return try mod.intern(.{ .ptr = .{
17866 .ty = (try mod.ptrType(.{
17877 .ty = (try sema.ptrType(.{
1786717878 .child = declaration_ty.toIntern(),
1786817879 .flags = .{
1786917880 .size = .Slice,
......@@ -18433,7 +18444,7 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr
1843318444
1843418445 const operand_ty = sema.typeOf(operand);
1843518446 const ptr_info = operand_ty.ptrInfo(mod);
18436 const res_ty = try mod.ptrType(.{
18447 const res_ty = try sema.ptrType(.{
1843718448 .child = err_union_ty.errorUnionPayload(mod).toIntern(),
1843818449 .flags = .{
1843918450 .is_const = ptr_info.flags.is_const,
......@@ -18924,9 +18935,8 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1892418935 },
1892518936 else => {},
1892618937 }
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);
18938 const align_bytes = (try val.getUnsignedIntAdvanced(mod, sema)).?;
18939 break :blk try sema.validateAlignAllowZero(block, align_src, align_bytes);
1893018940 } else .none;
1893118941
1893218942 const address_space: std.builtin.AddressSpace = if (inst_data.flags.has_addrspace) blk: {
......@@ -18988,7 +18998,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1898818998 }
1898918999 }
1899019000
18991 const ty = try mod.ptrType(.{
19001 const ty = try sema.ptrType(.{
1899219002 .child = elem_ty.toIntern(),
1899319003 .sentinel = sentinel,
1899419004 .flags = .{
......@@ -19226,7 +19236,7 @@ fn zirStructInit(
1922619236
1922719237 if (is_ref) {
1922819238 const target = mod.getTarget();
19229 const alloc_ty = try mod.ptrType(.{
19239 const alloc_ty = try sema.ptrType(.{
1923019240 .child = resolved_ty.toIntern(),
1923119241 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
1923219242 });
......@@ -19291,12 +19301,12 @@ fn finishStructInit(
1929119301 }
1929219302 },
1929319303 .struct_type => |struct_type| {
19294 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
19295 for (struct_obj.fields.values(), 0..) |field, i| {
19304 for (0..struct_type.field_types.len) |i| {
1929619305 if (field_inits[i] != .none) continue;
1929719306
19298 if (field.default_val == .none) {
19299 const field_name = struct_obj.fields.keys()[i];
19307 const field_init = struct_type.fieldInit(ip, i);
19308 if (field_init == .none) {
19309 const field_name = struct_type.field_names.get(ip)[i];
1930019310 const template = "missing struct field: {}";
1930119311 const args = .{field_name.fmt(ip)};
1930219312 if (root_msg) |msg| {
......@@ -19305,7 +19315,7 @@ fn finishStructInit(
1930519315 root_msg = try sema.errMsg(block, init_src, template, args);
1930619316 }
1930719317 } else {
19308 field_inits[i] = Air.internedToRef(field.default_val);
19318 field_inits[i] = Air.internedToRef(field_init);
1930919319 }
1931019320 }
1931119321 },
......@@ -19313,10 +19323,11 @@ fn finishStructInit(
1931319323 }
1931419324
1931519325 if (root_msg) |msg| {
19316 if (mod.typeToStruct(struct_ty)) |struct_obj| {
19317 const fqn = try struct_obj.getFullyQualifiedName(mod);
19326 if (mod.typeToStruct(struct_ty)) |struct_type| {
19327 const decl = mod.declPtr(struct_type.decl.unwrap().?);
19328 const fqn = try decl.getFullyQualifiedName(mod);
1931819329 try mod.errNoteNonLazy(
19319 struct_obj.srcLoc(mod),
19330 decl.srcLoc(mod),
1932019331 msg,
1932119332 "struct '{}' declared here",
1932219333 .{fqn.fmt(ip)},
......@@ -19349,7 +19360,7 @@ fn finishStructInit(
1934919360 if (is_ref) {
1935019361 try sema.resolveStructLayout(struct_ty);
1935119362 const target = sema.mod.getTarget();
19352 const alloc_ty = try mod.ptrType(.{
19363 const alloc_ty = try sema.ptrType(.{
1935319364 .child = struct_ty.toIntern(),
1935419365 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
1935519366 });
......@@ -19502,7 +19513,7 @@ fn structInitAnon(
1950219513
1950319514 if (is_ref) {
1950419515 const target = mod.getTarget();
19505 const alloc_ty = try mod.ptrType(.{
19516 const alloc_ty = try sema.ptrType(.{
1950619517 .child = tuple_ty,
1950719518 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
1950819519 });
......@@ -19516,7 +19527,7 @@ fn structInitAnon(
1951619527 };
1951719528 extra_index = item.end;
1951819529
19519 const field_ptr_ty = try mod.ptrType(.{
19530 const field_ptr_ty = try sema.ptrType(.{
1952019531 .child = field_ty,
1952119532 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
1952219533 });
......@@ -19640,7 +19651,7 @@ fn zirArrayInit(
1964019651
1964119652 if (is_ref) {
1964219653 const target = mod.getTarget();
19643 const alloc_ty = try mod.ptrType(.{
19654 const alloc_ty = try sema.ptrType(.{
1964419655 .child = array_ty.toIntern(),
1964519656 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
1964619657 });
......@@ -19648,7 +19659,7 @@ fn zirArrayInit(
1964819659
1964919660 if (array_ty.isTuple(mod)) {
1965019661 for (resolved_args, 0..) |arg, i| {
19651 const elem_ptr_ty = try mod.ptrType(.{
19662 const elem_ptr_ty = try sema.ptrType(.{
1965219663 .child = array_ty.structFieldType(i, mod).toIntern(),
1965319664 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
1965419665 });
......@@ -19661,7 +19672,7 @@ fn zirArrayInit(
1966119672 return sema.makePtrConst(block, alloc);
1966219673 }
1966319674
19664 const elem_ptr_ty = try mod.ptrType(.{
19675 const elem_ptr_ty = try sema.ptrType(.{
1966519676 .child = array_ty.elemType2(mod).toIntern(),
1966619677 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
1966719678 });
......@@ -19749,14 +19760,14 @@ fn arrayInitAnon(
1974919760
1975019761 if (is_ref) {
1975119762 const target = sema.mod.getTarget();
19752 const alloc_ty = try mod.ptrType(.{
19763 const alloc_ty = try sema.ptrType(.{
1975319764 .child = tuple_ty,
1975419765 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
1975519766 });
1975619767 const alloc = try block.addTy(.alloc, alloc_ty);
1975719768 for (operands, 0..) |operand, i_usize| {
1975819769 const i: u32 = @intCast(i_usize);
19759 const field_ptr_ty = try mod.ptrType(.{
19770 const field_ptr_ty = try sema.ptrType(.{
1976019771 .child = types[i],
1976119772 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
1976219773 });
......@@ -19848,10 +19859,10 @@ fn fieldType(
1984819859 return Air.internedToRef(anon_struct.types.get(ip)[field_index]);
1984919860 },
1985019861 .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());
19862 const field_index = struct_type.nameIndex(ip, field_name) orelse
19863 return sema.failWithBadStructFieldAccess(block, struct_type, field_src, field_name);
19864 const field_ty = struct_type.field_types.get(ip)[field_index];
19865 return Air.internedToRef(field_ty);
1985519866 },
1985619867 else => unreachable,
1985719868 },
......@@ -20167,14 +20178,14 @@ fn zirReify(
2016720178 .AnyFrame => return sema.failWithUseOfAsync(block, src),
2016820179 .EnumLiteral => return .enum_literal_type,
2016920180 .Int => {
20170 const fields = ip.typeOf(union_val.val).toType().structFields(mod);
20181 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
2017120182 const signedness_val = try union_val.val.toValue().fieldValue(
2017220183 mod,
20173 fields.getIndex(try ip.getOrPutString(gpa, "signedness")).?,
20184 struct_type.nameIndex(ip, try ip.getOrPutString(gpa, "signedness")).?,
2017420185 );
2017520186 const bits_val = try union_val.val.toValue().fieldValue(
2017620187 mod,
20177 fields.getIndex(try ip.getOrPutString(gpa, "bits")).?,
20188 struct_type.nameIndex(ip, try ip.getOrPutString(gpa, "bits")).?,
2017820189 );
2017920190
2018020191 const signedness = mod.toEnum(std.builtin.Signedness, signedness_val);
......@@ -20183,11 +20194,13 @@ fn zirReify(
2018320194 return Air.internedToRef(ty.toIntern());
2018420195 },
2018520196 .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(
20197 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20198 const len_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20199 ip,
2018820200 try ip.getOrPutString(gpa, "len"),
2018920201 ).?);
20190 const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20202 const child_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20203 ip,
2019120204 try ip.getOrPutString(gpa, "child"),
2019220205 ).?);
2019320206
......@@ -20203,8 +20216,9 @@ fn zirReify(
2020320216 return Air.internedToRef(ty.toIntern());
2020420217 },
2020520218 .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(
20219 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20220 const bits_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20221 ip,
2020820222 try ip.getOrPutString(gpa, "bits"),
2020920223 ).?);
2021020224
......@@ -20220,29 +20234,37 @@ fn zirReify(
2022020234 return Air.internedToRef(ty.toIntern());
2022120235 },
2022220236 .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(
20237 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20238 const size_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20239 ip,
2022520240 try ip.getOrPutString(gpa, "size"),
2022620241 ).?);
20227 const is_const_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20242 const is_const_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20243 ip,
2022820244 try ip.getOrPutString(gpa, "is_const"),
2022920245 ).?);
20230 const is_volatile_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20246 const is_volatile_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20247 ip,
2023120248 try ip.getOrPutString(gpa, "is_volatile"),
2023220249 ).?);
20233 const alignment_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20250 const alignment_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20251 ip,
2023420252 try ip.getOrPutString(gpa, "alignment"),
2023520253 ).?);
20236 const address_space_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20254 const address_space_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20255 ip,
2023720256 try ip.getOrPutString(gpa, "address_space"),
2023820257 ).?);
20239 const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20258 const child_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20259 ip,
2024020260 try ip.getOrPutString(gpa, "child"),
2024120261 ).?);
20242 const is_allowzero_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20262 const is_allowzero_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20263 ip,
2024320264 try ip.getOrPutString(gpa, "is_allowzero"),
2024420265 ).?);
20245 const sentinel_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20266 const sentinel_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20267 ip,
2024620268 try ip.getOrPutString(gpa, "sentinel"),
2024720269 ).?);
2024820270
......@@ -20307,7 +20329,7 @@ fn zirReify(
2030720329 }
2030820330 }
2030920331
20310 const ty = try mod.ptrType(.{
20332 const ty = try sema.ptrType(.{
2031120333 .child = elem_ty.toIntern(),
2031220334 .sentinel = actual_sentinel,
2031320335 .flags = .{
......@@ -20322,14 +20344,17 @@ fn zirReify(
2032220344 return Air.internedToRef(ty.toIntern());
2032320345 },
2032420346 .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(
20347 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20348 const len_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20349 ip,
2032720350 try ip.getOrPutString(gpa, "len"),
2032820351 ).?);
20329 const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20352 const child_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20353 ip,
2033020354 try ip.getOrPutString(gpa, "child"),
2033120355 ).?);
20332 const sentinel_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20356 const sentinel_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20357 ip,
2033320358 try ip.getOrPutString(gpa, "sentinel"),
2033420359 ).?);
2033520360
......@@ -20348,8 +20373,9 @@ fn zirReify(
2034820373 return Air.internedToRef(ty.toIntern());
2034920374 },
2035020375 .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(
20376 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20377 const child_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20378 ip,
2035320379 try ip.getOrPutString(gpa, "child"),
2035420380 ).?);
2035520381
......@@ -20359,11 +20385,13 @@ fn zirReify(
2035920385 return Air.internedToRef(ty.toIntern());
2036020386 },
2036120387 .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(
20388 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20389 const error_set_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20390 ip,
2036420391 try ip.getOrPutString(gpa, "error_set"),
2036520392 ).?);
20366 const payload_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20393 const payload_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20394 ip,
2036720395 try ip.getOrPutString(gpa, "payload"),
2036820396 ).?);
2036920397
......@@ -20386,8 +20414,9 @@ fn zirReify(
2038620414 try names.ensureUnusedCapacity(sema.arena, len);
2038720415 for (0..len) |i| {
2038820416 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(
20417 const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type;
20418 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
20419 ip,
2039120420 try ip.getOrPutString(gpa, "name"),
2039220421 ).?);
2039320422
......@@ -20405,20 +20434,25 @@ fn zirReify(
2040520434 return Air.internedToRef(ty.toIntern());
2040620435 },
2040720436 .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(
20437 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20438 const layout_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20439 ip,
2041020440 try ip.getOrPutString(gpa, "layout"),
2041120441 ).?);
20412 const backing_integer_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20442 const backing_integer_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20443 ip,
2041320444 try ip.getOrPutString(gpa, "backing_integer"),
2041420445 ).?);
20415 const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20446 const fields_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20447 ip,
2041620448 try ip.getOrPutString(gpa, "fields"),
2041720449 ).?);
20418 const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20450 const decls_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20451 ip,
2041920452 try ip.getOrPutString(gpa, "decls"),
2042020453 ).?);
20421 const is_tuple_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20454 const is_tuple_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20455 ip,
2042220456 try ip.getOrPutString(gpa, "is_tuple"),
2042320457 ).?);
2042420458
......@@ -20436,17 +20470,21 @@ fn zirReify(
2043620470 return try sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_val, name_strategy, is_tuple_val.toBool());
2043720471 },
2043820472 .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(
20473 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20474 const tag_type_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20475 ip,
2044120476 try ip.getOrPutString(gpa, "tag_type"),
2044220477 ).?);
20443 const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20478 const fields_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20479 ip,
2044420480 try ip.getOrPutString(gpa, "fields"),
2044520481 ).?);
20446 const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20482 const decls_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20483 ip,
2044720484 try ip.getOrPutString(gpa, "decls"),
2044820485 ).?);
20449 const is_exhaustive_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20486 const is_exhaustive_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20487 ip,
2045020488 try ip.getOrPutString(gpa, "is_exhaustive"),
2045120489 ).?);
2045220490
......@@ -20496,11 +20534,13 @@ fn zirReify(
2049620534
2049720535 for (0..fields_len) |field_i| {
2049820536 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(
20537 const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type;
20538 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
20539 ip,
2050120540 try ip.getOrPutString(gpa, "name"),
2050220541 ).?);
20503 const value_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
20542 const value_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
20543 ip,
2050420544 try ip.getOrPutString(gpa, "value"),
2050520545 ).?);
2050620546
......@@ -20515,7 +20555,7 @@ fn zirReify(
2051520555 });
2051620556 }
2051720557
20518 if (try incomplete_enum.addFieldName(ip, gpa, field_name)) |other_index| {
20558 if (incomplete_enum.addFieldName(ip, field_name)) |other_index| {
2051920559 const msg = msg: {
2052020560 const msg = try sema.errMsg(block, src, "duplicate enum field '{}'", .{
2052120561 field_name.fmt(ip),
......@@ -20528,7 +20568,7 @@ fn zirReify(
2052820568 return sema.failWithOwnedErrorMsg(block, msg);
2052920569 }
2053020570
20531 if (try incomplete_enum.addFieldValue(ip, gpa, (try mod.getCoerced(value_val, int_tag_ty)).toIntern())) |other| {
20571 if (incomplete_enum.addFieldValue(ip, (try mod.getCoerced(value_val, int_tag_ty)).toIntern())) |other| {
2053220572 const msg = msg: {
2053320573 const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{value_val.fmtValue(Type.comptime_int, mod)});
2053420574 errdefer msg.destroy(gpa);
......@@ -20545,8 +20585,9 @@ fn zirReify(
2054520585 return decl_val;
2054620586 },
2054720587 .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(
20588 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20589 const decls_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20590 ip,
2055020591 try ip.getOrPutString(gpa, "decls"),
2055120592 ).?);
2055220593
......@@ -20594,17 +20635,21 @@ fn zirReify(
2059420635 return decl_val;
2059520636 },
2059620637 .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(
20638 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20639 const layout_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20640 ip,
2059920641 try ip.getOrPutString(gpa, "layout"),
2060020642 ).?);
20601 const tag_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20643 const tag_type_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20644 ip,
2060220645 try ip.getOrPutString(gpa, "tag_type"),
2060320646 ).?);
20604 const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20647 const fields_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20648 ip,
2060520649 try ip.getOrPutString(gpa, "fields"),
2060620650 ).?);
20607 const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20651 const decls_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20652 ip,
2060820653 try ip.getOrPutString(gpa, "decls"),
2060920654 ).?);
2061020655
......@@ -20644,14 +20689,17 @@ fn zirReify(
2064420689
2064520690 for (0..fields_len) |i| {
2064620691 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(
20692 const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type;
20693 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
20694 ip,
2064920695 try ip.getOrPutString(gpa, "name"),
2065020696 ).?);
20651 const type_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
20697 const type_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
20698 ip,
2065220699 try ip.getOrPutString(gpa, "type"),
2065320700 ).?);
20654 const alignment_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
20701 const alignment_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
20702 ip,
2065520703 try ip.getOrPutString(gpa, "alignment"),
2065620704 ).?);
2065720705
......@@ -20812,23 +20860,29 @@ fn zirReify(
2081220860 return decl_val;
2081320861 },
2081420862 .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(
20863 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20864 const calling_convention_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20865 ip,
2081720866 try ip.getOrPutString(gpa, "calling_convention"),
2081820867 ).?);
20819 const alignment_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20868 const alignment_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20869 ip,
2082020870 try ip.getOrPutString(gpa, "alignment"),
2082120871 ).?);
20822 const is_generic_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20872 const is_generic_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20873 ip,
2082320874 try ip.getOrPutString(gpa, "is_generic"),
2082420875 ).?);
20825 const is_var_args_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20876 const is_var_args_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20877 ip,
2082620878 try ip.getOrPutString(gpa, "is_var_args"),
2082720879 ).?);
20828 const return_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20880 const return_type_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20881 ip,
2082920882 try ip.getOrPutString(gpa, "return_type"),
2083020883 ).?);
20831 const params_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
20884 const params_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20885 ip,
2083220886 try ip.getOrPutString(gpa, "params"),
2083320887 ).?);
2083420888
......@@ -20844,15 +20898,9 @@ fn zirReify(
2084420898 }
2084520899
2084620900 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 }
20901 const alignment = try sema.validateAlignAllowZero(block, src, alignment_val.toUnsignedInt(mod));
20902 const default = target_util.defaultFunctionAlignment(target);
20903 break :alignment if (alignment == default) .none else alignment;
2085620904 };
2085720905 const return_type = return_type_val.optionalValue(mod) orelse
2085820906 return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{});
......@@ -20863,14 +20911,17 @@ fn zirReify(
2086320911 var noalias_bits: u32 = 0;
2086420912 for (param_types, 0..) |*param_type, i| {
2086520913 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(
20914 const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type;
20915 const param_is_generic_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
20916 ip,
2086820917 try ip.getOrPutString(gpa, "is_generic"),
2086920918 ).?);
20870 const param_is_noalias_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
20919 const param_is_noalias_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
20920 ip,
2087120921 try ip.getOrPutString(gpa, "is_noalias"),
2087220922 ).?);
20873 const opt_param_type_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
20923 const opt_param_type_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
20924 ip,
2087420925 try ip.getOrPutString(gpa, "type"),
2087520926 ).?);
2087620927
......@@ -20931,6 +20982,8 @@ fn reifyStruct(
2093120982 .Auto => {},
2093220983 };
2093320984
20985 const fields_len: u32 = @intCast(try sema.usizeCast(block, src, fields_val.sliceLen(mod)));
20986
2093420987 // Because these three things each reference each other, `undefined`
2093520988 // placeholders are used before being set after the struct type gains an
2093620989 // InternPool index.
......@@ -20946,58 +20999,52 @@ fn reifyStruct(
2094620999 mod.abortAnonDecl(new_decl_index);
2094721000 }
2094821001
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 = .{},
21002 const ty = try ip.getStructType(gpa, .{
21003 .decl = new_decl_index,
21004 .namespace = .none,
2096021005 .zir_index = inst,
2096121006 .layout = layout,
20962 .status = .have_field_types,
2096321007 .known_non_opv = false,
21008 .fields_len = fields_len,
21009 .requires_comptime = .unknown,
2096421010 .is_tuple = is_tuple,
20965 .namespace = new_namespace_index,
21011 // So that we don't have to scan ahead, we allocate space in the struct
21012 // type for alignments, comptime fields, and default inits. This might
21013 // result in wasted space, however, this is a permitted encoding of
21014 // struct types.
21015 .any_comptime_fields = true,
21016 .any_default_inits = true,
21017 .any_aligned_fields = true,
2096621018 });
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 } });
2097421019 // TODO: figure out InternPool removals for incremental compilation
20975 //errdefer ip.remove(struct_ty);
21020 //errdefer ip.remove(ty);
21021 const struct_type = ip.indexToKey(ty).struct_type;
2097621022
2097721023 new_decl.ty = Type.type;
20978 new_decl.val = struct_ty.toValue();
20979 new_namespace.ty = struct_ty.toType();
21024 new_decl.val = ty.toValue();
2098021025
2098121026 // 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) {
21027 for (0..fields_len) |i| {
2098621028 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(
21029 const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type;
21030 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21031 ip,
2098921032 try ip.getOrPutString(gpa, "name"),
2099021033 ).?);
20991 const type_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
21034 const type_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21035 ip,
2099221036 try ip.getOrPutString(gpa, "type"),
2099321037 ).?);
20994 const default_value_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
21038 const default_value_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21039 ip,
2099521040 try ip.getOrPutString(gpa, "default_value"),
2099621041 ).?);
20997 const is_comptime_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
21042 const is_comptime_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21043 ip,
2099821044 try ip.getOrPutString(gpa, "is_comptime"),
2099921045 ).?);
21000 const alignment_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
21046 const alignment_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21047 ip,
2100121048 try ip.getOrPutString(gpa, "alignment"),
2100221049 ).?);
2100321050
......@@ -21009,6 +21056,8 @@ fn reifyStruct(
2100921056 if (layout == .Packed) {
2101021057 if (abi_align != 0) return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{});
2101121058 if (is_comptime_val.toBool()) return sema.fail(block, src, "packed struct fields cannot be marked comptime", .{});
21059 } else {
21060 struct_type.field_aligns.get(ip)[i] = Alignment.fromByteUnits(abi_align);
2101221061 }
2101321062 if (layout == .Extern and is_comptime_val.toBool()) {
2101421063 return sema.fail(block, src, "extern struct fields cannot be marked comptime", .{});
......@@ -21032,10 +21081,8 @@ fn reifyStruct(
2103221081 .{field_index},
2103321082 );
2103421083 }
21035 }
21036 const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);
21037 if (gop.found_existing) {
21038 // TODO: better source location
21084 } else if (struct_type.addFieldName(ip, field_name)) |prev_index| {
21085 _ = prev_index; // TODO: better source location
2103921086 return sema.fail(block, src, "duplicate struct field {}", .{field_name.fmt(ip)});
2104021087 }
2104121088
......@@ -21051,13 +21098,10 @@ fn reifyStruct(
2105121098 return sema.fail(block, src, "comptime field without default initialization value", .{});
2105221099 }
2105321100
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 };
21101 struct_type.field_types.get(ip)[i] = field_ty.toIntern();
21102 struct_type.field_inits.get(ip)[i] = default_val;
21103 if (is_comptime_val.toBool())
21104 struct_type.setFieldComptime(ip, i);
2106121105
2106221106 if (field_ty.zigTypeTag(mod) == .Opaque) {
2106321107 const msg = msg: {
......@@ -21079,7 +21123,7 @@ fn reifyStruct(
2107921123 };
2108021124 return sema.failWithOwnedErrorMsg(block, msg);
2108121125 }
21082 if (struct_obj.layout == .Extern and !try sema.validateExternType(field_ty, .struct_field)) {
21126 if (layout == .Extern and !try sema.validateExternType(field_ty, .struct_field)) {
2108321127 const msg = msg: {
2108421128 const msg = try sema.errMsg(block, src, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
2108521129 errdefer msg.destroy(gpa);
......@@ -21091,7 +21135,7 @@ fn reifyStruct(
2109121135 break :msg msg;
2109221136 };
2109321137 return sema.failWithOwnedErrorMsg(block, msg);
21094 } else if (struct_obj.layout == .Packed and !(validatePackedType(field_ty, mod))) {
21138 } else if (layout == .Packed and !(validatePackedType(field_ty, mod))) {
2109521139 const msg = msg: {
2109621140 const msg = try sema.errMsg(block, src, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
2109721141 errdefer msg.destroy(gpa);
......@@ -21107,13 +21151,12 @@ fn reifyStruct(
2110721151 }
2110821152
2110921153 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) {
21154 for (0..struct_type.field_types.len) |index| {
21155 const field_ty = struct_type.field_types.get(ip)[index].toType();
21156 sema.resolveTypeLayout(field_ty) catch |err| switch (err) {
2111421157 error.AnalysisFail => {
2111521158 const msg = sema.err orelse return err;
21116 try sema.addFieldErrNote(struct_ty.toType(), index, msg, "while checking this field", .{});
21159 try sema.addFieldErrNote(ty.toType(), index, msg, "while checking this field", .{});
2111721160 return err;
2111821161 },
2111921162 else => return err,
......@@ -21121,19 +21164,18 @@ fn reifyStruct(
2112121164 }
2112221165
2112321166 var fields_bit_sum: u64 = 0;
21124 for (struct_obj.fields.values()) |field| {
21125 fields_bit_sum += field.ty.bitSize(mod);
21167 for (struct_type.field_types.get(ip)) |field_ty| {
21168 fields_bit_sum += field_ty.toType().bitSize(mod);
2112621169 }
2112721170
21128 if (backing_int_val.optionalValue(mod)) |payload| {
21129 const backing_int_ty = payload.toType();
21171 if (backing_int_val.optionalValue(mod)) |backing_int_ty_val| {
21172 const backing_int_ty = backing_int_ty_val.toType();
2113021173 try sema.checkBackingIntType(block, src, backing_int_ty, fields_bit_sum);
21131 struct_obj.backing_int_ty = backing_int_ty;
21174 struct_type.backingIntType(ip).* = backing_int_ty.toIntern();
2113221175 } else {
21133 struct_obj.backing_int_ty = try mod.intType(.unsigned, @intCast(fields_bit_sum));
21176 const backing_int_ty = try mod.intType(.unsigned, @intCast(fields_bit_sum));
21177 struct_type.backingIntType(ip).* = backing_int_ty.toIntern();
2113421178 }
21135
21136 struct_obj.status = .have_layout;
2113721179 }
2113821180
2113921181 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
......@@ -21439,8 +21481,9 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
2143921481 const is_non_zero = try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize);
2144021482 try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null);
2144121483 }
21442 if (ptr_align > 1) {
21443 const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, ptr_align - 1)).toIntern());
21484 if (ptr_align.compare(.gt, .@"1")) {
21485 const align_bytes_minus_1 = ptr_align.toByteUnitsOptional().? - 1;
21486 const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, align_bytes_minus_1)).toIntern());
2144421487 const remainder = try block.addBinOp(.bit_and, operand_coerced, align_minus_1);
2144521488 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
2144621489 try sema.addSafetyCheck(block, src, is_aligned, .incorrect_alignment);
......@@ -21458,8 +21501,9 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
2145821501 const is_non_zero = try block.addBinOp(.cmp_neq, elem_coerced, .zero_usize);
2145921502 try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null);
2146021503 }
21461 if (ptr_align > 1) {
21462 const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, ptr_align - 1)).toIntern());
21504 if (ptr_align.compare(.gt, .@"1")) {
21505 const align_bytes_minus_1 = ptr_align.toByteUnitsOptional().? - 1;
21506 const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, align_bytes_minus_1)).toIntern());
2146321507 const remainder = try block.addBinOp(.bit_and, elem_coerced, align_minus_1);
2146421508 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
2146521509 try sema.addSafetyCheck(block, src, is_aligned, .incorrect_alignment);
......@@ -21476,12 +21520,19 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
2147621520 return block.addAggregateInit(dest_ty, new_elems);
2147721521}
2147821522
21479fn ptrFromIntVal(sema: *Sema, block: *Block, operand_src: LazySrcLoc, operand_val: Value, ptr_ty: Type, ptr_align: u32) !Value {
21523fn ptrFromIntVal(
21524 sema: *Sema,
21525 block: *Block,
21526 operand_src: LazySrcLoc,
21527 operand_val: Value,
21528 ptr_ty: Type,
21529 ptr_align: Alignment,
21530) !Value {
2148021531 const mod = sema.mod;
2148121532 const addr = operand_val.toUnsignedInt(mod);
2148221533 if (!ptr_ty.isAllowzeroPtr(mod) and addr == 0)
2148321534 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)
21535 if (addr != 0 and ptr_align != .none and !ptr_align.check(addr))
2148521536 return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{ptr_ty.fmt(sema.mod)});
2148621537
2148721538 return switch (ptr_ty.zigTypeTag(mod)) {
......@@ -21795,18 +21846,26 @@ fn ptrCastFull(
2179521846 // TODO: vector index?
2179621847 }
2179721848
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);
21849 const src_align = if (src_info.flags.alignment != .none)
21850 src_info.flags.alignment
21851 else
21852 src_info.child.toType().abiAlignment(mod);
21853
21854 const dest_align = if (dest_info.flags.alignment != .none)
21855 dest_info.flags.alignment
21856 else
21857 dest_info.child.toType().abiAlignment(mod);
21858
2180021859 if (!flags.align_cast) {
21801 if (dest_align > src_align) {
21860 if (dest_align.compare(.gt, src_align)) {
2180221861 return sema.failWithOwnedErrorMsg(block, msg: {
2180321862 const msg = try sema.errMsg(block, src, "cast increases pointer alignment", .{});
2180421863 errdefer msg.destroy(sema.gpa);
2180521864 try sema.errNote(block, operand_src, msg, "'{}' has alignment '{d}'", .{
21806 operand_ty.fmt(mod), src_align,
21865 operand_ty.fmt(mod), src_align.toByteUnits(0),
2180721866 });
2180821867 try sema.errNote(block, src, msg, "'{}' has alignment '{d}'", .{
21809 dest_ty.fmt(mod), dest_align,
21868 dest_ty.fmt(mod), dest_align.toByteUnits(0),
2181021869 });
2181121870 try sema.errNote(block, src, msg, "use @alignCast to assert pointer alignment", .{});
2181221871 break :msg msg;
......@@ -21874,7 +21933,7 @@ fn ptrCastFull(
2187421933 // Only convert to a many-pointer at first
2187521934 var info = dest_info;
2187621935 info.flags.size = .Many;
21877 const ty = try mod.ptrType(info);
21936 const ty = try sema.ptrType(info);
2187821937 if (dest_ty.zigTypeTag(mod) == .Optional) {
2187921938 break :blk try mod.optionalType(ty.toIntern());
2188021939 } else {
......@@ -21891,10 +21950,13 @@ fn ptrCastFull(
2189121950 if (!dest_ty.ptrAllowsZero(mod) and ptr_val.isNull(mod)) {
2189221951 return sema.fail(block, operand_src, "null pointer casted to type '{}'", .{dest_ty.fmt(mod)});
2189321952 }
21894 if (dest_align > src_align) {
21953 if (dest_align.compare(.gt, src_align)) {
2189521954 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 });
21955 if (!dest_align.check(addr)) {
21956 return sema.fail(block, operand_src, "pointer address 0x{X} is not aligned to {d} bytes", .{
21957 addr,
21958 dest_align.toByteUnitsOptional().?,
21959 });
2189821960 }
2189921961 }
2190021962 }
......@@ -21928,8 +21990,12 @@ fn ptrCastFull(
2192821990 try sema.addSafetyCheck(block, src, ok, .cast_to_null);
2192921991 }
2193021992
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());
21993 if (block.wantSafety() and
21994 dest_align.compare(.gt, src_align) and
21995 try sema.typeHasRuntimeBits(dest_info.child.toType()))
21996 {
21997 const align_bytes_minus_1 = dest_align.toByteUnitsOptional().? - 1;
21998 const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, align_bytes_minus_1)).toIntern());
2193321999 const ptr_int = try block.addUnOp(.int_from_ptr, ptr);
2193422000 const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1);
2193522001 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
......@@ -21946,7 +22012,7 @@ fn ptrCastFull(
2194622012 // We can't change address spaces with a bitcast, so this requires two instructions
2194722013 var intermediate_info = src_info;
2194822014 intermediate_info.flags.address_space = dest_info.flags.address_space;
21949 const intermediate_ptr_ty = try mod.ptrType(intermediate_info);
22015 const intermediate_ptr_ty = try sema.ptrType(intermediate_info);
2195022016 const intermediate_ty = if (dest_ptr_ty.zigTypeTag(mod) == .Optional) blk: {
2195122017 break :blk try mod.optionalType(intermediate_ptr_ty.toIntern());
2195222018 } else intermediate_ptr_ty;
......@@ -22002,7 +22068,7 @@ fn zirPtrCastNoDest(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst
2200222068 var ptr_info = operand_ty.ptrInfo(mod);
2200322069 if (flags.const_cast) ptr_info.flags.is_const = false;
2200422070 if (flags.volatile_cast) ptr_info.flags.is_volatile = false;
22005 const dest_ty = try mod.ptrType(ptr_info);
22071 const dest_ty = try sema.ptrType(ptr_info);
2200622072
2200722073 if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
2200822074 return Air.internedToRef((try mod.getCoerced(operand_val, dest_ty)).toIntern());
......@@ -22285,6 +22351,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6
2228522351 });
2228622352
2228722353 const mod = sema.mod;
22354 const ip = &mod.intern_pool;
2228822355 try sema.resolveTypeLayout(ty);
2228922356 switch (ty.zigTypeTag(mod)) {
2229022357 .Struct => {},
......@@ -22300,7 +22367,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6
2230022367 }
2230122368
2230222369 const field_index = if (ty.isTuple(mod)) blk: {
22303 if (mod.intern_pool.stringEqlSlice(field_name, "len")) {
22370 if (ip.stringEqlSlice(field_name, "len")) {
2230422371 return sema.fail(block, src, "no offset available for 'len' field of tuple", .{});
2230522372 }
2230622373 break :blk try sema.tupleFieldIndex(block, ty, field_name, rhs_src);
......@@ -22313,12 +22380,13 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6
2231322380 switch (ty.containerLayout(mod)) {
2231422381 .Packed => {
2231522382 var bit_sum: u64 = 0;
22316 const fields = ty.structFields(mod);
22317 for (fields.values(), 0..) |field, i| {
22383 const struct_type = ip.indexToKey(ty.toIntern()).struct_type;
22384 for (0..struct_type.field_types.len) |i| {
2231822385 if (i == field_index) {
2231922386 return bit_sum;
2232022387 }
22321 bit_sum += field.ty.bitSize(mod);
22388 const field_ty = struct_type.field_types.get(ip)[i].toType();
22389 bit_sum += field_ty.bitSize(mod);
2232222390 } else unreachable;
2232322391 },
2232422392 else => return ty.structFieldOffset(field_index, mod) * 8,
......@@ -22535,7 +22603,7 @@ fn checkAtomicPtrOperand(
2253522603 const ptr_data = switch (try ptr_ty.zigTypeTagOrPoison(mod)) {
2253622604 .Pointer => ptr_ty.ptrInfo(mod),
2253722605 else => {
22538 const wanted_ptr_ty = try mod.ptrType(wanted_ptr_data);
22606 const wanted_ptr_ty = try sema.ptrType(wanted_ptr_data);
2253922607 _ = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src);
2254022608 unreachable;
2254122609 },
......@@ -22545,7 +22613,7 @@ fn checkAtomicPtrOperand(
2254522613 wanted_ptr_data.flags.is_allowzero = ptr_data.flags.is_allowzero;
2254622614 wanted_ptr_data.flags.is_volatile = ptr_data.flags.is_volatile;
2254722615
22548 const wanted_ptr_ty = try mod.ptrType(wanted_ptr_data);
22616 const wanted_ptr_ty = try sema.ptrType(wanted_ptr_data);
2254922617 const casted_ptr = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src);
2255022618
2255122619 return casted_ptr;
......@@ -23717,8 +23785,8 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
2371723785 return sema.fail(block, src, "TODO handle packed structs/unions with @fieldParentPtr", .{});
2371823786 } else {
2371923787 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;
23788 if (mod.typeToStruct(parent_ty)) |struct_type| {
23789 break :blk struct_type.fieldAlign(ip, field_index);
2372223790 } else if (mod.typeToUnion(parent_ty)) |union_obj| {
2372323791 break :blk union_obj.fieldAlign(ip, field_index);
2372423792 } else {
......@@ -23727,11 +23795,11 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
2372723795 };
2372823796 }
2372923797
23730 const actual_field_ptr_ty = try mod.ptrType(ptr_ty_data);
23798 const actual_field_ptr_ty = try sema.ptrType(ptr_ty_data);
2373123799 const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, ptr_src);
2373223800
2373323801 ptr_ty_data.child = parent_ty.toIntern();
23734 const result_ptr = try mod.ptrType(ptr_ty_data);
23802 const result_ptr = try sema.ptrType(ptr_ty_data);
2373523803
2373623804 if (try sema.resolveDefinedValue(block, src, casted_field_ptr)) |field_ptr_val| {
2373723805 const field = switch (ip.indexToKey(field_ptr_val.toIntern())) {
......@@ -24062,7 +24130,7 @@ fn upgradeToArrayPtr(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, len: u64) !A
2406224130 // Already an array pointer.
2406324131 return ptr;
2406424132 }
24065 const new_ty = try mod.ptrType(.{
24133 const new_ty = try sema.ptrType(.{
2406624134 .child = (try mod.arrayType(.{
2406724135 .len = len,
2406824136 .sentinel = info.sentinel,
......@@ -24266,7 +24334,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
2426624334 assert(dest_manyptr_ty_key.flags.size == .One);
2426724335 dest_manyptr_ty_key.child = dest_elem_ty.toIntern();
2426824336 dest_manyptr_ty_key.flags.size = .Many;
24269 break :ptr try sema.coerceCompatiblePtrs(block, try mod.ptrType(dest_manyptr_ty_key), new_dest_ptr, dest_src);
24337 break :ptr try sema.coerceCompatiblePtrs(block, try sema.ptrType(dest_manyptr_ty_key), new_dest_ptr, dest_src);
2427024338 } else new_dest_ptr;
2427124339
2427224340 const new_src_ptr_ty = sema.typeOf(new_src_ptr);
......@@ -24277,7 +24345,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
2427724345 assert(src_manyptr_ty_key.flags.size == .One);
2427824346 src_manyptr_ty_key.child = src_elem_ty.toIntern();
2427924347 src_manyptr_ty_key.flags.size = .Many;
24280 break :ptr try sema.coerceCompatiblePtrs(block, try mod.ptrType(src_manyptr_ty_key), new_src_ptr, src_src);
24348 break :ptr try sema.coerceCompatiblePtrs(block, try sema.ptrType(src_manyptr_ty_key), new_src_ptr, src_src);
2428124349 } else new_src_ptr;
2428224350
2428324351 // ok1: dest >= src + len
......@@ -24528,13 +24596,9 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
2452824596 if (val.isGenericPoison()) {
2452924597 break :blk null;
2453024598 }
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 }
24599 const alignment = try sema.validateAlignAllowZero(block, align_src, val.toUnsignedInt(mod));
24600 const default = target_util.defaultFunctionAlignment(target);
24601 break :blk if (alignment == default) .none else alignment;
2453824602 } else if (extra.data.bits.has_align_ref) blk: {
2453924603 const align_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
2454024604 extra_index += 1;
......@@ -24546,13 +24610,9 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
2454624610 },
2454724611 else => |e| return e,
2454824612 };
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 }
24613 const alignment = try sema.validateAlignAllowZero(block, align_src, align_tv.val.toUnsignedInt(mod));
24614 const default = target_util.defaultFunctionAlignment(target);
24615 break :blk if (alignment == default) .none else alignment;
2455624616 } else .none;
2455724617
2455824618 const @"addrspace": ?std.builtin.AddressSpace = if (extra.data.bits.has_addrspace_body) blk: {
......@@ -25237,16 +25297,17 @@ fn explainWhyTypeIsComptimeInner(
2523725297 .Struct => {
2523825298 if ((try type_set.getOrPut(sema.gpa, ty.toIntern())).found_existing) return;
2523925299
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, .{
25300 if (mod.typeToStruct(ty)) |struct_type| {
25301 for (0..struct_type.field_types.len) |i| {
25302 const field_ty = struct_type.field_types.get(ip)[i].toType();
25303 const field_src_loc = mod.fieldSrcLoc(struct_type.decl.unwrap().?, .{
2524325304 .index = i,
2524425305 .range = .type,
2524525306 });
2524625307
25247 if (try sema.typeRequiresComptime(field.ty)) {
25308 if (try sema.typeRequiresComptime(field_ty)) {
2524825309 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);
25310 try sema.explainWhyTypeIsComptimeInner(msg, field_src_loc, field_ty, type_set);
2525025311 }
2525125312 }
2525225313 }
......@@ -25515,7 +25576,7 @@ fn prepareSimplePanic(sema: *Sema, block: *Block) !void {
2551525576 const stack_trace_ty = try sema.getBuiltinType("StackTrace");
2551625577 try sema.resolveTypeFields(stack_trace_ty);
2551725578 const target = mod.getTarget();
25518 const ptr_stack_trace_ty = try mod.ptrType(.{
25579 const ptr_stack_trace_ty = try sema.ptrType(.{
2551925580 .child = stack_trace_ty.toIntern(),
2552025581 .flags = .{
2552125582 .address_space = target_util.defaultAddressSpace(target, .global_constant),
......@@ -25867,7 +25928,7 @@ fn fieldVal(
2586725928 return Air.internedToRef((try mod.intValue(Type.usize, inner_ty.arrayLen(mod))).toIntern());
2586825929 } else if (ip.stringEqlSlice(field_name, "ptr") and is_pointer_to) {
2586925930 const ptr_info = object_ty.ptrInfo(mod);
25870 const result_ty = try mod.ptrType(.{
25931 const result_ty = try sema.ptrType(.{
2587125932 .child = ptr_info.child.toType().childType(mod).toIntern(),
2587225933 .sentinel = ptr_info.sentinel,
2587325934 .flags = .{
......@@ -26086,7 +26147,7 @@ fn fieldPtr(
2608626147 if (ip.stringEqlSlice(field_name, "ptr")) {
2608726148 const slice_ptr_ty = inner_ty.slicePtrFieldType(mod);
2608826149
26089 const result_ty = try mod.ptrType(.{
26150 const result_ty = try sema.ptrType(.{
2609026151 .child = slice_ptr_ty.toIntern(),
2609126152 .flags = .{
2609226153 .is_const = !attr_ptr_ty.ptrIsMutable(mod),
......@@ -26108,7 +26169,7 @@ fn fieldPtr(
2610826169
2610926170 return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr);
2611026171 } else if (ip.stringEqlSlice(field_name, "len")) {
26111 const result_ty = try mod.ptrType(.{
26172 const result_ty = try sema.ptrType(.{
2611226173 .child = .usize_type,
2611326174 .flags = .{
2611426175 .is_const = !attr_ptr_ty.ptrIsMutable(mod),
......@@ -26297,13 +26358,12 @@ fn fieldCallBind(
2629726358 switch (concrete_ty.zigTypeTag(mod)) {
2629826359 .Struct => {
2629926360 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
26361 if (mod.typeToStruct(concrete_ty)) |struct_type| {
26362 const field_index = struct_type.nameIndex(ip, field_name) orelse
2630226363 break :find_field;
26303 const field_index: u32 = @intCast(field_index_usize);
26304 const field = struct_obj.fields.values()[field_index];
26364 const field_ty = struct_type.field_types.get(ip)[field_index].toType();
2630526365
26306 return sema.finishFieldCallBind(block, src, ptr_ty, field.ty, field_index, object_ptr);
26366 return sema.finishFieldCallBind(block, src, ptr_ty, field_ty, field_index, object_ptr);
2630726367 } else if (concrete_ty.isTuple(mod)) {
2630826368 if (ip.stringEqlSlice(field_name, "len")) {
2630926369 return .{ .direct = try mod.intRef(Type.usize, concrete_ty.structFieldCount(mod)) };
......@@ -26316,7 +26376,7 @@ fn fieldCallBind(
2631626376 const max = concrete_ty.structFieldCount(mod);
2631726377 for (0..max) |i_usize| {
2631826378 const i: u32 = @intCast(i_usize);
26319 if (field_name == concrete_ty.structFieldName(i, mod)) {
26379 if (field_name == concrete_ty.structFieldName(i, mod).unwrap().?) {
2632026380 return sema.finishFieldCallBind(block, src, ptr_ty, concrete_ty.structFieldType(i, mod), i, object_ptr);
2632126381 }
2632226382 }
......@@ -26434,7 +26494,7 @@ fn finishFieldCallBind(
2643426494 object_ptr: Air.Inst.Ref,
2643526495) CompileError!ResolvedFieldCallee {
2643626496 const mod = sema.mod;
26437 const ptr_field_ty = try mod.ptrType(.{
26497 const ptr_field_ty = try sema.ptrType(.{
2643826498 .child = field_ty.toIntern(),
2643926499 .flags = .{
2644026500 .is_const = !ptr_ty.ptrIsMutable(mod),
......@@ -26526,13 +26586,14 @@ fn structFieldPtr(
2652626586 initializing: bool,
2652726587) CompileError!Air.Inst.Ref {
2652826588 const mod = sema.mod;
26589 const ip = &mod.intern_pool;
2652926590 assert(struct_ty.zigTypeTag(mod) == .Struct);
2653026591
2653126592 try sema.resolveTypeFields(struct_ty);
2653226593 try sema.resolveStructLayout(struct_ty);
2653326594
2653426595 if (struct_ty.isTuple(mod)) {
26535 if (mod.intern_pool.stringEqlSlice(field_name, "len")) {
26596 if (ip.stringEqlSlice(field_name, "len")) {
2653626597 const len_inst = try mod.intRef(Type.usize, struct_ty.structFieldCount(mod));
2653726598 return sema.analyzeRef(block, src, len_inst);
2653826599 }
......@@ -26543,11 +26604,10 @@ fn structFieldPtr(
2654326604 return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing);
2654426605 }
2654526606
26546 const struct_obj = mod.typeToStruct(struct_ty).?;
26607 const struct_type = mod.typeToStruct(struct_ty).?;
2654726608
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);
26609 const field_index = struct_type.nameIndex(ip, field_name) orelse
26610 return sema.failWithBadStructFieldAccess(block, struct_type, field_name_src, field_name);
2655126611
2655226612 return sema.structFieldPtrByIndex(block, src, struct_ptr, field_index, field_name_src, struct_ty, initializing);
2655326613}
......@@ -26563,17 +26623,18 @@ fn structFieldPtrByIndex(
2656326623 initializing: bool,
2656426624) CompileError!Air.Inst.Ref {
2656526625 const mod = sema.mod;
26626 const ip = &mod.intern_pool;
2656626627 if (struct_ty.isAnonStruct(mod)) {
2656726628 return sema.tupleFieldPtr(block, src, struct_ptr, field_src, field_index, initializing);
2656826629 }
2656926630
26570 const struct_obj = mod.typeToStruct(struct_ty).?;
26571 const field = struct_obj.fields.values()[field_index];
26631 const struct_type = mod.typeToStruct(struct_ty).?;
26632 const field_ty = struct_type.field_types.get(ip)[field_index];
2657226633 const struct_ptr_ty = sema.typeOf(struct_ptr);
2657326634 const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(mod);
2657426635
2657526636 var ptr_ty_data: InternPool.Key.PtrType = .{
26576 .child = field.ty.toIntern(),
26637 .child = field_ty,
2657726638 .flags = .{
2657826639 .is_const = struct_ptr_ty_info.flags.is_const,
2657926640 .is_volatile = struct_ptr_ty_info.flags.is_volatile,
......@@ -26583,20 +26644,23 @@ fn structFieldPtrByIndex(
2658326644
2658426645 const target = mod.getTarget();
2658526646
26586 const parent_align = struct_ptr_ty_info.flags.alignment.toByteUnitsOptional() orelse
26647 const parent_align = if (struct_ptr_ty_info.flags.alignment != .none)
26648 struct_ptr_ty_info.flags.alignment
26649 else
2658726650 try sema.typeAbiAlignment(struct_ptr_ty_info.child.toType());
2658826651
26589 if (struct_obj.layout == .Packed) {
26652 if (struct_type.layout == .Packed) {
2659026653 comptime assert(Type.packed_struct_layout_version == 2);
2659126654
2659226655 var running_bits: u16 = 0;
26593 for (struct_obj.fields.values(), 0..) |f, i| {
26594 if (!(try sema.typeHasRuntimeBits(f.ty))) continue;
26656 for (0..struct_type.field_types.len) |i| {
26657 const f_ty = struct_type.field_types.get(ip)[i].toType();
26658 if (!(try sema.typeHasRuntimeBits(f_ty))) continue;
2659526659
2659626660 if (i == field_index) {
2659726661 ptr_ty_data.packed_offset.bit_offset = running_bits;
2659826662 }
26599 running_bits += @intCast(f.ty.bitSize(mod));
26663 running_bits += @intCast(f_ty.bitSize(mod));
2660026664 }
2660126665 ptr_ty_data.packed_offset.host_size = (running_bits + 7) / 8;
2660226666
......@@ -26607,7 +26671,7 @@ fn structFieldPtrByIndex(
2660726671 ptr_ty_data.packed_offset.bit_offset += struct_ptr_ty_info.packed_offset.bit_offset;
2660826672 }
2660926673
26610 ptr_ty_data.flags.alignment = Alignment.fromByteUnits(parent_align);
26674 ptr_ty_data.flags.alignment = parent_align;
2661126675
2661226676 // If the field happens to be byte-aligned, simplify the pointer type.
2661326677 // The pointee type bit size must match its ABI byte size so that loads and stores
......@@ -26617,38 +26681,47 @@ fn structFieldPtrByIndex(
2661726681 // targets before adding the necessary complications to this code. This will not
2661826682 // cause miscompilations; it only means the field pointer uses bit masking when it
2661926683 // might not be strictly necessary.
26620 if (parent_align != 0 and ptr_ty_data.packed_offset.bit_offset % 8 == 0 and
26684 if (parent_align != .none and ptr_ty_data.packed_offset.bit_offset % 8 == 0 and
2662126685 target.cpu.arch.endian() == .Little)
2662226686 {
26623 const elem_size_bytes = ptr_ty_data.child.toType().abiSize(mod);
26687 const elem_size_bytes = try sema.typeAbiSize(ptr_ty_data.child.toType());
2662426688 const elem_size_bits = ptr_ty_data.child.toType().bitSize(mod);
2662526689 if (elem_size_bytes * 8 == elem_size_bits) {
2662626690 const byte_offset = ptr_ty_data.packed_offset.bit_offset / 8;
26627 const new_align: Alignment = @enumFromInt(@ctz(byte_offset | parent_align));
26691 const new_align: Alignment = @enumFromInt(@ctz(byte_offset | parent_align.toByteUnitsOptional().?));
2662826692 assert(new_align != .none);
2662926693 ptr_ty_data.flags.alignment = new_align;
2663026694 ptr_ty_data.packed_offset = .{ .host_size = 0, .bit_offset = 0 };
2663126695 }
2663226696 }
26633 } else if (struct_obj.layout == .Extern) {
26634 // For extern structs, field aligment might be bigger than type's natural alignment. Eg, in
26635 // `extern struct { x: u32, y: u16 }` the second field is aligned as u32.
26697 } else if (struct_type.layout == .Extern) {
26698 // For extern structs, field alignment might be bigger than type's
26699 // natural alignment. Eg, in `extern struct { x: u32, y: u16 }` the
26700 // second field is aligned as u32.
2663626701 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 );
26702 ptr_ty_data.flags.alignment = if (parent_align == .none)
26703 .none
26704 else
26705 @enumFromInt(@min(@intFromEnum(parent_align), @ctz(field_offset)));
2664026706 } else {
26641 // 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));
26707 // Our alignment is capped at the field alignment.
26708 const field_align = try sema.structFieldAlignment(
26709 struct_type.fieldAlign(ip, field_index),
26710 field_ty.toType(),
26711 struct_type.layout,
26712 );
26713 ptr_ty_data.flags.alignment = if (struct_ptr_ty_info.flags.alignment == .none)
26714 field_align
26715 else
26716 field_align.min(parent_align);
2664426717 }
2664526718
26646 const ptr_field_ty = try mod.ptrType(ptr_ty_data);
26719 const ptr_field_ty = try sema.ptrType(ptr_ty_data);
2664726720
26648 if (field.is_comptime) {
26721 if (struct_type.fieldIsComptime(ip, field_index)) {
2664926722 const val = try mod.intern(.{ .ptr = .{
2665026723 .ty = ptr_field_ty.toIntern(),
26651 .addr = .{ .comptime_field = field.default_val },
26724 .addr = .{ .comptime_field = struct_type.field_inits.get(ip)[field_index] },
2665226725 } });
2665326726 return Air.internedToRef(val);
2665426727 }
......@@ -26678,33 +26751,34 @@ fn structFieldVal(
2667826751 struct_ty: Type,
2667926752) CompileError!Air.Inst.Ref {
2668026753 const mod = sema.mod;
26754 const ip = &mod.intern_pool;
2668126755 assert(struct_ty.zigTypeTag(mod) == .Struct);
2668226756
2668326757 try sema.resolveTypeFields(struct_ty);
26684 switch (mod.intern_pool.indexToKey(struct_ty.toIntern())) {
26758 switch (ip.indexToKey(struct_ty.toIntern())) {
2668526759 .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];
26760 if (struct_type.isTuple(ip))
26761 return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty);
2669326762
26694 if (field.is_comptime) {
26695 return Air.internedToRef(field.default_val);
26763 const field_index = struct_type.nameIndex(ip, field_name) orelse
26764 return sema.failWithBadStructFieldAccess(block, struct_type, field_name_src, field_name);
26765 if (struct_type.fieldIsComptime(ip, field_index)) {
26766 return Air.internedToRef(struct_type.field_inits.get(ip)[field_index]);
2669626767 }
2669726768
26769 const field_ty = struct_type.field_types.get(ip)[field_index].toType();
26770
2669826771 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| {
26772 if (struct_val.isUndef(mod)) return mod.undefRef(field_ty);
26773 if ((try sema.typeHasOnePossibleValue(field_ty))) |opv| {
2670126774 return Air.internedToRef(opv.toIntern());
2670226775 }
2670326776 return Air.internedToRef((try struct_val.fieldValue(mod, field_index)).toIntern());
2670426777 }
2670526778
2670626779 try sema.requireRuntimeBlock(block, src, null);
26707 return block.addStructFieldVal(struct_byval, field_index, field.ty);
26780 try sema.resolveTypeLayout(field_ty);
26781 return block.addStructFieldVal(struct_byval, field_index, field_ty);
2670826782 },
2670926783 .anon_struct_type => |anon_struct| {
2671026784 if (anon_struct.names.len == 0) {
......@@ -26792,6 +26866,7 @@ fn tupleFieldValByIndex(
2679226866 }
2679326867
2679426868 try sema.requireRuntimeBlock(block, src, null);
26869 try sema.resolveTypeLayout(field_ty);
2679526870 return block.addStructFieldVal(tuple_byval, field_index, field_ty);
2679626871}
2679726872
......@@ -26816,16 +26891,19 @@ fn unionFieldPtr(
2681626891 const union_obj = mod.typeToUnion(union_ty).?;
2681726892 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
2681826893 const field_ty = union_obj.field_types.get(ip)[field_index].toType();
26819 const ptr_field_ty = try mod.ptrType(.{
26894 const ptr_field_ty = try sema.ptrType(.{
2682026895 .child = field_ty.toIntern(),
2682126896 .flags = .{
2682226897 .is_const = union_ptr_info.flags.is_const,
2682326898 .is_volatile = union_ptr_info.flags.is_volatile,
2682426899 .address_space = union_ptr_info.flags.address_space,
2682526900 .alignment = if (union_obj.getLayout(ip) == .Auto) blk: {
26826 const union_align = union_ptr_info.flags.alignment.toByteUnitsOptional() orelse try sema.typeAbiAlignment(union_ty);
26901 const union_align = if (union_ptr_info.flags.alignment != .none)
26902 union_ptr_info.flags.alignment
26903 else
26904 try sema.typeAbiAlignment(union_ty);
2682726905 const field_align = try sema.unionFieldAlignment(union_obj, field_index);
26828 break :blk InternPool.Alignment.fromByteUnits(@min(union_align, field_align));
26906 break :blk union_align.min(field_align);
2682926907 } else union_ptr_info.flags.alignment,
2683026908 },
2683126909 .packed_offset = union_ptr_info.packed_offset,
......@@ -26970,6 +27048,7 @@ fn unionFieldVal(
2697027048 _ = try block.addNoOp(.unreach);
2697127049 return .unreachable_value;
2697227050 }
27051 try sema.resolveTypeLayout(field_ty);
2697327052 return block.addStructFieldVal(union_byval, field_index, field_ty);
2697427053}
2697527054
......@@ -27194,7 +27273,7 @@ fn tupleFieldPtr(
2719427273 }
2719527274
2719627275 const field_ty = tuple_ty.structFieldType(field_index, mod);
27197 const ptr_field_ty = try mod.ptrType(.{
27276 const ptr_field_ty = try sema.ptrType(.{
2719827277 .child = field_ty.toIntern(),
2719927278 .flags = .{
2720027279 .is_const = !tuple_ptr_ty.ptrIsMutable(mod),
......@@ -27265,6 +27344,7 @@ fn tupleField(
2726527344 try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src);
2726627345
2726727346 try sema.requireRuntimeBlock(block, tuple_src, null);
27347 try sema.resolveTypeLayout(field_ty);
2726827348 return block.addStructFieldVal(tuple, field_index, field_ty);
2726927349}
2727027350
......@@ -28266,7 +28346,7 @@ const InMemoryCoercionResult = union(enum) {
2826628346 ptr_qualifiers: Qualifiers,
2826728347 ptr_allowzero: Pair,
2826828348 ptr_bit_range: BitRange,
28269 ptr_alignment: IntPair,
28349 ptr_alignment: AlignPair,
2827028350 double_ptr_to_anyopaque: Pair,
2827128351 slice_to_anyopaque: Pair,
2827228352
......@@ -28312,6 +28392,11 @@ const InMemoryCoercionResult = union(enum) {
2831228392 wanted: u64,
2831328393 };
2831428394
28395 const AlignPair = struct {
28396 actual: Alignment,
28397 wanted: Alignment,
28398 };
28399
2831528400 const Size = struct {
2831628401 actual: std.builtin.Type.Pointer.Size,
2831728402 wanted: std.builtin.Type.Pointer.Size,
......@@ -28555,8 +28640,8 @@ const InMemoryCoercionResult = union(enum) {
2855528640 break;
2855628641 },
2855728642 .ptr_alignment => |pair| {
28558 try sema.errNote(block, src, msg, "pointer alignment '{}' cannot cast into pointer alignment '{}'", .{
28559 pair.actual, pair.wanted,
28643 try sema.errNote(block, src, msg, "pointer alignment '{d}' cannot cast into pointer alignment '{d}'", .{
28644 pair.actual.toByteUnits(0), pair.wanted.toByteUnits(0),
2856028645 });
2856128646 break;
2856228647 },
......@@ -29133,13 +29218,17 @@ fn coerceInMemoryAllowedPtrs(
2913329218 if (src_info.flags.alignment != .none or dest_info.flags.alignment != .none or
2913429219 dest_info.child != src_info.child)
2913529220 {
29136 const src_align = src_info.flags.alignment.toByteUnitsOptional() orelse
29137 src_info.child.toType().abiAlignment(mod);
29221 const src_align = if (src_info.flags.alignment != .none)
29222 src_info.flags.alignment
29223 else
29224 try sema.typeAbiAlignment(src_info.child.toType());
2913829225
29139 const dest_align = dest_info.flags.alignment.toByteUnitsOptional() orelse
29140 dest_info.child.toType().abiAlignment(mod);
29226 const dest_align = if (dest_info.flags.alignment != .none)
29227 dest_info.flags.alignment
29228 else
29229 try sema.typeAbiAlignment(dest_info.child.toType());
2914129230
29142 if (dest_align > src_align) {
29231 if (dest_align.compare(.gt, src_align)) {
2914329232 return InMemoryCoercionResult{ .ptr_alignment = .{
2914429233 .actual = src_align,
2914529234 .wanted = dest_align,
......@@ -30378,13 +30467,17 @@ fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_resul
3037830467 if (inst_info.flags.alignment == .none and dest_info.flags.alignment == .none) return true;
3037930468 if (len0) return true;
3038030469
30381 const inst_align = inst_info.flags.alignment.toByteUnitsOptional() orelse
30470 const inst_align = if (inst_info.flags.alignment != .none)
30471 inst_info.flags.alignment
30472 else
3038230473 inst_info.child.toType().abiAlignment(mod);
3038330474
30384 const dest_align = dest_info.flags.alignment.toByteUnitsOptional() orelse
30475 const dest_align = if (dest_info.flags.alignment != .none)
30476 dest_info.flags.alignment
30477 else
3038530478 dest_info.child.toType().abiAlignment(mod);
3038630479
30387 if (dest_align > inst_align) {
30480 if (dest_align.compare(.gt, inst_align)) {
3038830481 in_memory_result.* = .{ .ptr_alignment = .{
3038930482 .actual = inst_align,
3039030483 .wanted = dest_align,
......@@ -30598,7 +30691,7 @@ fn coerceAnonStructToUnion(
3059830691 else
3059930692 .{ .count = anon_struct_type.names.len },
3060030693 .struct_type => |struct_type| name: {
30601 const field_names = mod.structPtrUnwrap(struct_type.index).?.fields.keys();
30694 const field_names = struct_type.field_names.get(ip);
3060230695 break :name if (field_names.len == 1)
3060330696 .{ .name = field_names[0] }
3060430697 else
......@@ -30869,8 +30962,8 @@ fn coerceTupleToStruct(
3086930962 return sema.coerceTupleToTuple(block, struct_ty, inst, inst_src);
3087030963 }
3087130964
30872 const fields = struct_ty.structFields(mod);
30873 const field_vals = try sema.arena.alloc(InternPool.Index, fields.count());
30965 const struct_type = mod.typeToStruct(struct_ty).?;
30966 const field_vals = try sema.arena.alloc(InternPool.Index, struct_type.field_types.len);
3087430967 const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len);
3087530968 @memset(field_refs, .none);
3087630969
......@@ -30878,10 +30971,7 @@ fn coerceTupleToStruct(
3087830971 var runtime_src: ?LazySrcLoc = null;
3087930972 const field_count = switch (ip.indexToKey(inst_ty.toIntern())) {
3088030973 .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,
30974 .struct_type => |s| s.field_types.len,
3088530975 else => unreachable,
3088630976 };
3088730977 for (0..field_count) |field_index_usize| {
......@@ -30893,22 +30983,23 @@ fn coerceTupleToStruct(
3089330983 anon_struct_type.names.get(ip)[field_i]
3089430984 else
3089530985 try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}),
30896 .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.keys()[field_i],
30986 .struct_type => |s| s.field_names.get(ip)[field_i],
3089730987 else => unreachable,
3089830988 };
3089930989 const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src);
30900 const field = fields.values()[field_index];
30990 const field_ty = struct_type.field_types.get(ip)[field_index].toType();
3090130991 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);
30992 const coerced = try sema.coerce(block, field_ty, elem_ref, field_src);
3090330993 field_refs[field_index] = coerced;
30904 if (field.is_comptime) {
30994 if (struct_type.fieldIsComptime(ip, field_index)) {
3090530995 const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse {
3090630996 return sema.failWithNeededComptime(block, field_src, .{
3090730997 .needed_comptime_reason = "value stored in comptime field must be comptime-known",
3090830998 });
3090930999 };
3091031000
30911 if (!init_val.eql(field.default_val.toValue(), field.ty, sema.mod)) {
31001 const field_init = struct_type.field_inits.get(ip)[field_index].toValue();
31002 if (!init_val.eql(field_init, field_ty, sema.mod)) {
3091231003 return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i);
3091331004 }
3091431005 }
......@@ -30928,10 +31019,10 @@ fn coerceTupleToStruct(
3092831019 for (field_refs, 0..) |*field_ref, i| {
3092931020 if (field_ref.* != .none) continue;
3093031021
30931 const field_name = fields.keys()[i];
30932 const field = fields.values()[i];
31022 const field_name = struct_type.field_names.get(ip)[i];
31023 const field_default_val = struct_type.fieldInit(ip, i);
3093331024 const field_src = inst_src; // TODO better source location
30934 if (field.default_val == .none) {
31025 if (field_default_val == .none) {
3093531026 const template = "missing struct field: {}";
3093631027 const args = .{field_name.fmt(ip)};
3093731028 if (root_msg) |msg| {
......@@ -30942,9 +31033,9 @@ fn coerceTupleToStruct(
3094231033 continue;
3094331034 }
3094431035 if (runtime_src == null) {
30945 field_vals[i] = field.default_val;
31036 field_vals[i] = field_default_val;
3094631037 } else {
30947 field_ref.* = Air.internedToRef(field.default_val);
31038 field_ref.* = Air.internedToRef(field_default_val);
3094831039 }
3094931040 }
3095031041
......@@ -30980,10 +31071,7 @@ fn coerceTupleToTuple(
3098031071 const ip = &mod.intern_pool;
3098131072 const dest_field_count = switch (ip.indexToKey(tuple_ty.toIntern())) {
3098231073 .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,
31074 .struct_type => |struct_type| struct_type.field_types.len,
3098731075 else => unreachable,
3098831076 };
3098931077 const field_vals = try sema.arena.alloc(InternPool.Index, dest_field_count);
......@@ -30993,10 +31081,7 @@ fn coerceTupleToTuple(
3099331081 const inst_ty = sema.typeOf(inst);
3099431082 const src_field_count = switch (ip.indexToKey(inst_ty.toIntern())) {
3099531083 .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,
31084 .struct_type => |struct_type| struct_type.field_types.len,
3100031085 else => unreachable,
3100131086 };
3100231087 if (src_field_count > dest_field_count) return error.NotCoercible;
......@@ -31011,7 +31096,7 @@ fn coerceTupleToTuple(
3101131096 anon_struct_type.names.get(ip)[field_i]
3101231097 else
3101331098 try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}),
31014 .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.keys()[field_i],
31099 .struct_type => |struct_type| struct_type.field_names.get(ip)[field_i],
3101531100 else => unreachable,
3101631101 };
3101731102
......@@ -31019,20 +31104,20 @@ fn coerceTupleToTuple(
3101931104 return sema.fail(block, field_src, "cannot assign to 'len' field of tuple", .{});
3102031105
3102131106 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,
31107 .anon_struct_type => |anon_struct_type| anon_struct_type.types.get(ip)[field_index_usize],
31108 .struct_type => |struct_type| struct_type.field_types.get(ip)[field_index_usize],
3102431109 else => unreachable,
3102531110 };
3102631111 const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {
3102731112 .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,
31113 .struct_type => |struct_type| struct_type.fieldInit(ip, field_index_usize),
3102931114 else => unreachable,
3103031115 };
3103131116
3103231117 const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_src);
3103331118
3103431119 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);
31120 const coerced = try sema.coerce(block, field_ty.toType(), elem_ref, field_src);
3103631121 field_refs[field_index] = coerced;
3103731122 if (default_val != .none) {
3103831123 const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse {
......@@ -31041,7 +31126,7 @@ fn coerceTupleToTuple(
3104131126 });
3104231127 };
3104331128
31044 if (!init_val.eql(default_val.toValue(), field_ty, sema.mod)) {
31129 if (!init_val.eql(default_val.toValue(), field_ty.toType(), sema.mod)) {
3104531130 return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i);
3104631131 }
3104731132 }
......@@ -31058,18 +31143,19 @@ fn coerceTupleToTuple(
3105831143 var root_msg: ?*Module.ErrorMsg = null;
3105931144 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
3106031145
31061 for (field_refs, 0..) |*field_ref, i| {
31146 for (field_refs, 0..) |*field_ref, i_usize| {
31147 const i: u32 = @intCast(i_usize);
3106231148 if (field_ref.* != .none) continue;
3106331149
3106431150 const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {
3106531151 .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,
31152 .struct_type => |struct_type| struct_type.fieldInit(ip, i),
3106731153 else => unreachable,
3106831154 };
3106931155
3107031156 const field_src = inst_src; // TODO better source location
3107131157 if (default_val == .none) {
31072 if (tuple_ty.isTuple(mod)) {
31158 const field_name = tuple_ty.structFieldName(i, mod).unwrap() orelse {
3107331159 const template = "missing tuple field: {d}";
3107431160 if (root_msg) |msg| {
3107531161 try sema.errNote(block, field_src, msg, template, .{i});
......@@ -31077,9 +31163,9 @@ fn coerceTupleToTuple(
3107731163 root_msg = try sema.errMsg(block, field_src, template, .{i});
3107831164 }
3107931165 continue;
31080 }
31166 };
3108131167 const template = "missing struct field: {}";
31082 const args = .{tuple_ty.structFieldName(i, mod).fmt(ip)};
31168 const args = .{field_name.fmt(ip)};
3108331169 if (root_msg) |msg| {
3108431170 try sema.errNote(block, field_src, msg, template, args);
3108531171 } else {
......@@ -31229,7 +31315,7 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: Decl.Index, analyze_fn_body: boo
3122931315
3123031316 const decl = mod.declPtr(decl_index);
3123131317 const decl_tv = try decl.typedValue();
31232 const ptr_ty = try mod.ptrType(.{
31318 const ptr_ty = try sema.ptrType(.{
3123331319 .child = decl_tv.ty.toIntern(),
3123431320 .flags = .{
3123531321 .alignment = decl.alignment,
......@@ -31283,14 +31369,14 @@ fn analyzeRef(
3128331369
3128431370 try sema.requireRuntimeBlock(block, src, null);
3128531371 const address_space = target_util.defaultAddressSpace(mod.getTarget(), .local);
31286 const ptr_type = try mod.ptrType(.{
31372 const ptr_type = try sema.ptrType(.{
3128731373 .child = operand_ty.toIntern(),
3128831374 .flags = .{
3128931375 .is_const = true,
3129031376 .address_space = address_space,
3129131377 },
3129231378 });
31293 const mut_ptr_type = try mod.ptrType(.{
31379 const mut_ptr_type = try sema.ptrType(.{
3129431380 .child = operand_ty.toIntern(),
3129531381 .flags = .{ .address_space = address_space },
3129631382 });
......@@ -31662,7 +31748,7 @@ fn analyzeSlice(
3166231748 assert(manyptr_ty_key.flags.size == .One);
3166331749 manyptr_ty_key.child = elem_ty.toIntern();
3166431750 manyptr_ty_key.flags.size = .Many;
31665 break :ptr try sema.coerceCompatiblePtrs(block, try mod.ptrType(manyptr_ty_key), ptr_or_slice, ptr_src);
31751 break :ptr try sema.coerceCompatiblePtrs(block, try sema.ptrType(manyptr_ty_key), ptr_or_slice, ptr_src);
3166631752 } else ptr_or_slice;
3166731753
3166831754 const start = try sema.coerce(block, Type.usize, uncasted_start, start_src);
......@@ -31885,7 +31971,7 @@ fn analyzeSlice(
3188531971 if (opt_new_len_val) |new_len_val| {
3188631972 const new_len_int = new_len_val.toUnsignedInt(mod);
3188731973
31888 const return_ty = try mod.ptrType(.{
31974 const return_ty = try sema.ptrType(.{
3188931975 .child = (try mod.arrayType(.{
3189031976 .len = new_len_int,
3189131977 .sentinel = if (sentinel) |s| s.toIntern() else .none,
......@@ -31946,7 +32032,7 @@ fn analyzeSlice(
3194632032 return sema.fail(block, src, "non-zero length slice of undefined pointer", .{});
3194732033 }
3194832034
31949 const return_ty = try mod.ptrType(.{
32035 const return_ty = try sema.ptrType(.{
3195032036 .child = elem_ty.toIntern(),
3195132037 .sentinel = if (sentinel) |s| s.toIntern() else .none,
3195232038 .flags = .{
......@@ -33181,12 +33267,17 @@ fn resolvePeerTypesInner(
3318133267 }
3318233268
3318333269 // 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
33270 ptr_info.flags.alignment = InternPool.Alignment.min(
33271 if (ptr_info.flags.alignment != .none)
33272 ptr_info.flags.alignment
33273 else
3318633274 ptr_info.child.toType().abiAlignment(mod),
33187 peer_info.flags.alignment.toByteUnitsOptional() orelse
33275
33276 if (peer_info.flags.alignment != .none)
33277 peer_info.flags.alignment
33278 else
3318833279 peer_info.child.toType().abiAlignment(mod),
33189 ));
33280 );
3319033281 if (ptr_info.flags.address_space != peer_info.flags.address_space) {
3319133282 return .{ .conflict = .{
3319233283 .peer_idx_a = first_idx,
......@@ -33208,7 +33299,7 @@ fn resolvePeerTypesInner(
3320833299
3320933300 opt_ptr_info = ptr_info;
3321033301 }
33211 return .{ .success = try mod.ptrType(opt_ptr_info.?) };
33302 return .{ .success = try sema.ptrType(opt_ptr_info.?) };
3321233303 },
3321333304
3321433305 .ptr => {
......@@ -33260,12 +33351,17 @@ fn resolvePeerTypesInner(
3326033351 } };
3326133352
3326233353 // 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
33265 ptr_info.child.toType().abiAlignment(mod),
33266 peer_info.flags.alignment.toByteUnitsOptional() orelse
33267 peer_info.child.toType().abiAlignment(mod),
33268 ));
33354 ptr_info.flags.alignment = Alignment.min(
33355 if (ptr_info.flags.alignment != .none)
33356 ptr_info.flags.alignment
33357 else
33358 try sema.typeAbiAlignment(ptr_info.child.toType()),
33359
33360 if (peer_info.flags.alignment != .none)
33361 peer_info.flags.alignment
33362 else
33363 try sema.typeAbiAlignment(peer_info.child.toType()),
33364 );
3326933365
3327033366 if (ptr_info.flags.address_space != peer_info.flags.address_space) {
3327133367 return generic_err;
......@@ -33513,7 +33609,7 @@ fn resolvePeerTypesInner(
3351333609 },
3351433610 }
3351533611
33516 return .{ .success = try mod.ptrType(opt_ptr_info.?) };
33612 return .{ .success = try sema.ptrType(opt_ptr_info.?) };
3351733613 },
3351833614
3351933615 .func => {
......@@ -33802,8 +33898,9 @@ fn resolvePeerTypesInner(
3380233898 }
3380333899
3380433900 if (!is_tuple) {
33805 for (field_names, 0..) |expected, field_idx| {
33806 const actual = ty.structFieldName(field_idx, mod);
33901 for (field_names, 0..) |expected, field_index_usize| {
33902 const field_index: u32 = @intCast(field_index_usize);
33903 const actual = ty.structFieldName(field_index, mod).unwrap().?;
3380733904 if (actual == expected) continue;
3380833905 return .{ .conflict = .{
3380933906 .peer_idx_a = first_idx,
......@@ -34190,104 +34287,246 @@ pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void {
3419034287 }
3419134288}
3419234289
34290/// Resolve a struct's alignment only without triggering resolution of its layout.
34291/// Asserts that the alignment is not yet resolved and the layout is non-packed.
34292pub fn resolveStructAlignment(
34293 sema: *Sema,
34294 ty: InternPool.Index,
34295 struct_type: InternPool.Key.StructType,
34296) CompileError!Alignment {
34297 const mod = sema.mod;
34298 const ip = &mod.intern_pool;
34299 const target = mod.getTarget();
34300
34301 assert(struct_type.flagsPtr(ip).alignment == .none);
34302 assert(struct_type.layout != .Packed);
34303
34304 if (struct_type.flagsPtr(ip).field_types_wip) {
34305 // We'll guess "pointer-aligned", if the struct has an
34306 // underaligned pointer field then some allocations
34307 // might require explicit alignment.
34308 //TODO write this bit and emit an error later if incorrect
34309 //struct_type.flagsPtr(ip).assumed_pointer_aligned = true;
34310 const result = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
34311 struct_type.flagsPtr(ip).alignment = result;
34312 return result;
34313 }
34314
34315 try sema.resolveTypeFieldsStruct(ty, struct_type);
34316
34317 if (struct_type.setAlignmentWip(ip)) {
34318 // We'll guess "pointer-aligned", if the struct has an
34319 // underaligned pointer field then some allocations
34320 // might require explicit alignment.
34321 //TODO write this bit and emit an error later if incorrect
34322 //struct_type.flagsPtr(ip).assumed_pointer_aligned = true;
34323 const result = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
34324 struct_type.flagsPtr(ip).alignment = result;
34325 return result;
34326 }
34327 defer struct_type.clearAlignmentWip(ip);
34328
34329 var result: Alignment = .@"1";
34330
34331 for (0..struct_type.field_types.len) |i| {
34332 const field_ty = struct_type.field_types.get(ip)[i].toType();
34333 if (struct_type.fieldIsComptime(ip, i) or try sema.typeRequiresComptime(field_ty))
34334 continue;
34335 const field_align = try sema.structFieldAlignment(
34336 struct_type.fieldAlign(ip, i),
34337 field_ty,
34338 struct_type.layout,
34339 );
34340 result = result.maxStrict(field_align);
34341 }
34342
34343 struct_type.flagsPtr(ip).alignment = result;
34344 return result;
34345}
34346
3419334347fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
3419434348 const mod = sema.mod;
34349 const ip = &mod.intern_pool;
34350 const struct_type = mod.typeToStruct(ty) orelse return;
34351
34352 if (struct_type.haveLayout(ip))
34353 return;
34354
3419534355 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);
34207 },
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;
34213 };
3421434356
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 }
34357 if (struct_type.layout == .Packed) {
34358 try semaBackingIntType(mod, struct_type);
34359 return;
34360 }
3422634361
34227 if (struct_obj.layout == .Packed) {
34228 try semaBackingIntType(mod, struct_obj);
34229 }
34362 if (struct_type.setLayoutWip(ip)) {
34363 const msg = try Module.ErrorMsg.create(
34364 sema.gpa,
34365 mod.declPtr(struct_type.decl.unwrap().?).srcLoc(mod),
34366 "struct '{}' depends on itself",
34367 .{ty.fmt(mod)},
34368 );
34369 return sema.failWithOwnedErrorMsg(null, msg);
34370 }
34371 defer struct_type.clearLayoutWip(ip);
3423034372
34231 struct_obj.status = .have_layout;
34232 _ = try sema.typeRequiresComptime(ty);
34373 const aligns = try sema.arena.alloc(Alignment, struct_type.field_types.len);
34374 const sizes = try sema.arena.alloc(u64, struct_type.field_types.len);
3423334375
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);
34376 var big_align: Alignment = .@"1";
34377
34378 for (aligns, sizes, 0..) |*field_align, *field_size, i| {
34379 const field_ty = struct_type.field_types.get(ip)[i].toType();
34380 if (struct_type.fieldIsComptime(ip, i) or try sema.typeRequiresComptime(field_ty)) {
34381 struct_type.offsets.get(ip)[i] = 0;
34382 field_size.* = 0;
34383 field_align.* = .none;
34384 continue;
3424234385 }
3424334386
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());
34387 field_size.* = sema.typeAbiSize(field_ty) catch |err| switch (err) {
34388 error.AnalysisFail => {
34389 const msg = sema.err orelse return err;
34390 try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{});
34391 return err;
34392 },
34393 else => return err,
34394 };
34395 field_align.* = try sema.structFieldAlignment(
34396 struct_type.fieldAlign(ip, i),
34397 field_ty,
34398 struct_type.layout,
34399 );
34400 big_align = big_align.maxStrict(field_align.*);
34401 }
3424834402
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;
34403 if (struct_type.flagsPtr(ip).assumed_runtime_bits and !(try sema.typeHasRuntimeBits(ty))) {
34404 const msg = try Module.ErrorMsg.create(
34405 sema.gpa,
34406 mod.declPtr(struct_type.decl.unwrap().?).srcLoc(mod),
34407 "struct layout depends on it having runtime bits",
34408 .{},
34409 );
34410 return sema.failWithOwnedErrorMsg(null, msg);
34411 }
34412
34413 if (struct_type.hasReorderedFields()) {
34414 const runtime_order = struct_type.runtime_order.get(ip);
34415
34416 for (runtime_order, 0..) |*ro, i| {
34417 const field_ty = struct_type.field_types.get(ip)[i].toType();
34418 if (struct_type.fieldIsComptime(ip, i) or try sema.typeRequiresComptime(field_ty)) {
34419 ro.* = .omitted;
34420 } else {
34421 ro.* = @enumFromInt(i);
3425434422 }
34423 }
34424
34425 const RuntimeOrder = InternPool.Key.StructType.RuntimeOrder;
3425534426
34256 const AlignSortContext = struct {
34257 struct_obj: *Module.Struct,
34258 sema: *Sema,
34427 const AlignSortContext = struct {
34428 aligns: []const Alignment,
3425934429
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);
34430 fn lessThan(ctx: @This(), a: RuntimeOrder, b: RuntimeOrder) bool {
34431 if (a == .omitted) return false;
34432 if (b == .omitted) return true;
34433 const a_align = ctx.aligns[@intFromEnum(a)];
34434 const b_align = ctx.aligns[@intFromEnum(b)];
34435 return a_align.compare(.gt, b_align);
34436 }
34437 };
34438 if (struct_type.isTuple(ip) or !mod.backendSupportsFeature(.field_reordering)) {
34439 // TODO: don't handle tuples differently. This logic exists only because it
34440 // uncovers latent bugs if removed. Fix the latent bugs and remove this logic!
34441 // Likewise, implement field reordering support in all the backends!
34442 // This logic does not reorder fields; it only moves the omitted ones to the end
34443 // so that logic elsewhere does not need to special-case tuples.
34444 var i: usize = 0;
34445 var off: usize = 0;
34446 while (i + off < runtime_order.len) {
34447 if (runtime_order[i + off] == .omitted) {
34448 off += 1;
34449 continue;
3426634450 }
34267 };
34268 mem.sort(u32, optimized_order, AlignSortContext{
34269 .struct_obj = struct_obj,
34270 .sema = sema,
34451 runtime_order[i] = runtime_order[i + off];
34452 i += 1;
34453 }
34454 @memset(runtime_order[i..], .omitted);
34455 } else {
34456 mem.sortUnstable(RuntimeOrder, runtime_order, AlignSortContext{
34457 .aligns = aligns,
3427134458 }, AlignSortContext.lessThan);
34272 struct_obj.optimized_order = optimized_order.ptr;
3427334459 }
3427434460 }
34275 // otherwise it's a tuple; no need to resolve anything
34461
34462 // Calculate size, alignment, and field offsets.
34463 const offsets = struct_type.offsets.get(ip);
34464 var it = struct_type.iterateRuntimeOrder(ip);
34465 var offset: u64 = 0;
34466 while (it.next()) |i| {
34467 offsets[i] = @intCast(aligns[i].forward(offset));
34468 offset = offsets[i] + sizes[i];
34469 }
34470 struct_type.size(ip).* = @intCast(big_align.forward(offset));
34471 const flags = struct_type.flagsPtr(ip);
34472 flags.alignment = big_align;
34473 flags.layout_resolved = true;
34474 _ = try sema.typeRequiresComptime(ty);
3427634475}
3427734476
34278fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!void {
34477fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) CompileError!void {
3427934478 const gpa = mod.gpa;
34479 const ip = &mod.intern_pool;
3428034480
34281 var fields_bit_sum: u64 = 0;
34282 for (struct_obj.fields.values()) |field| {
34283 fields_bit_sum += field.ty.bitSize(mod);
34284 }
34285
34286 const decl_index = struct_obj.owner_decl;
34481 const decl_index = struct_type.decl.unwrap().?;
3428734482 const decl = mod.declPtr(decl_index);
3428834483
34289 const zir = mod.namespacePtr(struct_obj.namespace).file_scope.zir;
34290 const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended;
34484 const zir = mod.namespacePtr(struct_type.namespace.unwrap().?).file_scope.zir;
34485
34486 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
34487 defer analysis_arena.deinit();
34488
34489 var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);
34490 defer comptime_mutable_decls.deinit();
34491
34492 var sema: Sema = .{
34493 .mod = mod,
34494 .gpa = gpa,
34495 .arena = analysis_arena.allocator(),
34496 .code = zir,
34497 .owner_decl = decl,
34498 .owner_decl_index = decl_index,
34499 .func_index = .none,
34500 .func_is_naked = false,
34501 .fn_ret_ty = Type.void,
34502 .fn_ret_ty_ies = null,
34503 .owner_func_index = .none,
34504 .comptime_mutable_decls = &comptime_mutable_decls,
34505 };
34506 defer sema.deinit();
34507
34508 var block: Block = .{
34509 .parent = null,
34510 .sema = &sema,
34511 .src_decl = decl_index,
34512 .namespace = struct_type.namespace.unwrap() orelse decl.src_namespace,
34513 .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
34514 .instructions = .{},
34515 .inlining = null,
34516 .is_comptime = true,
34517 };
34518 defer assert(block.instructions.items.len == 0);
34519
34520 const fields_bit_sum = blk: {
34521 var accumulator: u64 = 0;
34522 for (0..struct_type.field_types.len) |i| {
34523 const field_ty = struct_type.field_types.get(ip)[i].toType();
34524 accumulator += try field_ty.bitSizeAdvanced(mod, &sema);
34525 }
34526 break :blk accumulator;
34527 };
34528
34529 const extended = zir.instructions.items(.data)[struct_type.zir_index].extended;
3429134530 assert(extended.opcode == .struct_decl);
3429234531 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
3429334532
......@@ -34300,40 +34539,6 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi
3430034539 const backing_int_body_len = zir.extra[extra_index];
3430134540 extra_index += 1;
3430234541
34303 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
34304 defer analysis_arena.deinit();
34305
34306 var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);
34307 defer comptime_mutable_decls.deinit();
34308
34309 var sema: Sema = .{
34310 .mod = mod,
34311 .gpa = gpa,
34312 .arena = analysis_arena.allocator(),
34313 .code = zir,
34314 .owner_decl = decl,
34315 .owner_decl_index = decl_index,
34316 .func_index = .none,
34317 .func_is_naked = false,
34318 .fn_ret_ty = Type.void,
34319 .fn_ret_ty_ies = null,
34320 .owner_func_index = .none,
34321 .comptime_mutable_decls = &comptime_mutable_decls,
34322 };
34323 defer sema.deinit();
34324
34325 var block: Block = .{
34326 .parent = null,
34327 .sema = &sema,
34328 .src_decl = decl_index,
34329 .namespace = struct_obj.namespace,
34330 .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
34331 .instructions = .{},
34332 .inlining = null,
34333 .is_comptime = true,
34334 };
34335 defer assert(block.instructions.items.len == 0);
34336
3433734542 const backing_int_src: LazySrcLoc = .{ .node_offset_container_tag = 0 };
3433834543 const backing_int_ty = blk: {
3433934544 if (backing_int_body_len == 0) {
......@@ -34341,48 +34546,24 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi
3434134546 break :blk try sema.resolveType(&block, backing_int_src, backing_int_ref);
3434234547 } else {
3434334548 const body = zir.extra[extra_index..][0..backing_int_body_len];
34344 const ty_ref = try sema.resolveBody(&block, body, struct_obj.zir_index);
34549 const ty_ref = try sema.resolveBody(&block, body, struct_type.zir_index);
3434534550 break :blk try sema.analyzeAsType(&block, backing_int_src, ty_ref);
3434634551 }
3434734552 };
3434834553
3434934554 try sema.checkBackingIntType(&block, backing_int_src, backing_int_ty, fields_bit_sum);
34350 struct_obj.backing_int_ty = backing_int_ty;
34351 for (comptime_mutable_decls.items) |ct_decl_index| {
34352 const ct_decl = mod.declPtr(ct_decl_index);
34353 _ = try ct_decl.internValue(mod);
34354 }
34555 struct_type.backingIntType(ip).* = backing_int_ty.toIntern();
3435534556 } else {
3435634557 if (fields_bit_sum > std.math.maxInt(u16)) {
34357 var sema: Sema = .{
34358 .mod = mod,
34359 .gpa = gpa,
34360 .arena = undefined,
34361 .code = zir,
34362 .owner_decl = decl,
34363 .owner_decl_index = decl_index,
34364 .func_index = .none,
34365 .func_is_naked = false,
34366 .fn_ret_ty = Type.void,
34367 .fn_ret_ty_ies = null,
34368 .owner_func_index = .none,
34369 .comptime_mutable_decls = undefined,
34370 };
34371 defer sema.deinit();
34372
34373 var block: Block = .{
34374 .parent = null,
34375 .sema = &sema,
34376 .src_decl = decl_index,
34377 .namespace = struct_obj.namespace,
34378 .wip_capture_scope = undefined,
34379 .instructions = .{},
34380 .inlining = null,
34381 .is_comptime = true,
34382 };
3438334558 return sema.fail(&block, LazySrcLoc.nodeOffset(0), "size of packed struct '{d}' exceeds maximum bit width of 65535", .{fields_bit_sum});
3438434559 }
34385 struct_obj.backing_int_ty = try mod.intType(.unsigned, @intCast(fields_bit_sum));
34560 const backing_int_ty = try mod.intType(.unsigned, @intCast(fields_bit_sum));
34561 struct_type.backingIntType(ip).* = backing_int_ty.toIntern();
34562 }
34563
34564 for (comptime_mutable_decls.items) |ct_decl_index| {
34565 const ct_decl = mod.declPtr(ct_decl_index);
34566 _ = try ct_decl.internValue(mod);
3438634567 }
3438734568}
3438834569
......@@ -34532,30 +34713,20 @@ fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void {
3453234713 try sema.resolveStructLayout(ty);
3453334714
3453434715 const mod = sema.mod;
34535 try sema.resolveTypeFields(ty);
34536 const struct_obj = mod.typeToStruct(ty).?;
34716 const ip = &mod.intern_pool;
34717 const struct_type = mod.typeToStruct(ty).?;
3453734718
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 }
34719 if (struct_type.setFullyResolved(ip)) return;
34720 errdefer struct_type.clearFullyResolved(ip);
3454234721
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;
34722 // After we have resolve struct layout we have to go over the fields again to
34723 // make sure pointer fields get their child types resolved as well.
34724 // See also similar code for unions.
3454934725
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;
34726 for (0..struct_type.field_types.len) |i| {
34727 const field_ty = struct_type.field_types.get(ip)[i].toType();
34728 try sema.resolveTypeFully(field_ty);
3455534729 }
34556
34557 // And let's not forget comptime-only status.
34558 _ = try sema.typeRequiresComptime(ty);
3455934730}
3456034731
3456134732fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void {
......@@ -34591,8 +34762,10 @@ fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void {
3459134762
3459234763pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void {
3459334764 const mod = sema.mod;
34765 const ip = &mod.intern_pool;
34766 const ty_ip = ty.toIntern();
3459434767
34595 switch (ty.toIntern()) {
34768 switch (ty_ip) {
3459634769 .var_args_param_type => unreachable,
3459734770
3459834771 .none => unreachable,
......@@ -34673,20 +34846,15 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void {
3467334846 .empty_struct => unreachable,
3467434847 .generic_poison => unreachable,
3467534848
34676 else => switch (mod.intern_pool.items.items(.tag)[@intFromEnum(ty.toIntern())]) {
34849 else => switch (ip.items.items(.tag)[@intFromEnum(ty_ip)]) {
3467734850 .type_struct,
3467834851 .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 },
34852 .type_struct_packed,
34853 .type_struct_packed_inits,
34854 => try sema.resolveTypeFieldsStruct(ty_ip, ip.indexToKey(ty_ip).struct_type),
34855
34856 .type_union => try sema.resolveTypeFieldsUnion(ty_ip.toType(), ip.indexToKey(ty_ip).union_type),
34857 .simple_type => try sema.resolveSimpleType(ip.indexToKey(ty_ip).simple_type),
3469034858 else => {},
3469134859 },
3469234860 }
......@@ -34716,43 +34884,41 @@ fn resolveSimpleType(sema: *Sema, simple_type: InternPool.SimpleType) CompileErr
3471634884
3471734885fn resolveTypeFieldsStruct(
3471834886 sema: *Sema,
34719 ty: Type,
34720 struct_obj: *Module.Struct,
34887 ty: InternPool.Index,
34888 struct_type: InternPool.Key.StructType,
3472134889) CompileError!void {
34722 switch (sema.mod.declPtr(struct_obj.owner_decl).analysis) {
34890 const mod = sema.mod;
34891 const ip = &mod.intern_pool;
34892 // If there is no owner decl it means the struct has no fields.
34893 const owner_decl = struct_type.decl.unwrap() orelse return;
34894
34895 switch (mod.declPtr(owner_decl).analysis) {
3472334896 .file_failure,
3472434897 .dependency_failure,
3472534898 .sema_failure,
3472634899 .sema_failure_retryable,
3472734900 => {
3472834901 sema.owner_decl.analysis = .dependency_failure;
34729 sema.owner_decl.generation = sema.mod.generation;
34902 sema.owner_decl.generation = mod.generation;
3473034903 return error.AnalysisFail;
3473134904 },
3473234905 else => {},
3473334906 }
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,
34907
34908 if (struct_type.haveFieldTypes(ip)) return;
34909
34910 if (struct_type.setTypesWip(ip)) {
34911 const msg = try Module.ErrorMsg.create(
34912 sema.gpa,
34913 mod.declPtr(owner_decl).srcLoc(mod),
34914 "struct '{}' depends on itself",
34915 .{ty.toType().fmt(mod)},
34916 );
34917 return sema.failWithOwnedErrorMsg(null, msg);
3475134918 }
34919 defer struct_type.clearTypesWip(ip);
3475234920
34753 struct_obj.status = .field_types_wip;
34754 errdefer struct_obj.status = .none;
34755 try semaStructFields(sema.mod, struct_obj);
34921 try semaStructFields(mod, sema.arena, struct_type);
3475634922}
3475734923
3475834924fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Key.UnionType) CompileError!void {
......@@ -34936,12 +35102,19 @@ fn resolveInferredErrorSetTy(
3493635102 }
3493735103}
3493835104
34939fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void {
35105fn semaStructFields(
35106 mod: *Module,
35107 arena: Allocator,
35108 struct_type: InternPool.Key.StructType,
35109) CompileError!void {
3494035110 const gpa = mod.gpa;
3494135111 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;
35112 const decl_index = struct_type.decl.unwrap() orelse return;
35113 const decl = mod.declPtr(decl_index);
35114 const namespace_index = struct_type.namespace.unwrap() orelse decl.src_namespace;
35115 const zir = mod.namespacePtr(namespace_index).file_scope.zir;
35116 const zir_index = struct_type.zir_index;
35117 const extended = zir.instructions.items(.data)[zir_index].extended;
3494535118 assert(extended.opcode == .struct_decl);
3494635119 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
3494735120 var extra_index: usize = extended.operand;
......@@ -34977,18 +35150,16 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3497735150 while (decls_it.next()) |_| {}
3497835151 extra_index = decls_it.extra_index;
3497935152
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();
35153 if (fields_len == 0) switch (struct_type.layout) {
35154 .Packed => {
35155 try semaBackingIntType(mod, struct_type);
35156 return;
35157 },
35158 .Auto, .Extern => {
35159 struct_type.flagsPtr(ip).layout_resolved = true;
35160 return;
35161 },
35162 };
3499235163
3499335164 var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);
3499435165 defer comptime_mutable_decls.deinit();
......@@ -34996,7 +35167,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3499635167 var sema: Sema = .{
3499735168 .mod = mod,
3499835169 .gpa = gpa,
34999 .arena = analysis_arena.allocator(),
35170 .arena = arena,
3500035171 .code = zir,
3500135172 .owner_decl = decl,
3500235173 .owner_decl_index = decl_index,
......@@ -35013,7 +35184,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3501335184 .parent = null,
3501435185 .sema = &sema,
3501535186 .src_decl = decl_index,
35016 .namespace = struct_obj.namespace,
35187 .namespace = namespace_index,
3501735188 .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
3501835189 .instructions = .{},
3501935190 .inlining = null,
......@@ -35021,9 +35192,6 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3502135192 };
3502235193 defer assert(block_scope.instructions.items.len == 0);
3502335194
35024 struct_obj.fields = .{};
35025 try struct_obj.fields.ensureTotalCapacity(mod.tmp_hack_arena.allocator(), fields_len);
35026
3502735195 const Field = struct {
3502835196 type_body_len: u32 = 0,
3502935197 align_body_len: u32 = 0,
......@@ -35031,7 +35199,9 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3503135199 type_ref: Zir.Inst.Ref = .none,
3503235200 };
3503335201 const fields = try sema.arena.alloc(Field, fields_len);
35202
3503435203 var any_inits = false;
35204 var any_aligned = false;
3503535205
3503635206 {
3503735207 const bits_per_field = 4;
......@@ -35056,9 +35226,11 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3505635226 const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0;
3505735227 cur_bit_bag >>= 1;
3505835228
35059 var field_name_zir: ?[:0]const u8 = null;
35229 if (is_comptime) struct_type.setFieldComptime(ip, field_i);
35230
35231 var opt_field_name_zir: ?[:0]const u8 = null;
3506035232 if (!small.is_tuple) {
35061 field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]);
35233 opt_field_name_zir = zir.nullTerminatedString(zir.extra[extra_index]);
3506235234 extra_index += 1;
3506335235 }
3506435236 extra_index += 1; // doc_comment
......@@ -35073,37 +35245,27 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3507335245 extra_index += 1;
3507435246
3507535247 // 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);
35248 if (opt_field_name_zir) |field_name_zir| {
35249 const field_name = try ip.getOrPutString(gpa, field_name_zir);
35250 if (struct_type.addFieldName(ip, field_name)) |other_index| {
35251 const msg = msg: {
35252 const field_src = mod.fieldSrcLoc(decl_index, .{ .index = field_i }).lazy;
35253 const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{}'", .{field_name.fmt(ip)});
35254 errdefer msg.destroy(gpa);
3508735255
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);
35256 const prev_field_src = mod.fieldSrcLoc(decl_index, .{ .index = other_index });
35257 try mod.errNoteNonLazy(prev_field_src, msg, "other field here", .{});
35258 try sema.errNote(&block_scope, src, msg, "struct declared here", .{});
35259 break :msg msg;
35260 };
35261 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35262 }
3509535263 }
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 };
3510335264
3510435265 if (has_align) {
3510535266 fields[field_i].align_body_len = zir.extra[extra_index];
3510635267 extra_index += 1;
35268 any_aligned = true;
3510735269 }
3510835270 if (has_init) {
3510935271 fields[field_i].init_body_len = zir.extra[extra_index];
......@@ -35122,7 +35284,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3512235284 if (zir_field.type_ref != .none) {
3512335285 break :ty sema.resolveType(&block_scope, .unneeded, zir_field.type_ref) catch |err| switch (err) {
3512435286 error.NeededSourceLocation => {
35125 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
35287 const ty_src = mod.fieldSrcLoc(decl_index, .{
3512635288 .index = field_i,
3512735289 .range = .type,
3512835290 }).lazy;
......@@ -35135,10 +35297,10 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3513535297 assert(zir_field.type_body_len != 0);
3513635298 const body = zir.extra[extra_index..][0..zir_field.type_body_len];
3513735299 extra_index += body.len;
35138 const ty_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);
35300 const ty_ref = try sema.resolveBody(&block_scope, body, zir_index);
3513935301 break :ty sema.analyzeAsType(&block_scope, .unneeded, ty_ref) catch |err| switch (err) {
3514035302 error.NeededSourceLocation => {
35141 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
35303 const ty_src = mod.fieldSrcLoc(decl_index, .{
3514235304 .index = field_i,
3514335305 .range = .type,
3514435306 }).lazy;
......@@ -35152,12 +35314,11 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3515235314 return error.GenericPoison;
3515335315 }
3515435316
35155 const field = &struct_obj.fields.values()[field_i];
35156 field.ty = field_ty;
35317 struct_type.field_types.get(ip)[field_i] = field_ty.toIntern();
3515735318
3515835319 if (field_ty.zigTypeTag(mod) == .Opaque) {
3515935320 const msg = msg: {
35160 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
35321 const ty_src = mod.fieldSrcLoc(decl_index, .{
3516135322 .index = field_i,
3516235323 .range = .type,
3516335324 }).lazy;
......@@ -35171,7 +35332,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3517135332 }
3517235333 if (field_ty.zigTypeTag(mod) == .NoReturn) {
3517335334 const msg = msg: {
35174 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
35335 const ty_src = mod.fieldSrcLoc(decl_index, .{
3517535336 .index = field_i,
3517635337 .range = .type,
3517735338 }).lazy;
......@@ -35183,45 +35344,49 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3518335344 };
3518435345 return sema.failWithOwnedErrorMsg(&block_scope, msg);
3518535346 }
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);
35347 switch (struct_type.layout) {
35348 .Extern => if (!try sema.validateExternType(field_ty, .struct_field)) {
35349 const msg = msg: {
35350 const ty_src = mod.fieldSrcLoc(decl_index, .{
35351 .index = field_i,
35352 .range = .type,
35353 });
35354 const msg = try sema.errMsg(&block_scope, ty_src.lazy, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(mod)});
35355 errdefer msg.destroy(sema.gpa);
3519435356
35195 try sema.explainWhyTypeIsNotExtern(msg, ty_src, field.ty, .struct_field);
35357 try sema.explainWhyTypeIsNotExtern(msg, ty_src, field_ty, .struct_field);
3519635358
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);
35359 try sema.addDeclaredHereNote(msg, field_ty);
35360 break :msg msg;
35361 };
35362 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35363 },
35364 .Packed => if (!validatePackedType(field_ty, mod)) {
35365 const msg = msg: {
35366 const ty_src = mod.fieldSrcLoc(decl_index, .{
35367 .index = field_i,
35368 .range = .type,
35369 });
35370 const msg = try sema.errMsg(&block_scope, ty_src.lazy, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(mod)});
35371 errdefer msg.destroy(sema.gpa);
3520935372
35210 try sema.explainWhyTypeIsNotPacked(msg, ty_src, field.ty);
35373 try sema.explainWhyTypeIsNotPacked(msg, ty_src, field_ty);
3521135374
35212 try sema.addDeclaredHereNote(msg, field.ty);
35213 break :msg msg;
35214 };
35215 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35375 try sema.addDeclaredHereNote(msg, field_ty);
35376 break :msg msg;
35377 };
35378 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35379 },
35380 else => {},
3521635381 }
3521735382
3521835383 if (zir_field.align_body_len > 0) {
3521935384 const body = zir.extra[extra_index..][0..zir_field.align_body_len];
3522035385 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) {
35386 const align_ref = try sema.resolveBody(&block_scope, body, zir_index);
35387 const field_align = sema.analyzeAsAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) {
3522335388 error.NeededSourceLocation => {
35224 const align_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
35389 const align_src = mod.fieldSrcLoc(decl_index, .{
3522535390 .index = field_i,
3522635391 .range = .alignment,
3522735392 }).lazy;
......@@ -35230,36 +35395,38 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3523035395 },
3523135396 else => |e| return e,
3523235397 };
35398 struct_type.field_aligns.get(ip)[field_i] = field_align;
3523335399 }
3523435400
3523535401 extra_index += zir_field.init_body_len;
3523635402 }
3523735403
35238 struct_obj.status = .have_field_types;
35404 // TODO: there seems to be no mechanism to catch when an init depends on
35405 // another init that hasn't been resolved.
3523935406
3524035407 if (any_inits) {
3524135408 extra_index = bodies_index;
3524235409 for (fields, 0..) |zir_field, field_i| {
35410 const field_ty = struct_type.field_types.get(ip)[field_i].toType();
3524335411 extra_index += zir_field.type_body_len;
3524435412 extra_index += zir_field.align_body_len;
3524535413 if (zir_field.init_body_len > 0) {
3524635414 const body = zir.extra[extra_index..][0..zir_field.init_body_len];
3524735415 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) {
35416 const init = try sema.resolveBody(&block_scope, body, zir_index);
35417 const coerced = sema.coerce(&block_scope, field_ty, init, .unneeded) catch |err| switch (err) {
3525135418 error.NeededSourceLocation => {
35252 const init_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
35419 const init_src = mod.fieldSrcLoc(decl_index, .{
3525335420 .index = field_i,
3525435421 .range = .value,
3525535422 }).lazy;
35256 _ = try sema.coerce(&block_scope, field.ty, init, init_src);
35423 _ = try sema.coerce(&block_scope, field_ty, init, init_src);
3525735424 unreachable;
3525835425 },
3525935426 else => |e| return e,
3526035427 };
3526135428 const default_val = (try sema.resolveMaybeUndefVal(coerced)) orelse {
35262 const init_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
35429 const init_src = mod.fieldSrcLoc(decl_index, .{
3526335430 .index = field_i,
3526435431 .range = .value,
3526535432 }).lazy;
......@@ -35267,7 +35434,8 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3526735434 .needed_comptime_reason = "struct field default value must be comptime-known",
3526835435 });
3526935436 };
35270 field.default_val = try default_val.intern(field.ty, mod);
35437 const field_init = try default_val.intern(field_ty, mod);
35438 struct_type.field_inits.get(ip)[field_i] = field_init;
3527135439 }
3527235440 }
3527335441 }
......@@ -35275,8 +35443,6 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3527535443 const ct_decl = mod.declPtr(ct_decl_index);
3527635444 _ = try ct_decl.internValue(mod);
3527735445 }
35278
35279 struct_obj.have_field_inits = true;
3528035446}
3528135447
3528235448fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.UnionType) CompileError!void {
......@@ -36060,6 +36226,8 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3606036226 .type_struct,
3606136227 .type_struct_ns,
3606236228 .type_struct_anon,
36229 .type_struct_packed,
36230 .type_struct_packed_inits,
3606336231 .type_tuple_anon,
3606436232 .type_union,
3606536233 => switch (ip.indexToKey(ty.toIntern())) {
......@@ -36081,41 +36249,46 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3608136249
3608236250 .struct_type => |struct_type| {
3608336251 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 }
3610536252
36106 // In this case the struct has no runtime-known fields and
36253 if (struct_type.field_types.len == 0) {
36254 // In this case the struct has no fields at all and
3610736255 // therefore has one possible value.
3610836256 return (try mod.intern(.{ .aggregate = .{
3610936257 .ty = ty.toIntern(),
36110 .storage = .{ .elems = field_vals },
36258 .storage = .{ .elems = &.{} },
3611136259 } })).toValue();
3611236260 }
3611336261
36114 // In this case the struct has no fields at all and
36262 const field_vals = try sema.arena.alloc(
36263 InternPool.Index,
36264 struct_type.field_types.len,
36265 );
36266 for (field_vals, 0..) |*field_val, i| {
36267 if (struct_type.fieldIsComptime(ip, i)) {
36268 field_val.* = struct_type.field_inits.get(ip)[i];
36269 continue;
36270 }
36271 const field_ty = struct_type.field_types.get(ip)[i].toType();
36272 if (field_ty.eql(ty, mod)) {
36273 const msg = try Module.ErrorMsg.create(
36274 sema.gpa,
36275 mod.declPtr(struct_type.decl.unwrap().?).srcLoc(mod),
36276 "struct '{}' depends on itself",
36277 .{ty.fmt(mod)},
36278 );
36279 try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{});
36280 return sema.failWithOwnedErrorMsg(null, msg);
36281 }
36282 if (try sema.typeHasOnePossibleValue(field_ty)) |field_opv| {
36283 field_val.* = try field_opv.intern(field_ty, mod);
36284 } else return null;
36285 }
36286
36287 // In this case the struct has no runtime-known fields and
3611536288 // therefore has one possible value.
3611636289 return (try mod.intern(.{ .aggregate = .{
3611736290 .ty = ty.toIntern(),
36118 .storage = .{ .elems = &.{} },
36291 .storage = .{ .elems = field_vals },
3611936292 } })).toValue();
3612036293 },
3612136294
......@@ -36266,7 +36439,7 @@ fn analyzeComptimeAlloc(
3626636439 // Needed to make an anon decl with type `var_type` (the `finish()` call below).
3626736440 _ = try sema.typeHasOnePossibleValue(var_type);
3626836441
36269 const ptr_type = try mod.ptrType(.{
36442 const ptr_type = try sema.ptrType(.{
3627036443 .child = var_type.toIntern(),
3627136444 .flags = .{
3627236445 .alignment = alignment,
......@@ -36574,25 +36747,36 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3657436747 => true,
3657536748 },
3657636749 .struct_type => |struct_type| {
36577 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false;
36578 switch (struct_obj.requires_comptime) {
36750 if (struct_type.layout == .Packed) {
36751 // packed structs cannot be comptime-only because they have a well-defined
36752 // memory layout and every field has a well-defined bit pattern.
36753 return false;
36754 }
36755 switch (struct_type.flagsPtr(ip).requires_comptime) {
3657936756 .no, .wip => return false,
3658036757 .yes => return true,
3658136758 .unknown => {
36582 if (struct_obj.status == .field_types_wip)
36759 if (struct_type.flagsPtr(ip).field_types_wip)
3658336760 return false;
3658436761
36585 try sema.resolveTypeFieldsStruct(ty, struct_obj);
36762 try sema.resolveTypeFieldsStruct(ty.toIntern(), struct_type);
36763
36764 struct_type.flagsPtr(ip).requires_comptime = .wip;
3658636765
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;
36766 for (0..struct_type.field_types.len) |i_usize| {
36767 const i: u32 = @intCast(i_usize);
36768 if (struct_type.fieldIsComptime(ip, i)) continue;
36769 const field_ty = struct_type.field_types.get(ip)[i];
36770 if (try sema.typeRequiresComptime(field_ty.toType())) {
36771 // Note that this does not cause the layout to
36772 // be considered resolved. Comptime-only types
36773 // still maintain a layout of their
36774 // runtime-known fields.
36775 struct_type.flagsPtr(ip).requires_comptime = .yes;
3659236776 return true;
3659336777 }
3659436778 }
36595 struct_obj.requires_comptime = .no;
36779 struct_type.flagsPtr(ip).requires_comptime = .no;
3659636780 return false;
3659736781 },
3659836782 }
......@@ -36673,40 +36857,41 @@ fn typeAbiSize(sema: *Sema, ty: Type) !u64 {
3667336857 return ty.abiSize(sema.mod);
3667436858}
3667536859
36676fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!u32 {
36860fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!Alignment {
3667736861 return (try ty.abiAlignmentAdvanced(sema.mod, .{ .sema = sema })).scalar;
3667836862}
3667936863
3668036864/// Not valid to call for packed unions.
3668136865/// 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 {
36866fn unionFieldAlignment(sema: *Sema, u: InternPool.UnionType, field_index: u32) !Alignment {
3668436867 const mod = sema.mod;
3668536868 const ip = &mod.intern_pool;
36686 if (u.fieldAlign(ip, field_index).toByteUnitsOptional()) |a| return @intCast(a);
36869 const field_align = u.fieldAlign(ip, field_index);
36870 if (field_align != .none) return field_align;
3668736871 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));
36872 if (field_ty.isNoReturn(sema.mod)) return .none;
36873 return sema.typeAbiAlignment(field_ty);
3669036874}
3669136875
36692/// Keep implementation in sync with `Module.Struct.Field.alignment`.
36693fn structFieldAlignment(sema: *Sema, field: Module.Struct.Field, layout: std.builtin.Type.ContainerLayout) !u32 {
36876/// Keep implementation in sync with `Module.structFieldAlignment`.
36877fn structFieldAlignment(
36878 sema: *Sema,
36879 explicit_alignment: InternPool.Alignment,
36880 field_ty: Type,
36881 layout: std.builtin.Type.ContainerLayout,
36882) !Alignment {
36883 if (explicit_alignment != .none)
36884 return explicit_alignment;
3669436885 const mod = sema.mod;
36695 if (field.abi_align.toByteUnitsOptional()) |a| {
36696 assert(layout != .Packed);
36697 return @intCast(a);
36698 }
3669936886 switch (layout) {
36700 .Packed => return 0,
36701 .Auto => if (mod.getTarget().ofmt != .c) {
36702 return sema.typeAbiAlignment(field.ty);
36703 },
36887 .Packed => return .none,
36888 .Auto => if (mod.getTarget().ofmt != .c) return sema.typeAbiAlignment(field_ty),
3670436889 .Extern => {},
3670536890 }
3670636891 // 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);
36892 const ty_abi_align = try sema.typeAbiAlignment(field_ty);
36893 if (field_ty.isAbiInt(mod) and field_ty.intInfo(mod).bits >= 128) {
36894 return ty_abi_align.maxStrict(.@"16");
3671036895 }
3671136896 return ty_abi_align;
3671236897}
......@@ -36752,14 +36937,14 @@ fn structFieldIndex(
3675236937 field_src: LazySrcLoc,
3675336938) !u32 {
3675436939 const mod = sema.mod;
36940 const ip = &mod.intern_pool;
3675536941 try sema.resolveTypeFields(struct_ty);
3675636942 if (struct_ty.isAnonStruct(mod)) {
3675736943 return sema.anonStructFieldIndex(block, struct_ty, field_name, field_src);
3675836944 } 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);
36945 const struct_type = mod.typeToStruct(struct_ty).?;
36946 return struct_type.nameIndex(ip, field_name) orelse
36947 return sema.failWithBadStructFieldAccess(block, struct_type, field_src, field_name);
3676336948 }
3676436949}
3676536950
......@@ -36776,13 +36961,7 @@ fn anonStructFieldIndex(
3677636961 .anon_struct_type => |anon_struct_type| for (anon_struct_type.names.get(ip), 0..) |name, i| {
3677736962 if (name == field_name) return @intCast(i);
3677836963 },
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 },
36964 .struct_type => |struct_type| if (struct_type.nameIndex(ip, field_name)) |i| return i,
3678636965 else => unreachable,
3678736966 }
3678836967 return sema.fail(block, field_src, "no field named '{}' in anonymous struct '{}'", .{
......@@ -37167,8 +37346,8 @@ fn intFitsInType(
3716737346 // If it is u16 or bigger we know the alignment fits without resolving it.
3716837347 if (info.bits >= max_needed_bits) return true;
3716937348 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);
37349 if (x == .none) return true;
37350 const actual_needed_bits = @as(usize, x.toLog2Units()) + 1 + @intFromBool(info.signedness == .signed);
3717237351 return info.bits >= actual_needed_bits;
3717337352 },
3717437353 .lazy_size => |lazy_ty| {
......@@ -37381,7 +37560,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
3738137560
3738237561 const vector_info: struct {
3738337562 host_size: u16 = 0,
37384 alignment: u32 = 0,
37563 alignment: Alignment = .none,
3738537564 vector_index: VI = .none,
3738637565 } = if (parent_ty.isVector(mod) and ptr_info.flags.size == .One) blk: {
3738737566 const elem_bits = elem_ty.bitSize(mod);
......@@ -37391,7 +37570,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
3739137570
3739237571 break :blk .{
3739337572 .host_size = @intCast(parent_ty.arrayLen(mod)),
37394 .alignment = @intCast(parent_ty.abiAlignment(mod)),
37573 .alignment = parent_ty.abiAlignment(mod),
3739537574 .vector_index = if (offset) |some| @enumFromInt(some) else .runtime,
3739637575 };
3739737576 } else .{};
......@@ -37399,9 +37578,9 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
3739937578 const alignment: Alignment = a: {
3740037579 // Calculate the new pointer alignment.
3740137580 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;
37581 // In case of an ABI-aligned pointer, any pointer arithmetic
37582 // maintains the same ABI-alignedness.
37583 break :a vector_info.alignment;
3740537584 }
3740637585 // If the addend is not a comptime-known value we can still count on
3740737586 // it being a multiple of the type size.
......@@ -37413,12 +37592,12 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
3741337592 // non zero).
3741437593 const new_align: Alignment = @enumFromInt(@min(
3741537594 @ctz(addend),
37416 @intFromEnum(ptr_info.flags.alignment),
37595 ptr_info.flags.alignment.toLog2Units(),
3741737596 ));
3741837597 assert(new_align != .none);
3741937598 break :a new_align;
3742037599 };
37421 return mod.ptrType(.{
37600 return sema.ptrType(.{
3742237601 .child = elem_ty.toIntern(),
3742337602 .flags = .{
3742437603 .alignment = alignment,
......@@ -37473,3 +37652,10 @@ fn isKnownZigType(sema: *Sema, ref: Air.Inst.Ref, tag: std.builtin.TypeId) bool
3747337652 };
3747437653 return sema.typeOf(ref).zigTypeTag(sema.mod) == tag;
3747537654}
37655
37656fn ptrType(sema: *Sema, info: InternPool.Key.PtrType) CompileError!Type {
37657 if (info.flags.alignment != .none) {
37658 _ = try sema.typeAbiAlignment(info.child.toType());
37659 }
37660 return sema.mod.ptrType(info);
37661}
src/TypedValue.zig+13-8
......@@ -135,9 +135,10 @@ pub fn print(
135135
136136 var i: u32 = 0;
137137 while (i < max_len) : (i += 1) {
138 const elem_val = payload.ptr.elemValue(mod, i) catch |err| switch (err) {
138 const maybe_elem_val = payload.ptr.maybeElemValue(mod, i) catch |err| switch (err) {
139139 error.OutOfMemory => @panic("OOM"), // TODO: eliminate this panic
140140 };
141 const elem_val = maybe_elem_val orelse return writer.writeAll(".{ (reinterpreted data) }");
141142 if (elem_val.isUndef(mod)) break :str;
142143 buf[i] = std.math.cast(u8, elem_val.toUnsignedInt(mod)) orelse break :str;
143144 }
......@@ -153,9 +154,10 @@ pub fn print(
153154 var i: u32 = 0;
154155 while (i < max_len) : (i += 1) {
155156 if (i != 0) try writer.writeAll(", ");
156 const elem_val = payload.ptr.elemValue(mod, i) catch |err| switch (err) {
157 const maybe_elem_val = payload.ptr.maybeElemValue(mod, i) catch |err| switch (err) {
157158 error.OutOfMemory => @panic("OOM"), // TODO: eliminate this panic
158159 };
160 const elem_val = maybe_elem_val orelse return writer.writeAll("(reinterpreted data) }");
159161 try print(.{
160162 .ty = elem_ty,
161163 .val = elem_val,
......@@ -272,7 +274,8 @@ pub fn print(
272274 const max_len = @min(len, max_string_len);
273275 var buf: [max_string_len]u8 = undefined;
274276 for (buf[0..max_len], 0..) |*c, i| {
275 const elem = try val.elemValue(mod, i);
277 const maybe_elem = try val.maybeElemValue(mod, i);
278 const elem = maybe_elem orelse return writer.writeAll(".{ (reinterpreted data) }");
276279 if (elem.isUndef(mod)) break :str;
277280 c.* = @as(u8, @intCast(elem.toUnsignedInt(mod)));
278281 }
......@@ -283,9 +286,11 @@ pub fn print(
283286 const max_len = @min(len, max_aggregate_items);
284287 for (0..max_len) |i| {
285288 if (i != 0) try writer.writeAll(", ");
289 const maybe_elem = try val.maybeElemValue(mod, i);
290 const elem = maybe_elem orelse return writer.writeAll("(reinterpreted data) }");
286291 try print(.{
287292 .ty = elem_ty,
288 .val = try val.elemValue(mod, i),
293 .val = elem,
289294 }, writer, level - 1, mod);
290295 }
291296 if (len > max_aggregate_items) {
......@@ -350,11 +355,11 @@ pub fn print(
350355 const container_ty = ptr_container_ty.childType(mod);
351356 switch (container_ty.zigTypeTag(mod)) {
352357 .Struct => {
353 if (container_ty.isTuple(mod)) {
358 if (container_ty.structFieldName(@intCast(field.index), mod).unwrap()) |field_name| {
359 try writer.print(".{i}", .{field_name.fmt(ip)});
360 } else {
354361 try writer.print("[{d}]", .{field.index});
355362 }
356 const field_name = container_ty.structFieldName(@as(usize, @intCast(field.index)), mod);
357 try writer.print(".{i}", .{field_name.fmt(ip)});
358363 },
359364 .Union => {
360365 const field_name = mod.typeToUnion(container_ty).?.field_names.get(ip)[@intCast(field.index)];
......@@ -432,7 +437,7 @@ fn printAggregate(
432437 if (i != 0) try writer.writeAll(", ");
433438
434439 const field_name = switch (ip.indexToKey(ty.toIntern())) {
435 .struct_type => |x| mod.structPtrUnwrap(x.index).?.fields.keys()[i].toOptional(),
440 .struct_type => |x| x.fieldName(ip, i),
436441 .anon_struct_type => |x| if (x.isTuple()) .none else x.names.get(ip)[i].toOptional(),
437442 else => unreachable,
438443 };
src/Zir.zig+4-1
......@@ -2840,7 +2840,10 @@ pub const Inst = struct {
28402840 is_tuple: bool,
28412841 name_strategy: NameStrategy,
28422842 layout: std.builtin.Type.ContainerLayout,
2843 _: u5 = undefined,
2843 any_default_inits: bool,
2844 any_comptime_fields: bool,
2845 any_aligned_fields: bool,
2846 _: u2 = undefined,
28442847 };
28452848 };
28462849
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+16-18
......@@ -28,20 +28,22 @@ pub fn classifyType(ty: Type, mod: *Module) [2]Class {
2828 if (!ty.hasRuntimeBitsIgnoreComptime(mod)) return none;
2929 switch (ty.zigTypeTag(mod)) {
3030 .Struct => {
31 if (ty.containerLayout(mod) == .Packed) {
31 const struct_type = mod.typeToStruct(ty).?;
32 if (struct_type.layout == .Packed) {
3233 if (ty.bitSize(mod) <= 64) return direct;
3334 return .{ .direct, .direct };
3435 }
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)) {
36 if (struct_type.field_types.len > 1) {
37 // The struct type is non-scalar.
38 return memory;
39 }
40 const field_ty = struct_type.field_types.get(ip)[0].toType();
41 const explicit_align = struct_type.fieldAlign(ip, 0);
42 if (explicit_align != .none) {
43 if (explicit_align.compareStrict(.gt, field_ty.abiAlignment(mod)))
4144 return memory;
42 }
4345 }
44 return classifyType(field.ty, mod);
46 return classifyType(field_ty, mod);
4547 },
4648 .Int, .Enum, .ErrorSet, .Vector => {
4749 const int_bits = ty.intInfo(mod).bits;
......@@ -101,15 +103,11 @@ pub fn scalarType(ty: Type, mod: *Module) Type {
101103 const ip = &mod.intern_pool;
102104 switch (ty.zigTypeTag(mod)) {
103105 .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 },
106 if (mod.typeToPackedStruct(ty)) |packed_struct| {
107 return scalarType(packed_struct.backingIntType(ip).toType(), mod);
108 } else {
109 assert(ty.structFieldCount(mod) == 1);
110 return scalarType(ty.structFieldType(0, mod), mod);
113111 }
114112 },
115113 .Union => {
src/arch/x86_64/CodeGen.zig+61-58
......@@ -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,13 +11420,14 @@ 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 },
1142511427 .{ .immediate = result_ty.abiSize(mod) },
1142611428 );
11427 for (elements, 0..) |elem, elem_i| {
11429 for (elements, 0..) |elem, elem_i_usize| {
11430 const elem_i: u32 = @intCast(elem_i_usize);
1142811431 if ((try result_ty.structFieldValueComptime(mod, elem_i)) != null) continue;
1142911432
1143011433 const elem_ty = result_ty.structFieldType(elem_i, mod);
......@@ -11437,7 +11440,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
1143711440 }
1143811441 const elem_abi_size: u32 = @intCast(elem_ty.abiSize(mod));
1143911442 const elem_abi_bits = elem_abi_size * 8;
11440 const elem_off = struct_obj.packedFieldBitOffset(mod, elem_i);
11443 const elem_off = mod.structPackedFieldBitOffset(struct_type, elem_i);
1144111444 const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size);
1144211445 const elem_bit_off = elem_off % elem_abi_bits;
1144311446 const elem_mcv = try self.resolveInst(elem);
......@@ -11576,13 +11579,13 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
1157611579 const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index);
1157711580 const tag_int_val = try tag_val.intFromEnum(tag_ty, mod);
1157811581 const tag_int = tag_int_val.toUnsignedInt(mod);
11579 const tag_off: i32 = if (layout.tag_align < layout.payload_align)
11582 const tag_off: i32 = if (layout.tag_align.compare(.lt, layout.payload_align))
1158011583 @intCast(layout.payload_size)
1158111584 else
1158211585 0;
1158311586 try self.genCopy(tag_ty, dst_mcv.address().offset(tag_off).deref(), .{ .immediate = tag_int });
1158411587
11585 const pl_off: i32 = if (layout.tag_align < layout.payload_align)
11588 const pl_off: i32 = if (layout.tag_align.compare(.lt, layout.payload_align))
1158611589 0
1158711590 else
1158811591 @intCast(layout.tag_size);
......@@ -11823,7 +11826,7 @@ const CallMCValues = struct {
1182311826 args: []MCValue,
1182411827 return_value: InstTracking,
1182511828 stack_byte_count: u31,
11826 stack_align: u31,
11829 stack_align: Alignment,
1182711830
1182811831 fn deinit(self: *CallMCValues, func: *Self) void {
1182911832 func.gpa.free(self.args);
......@@ -11867,12 +11870,12 @@ fn resolveCallingConventionValues(
1186711870 .Naked => {
1186811871 assert(result.args.len == 0);
1186911872 result.return_value = InstTracking.init(.unreach);
11870 result.stack_align = 8;
11873 result.stack_align = .@"8";
1187111874 },
1187211875 .C => {
1187311876 var param_reg_i: usize = 0;
1187411877 var param_sse_reg_i: usize = 0;
11875 result.stack_align = 16;
11878 result.stack_align = .@"16";
1187611879
1187711880 switch (self.target.os.tag) {
1187811881 .windows => {
......@@ -11957,7 +11960,7 @@ fn resolveCallingConventionValues(
1195711960 }
1195811961
1195911962 const param_size: u31 = @intCast(ty.abiSize(mod));
11960 const param_align: u31 = @intCast(ty.abiAlignment(mod));
11963 const param_align: u31 = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?);
1196111964 result.stack_byte_count =
1196211965 mem.alignForward(u31, result.stack_byte_count, param_align);
1196311966 arg.* = .{ .load_frame = .{
......@@ -11968,7 +11971,7 @@ fn resolveCallingConventionValues(
1196811971 }
1196911972 },
1197011973 .Unspecified => {
11971 result.stack_align = 16;
11974 result.stack_align = .@"16";
1197211975
1197311976 // Return values
1197411977 if (ret_ty.zigTypeTag(mod) == .NoReturn) {
......@@ -11997,7 +12000,7 @@ fn resolveCallingConventionValues(
1199712000 continue;
1199812001 }
1199912002 const param_size: u31 = @intCast(ty.abiSize(mod));
12000 const param_align: u31 = @intCast(ty.abiAlignment(mod));
12003 const param_align: u31 = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?);
1200112004 result.stack_byte_count =
1200212005 mem.alignForward(u31, result.stack_byte_count, param_align);
1200312006 arg.* = .{ .load_frame = .{
......@@ -12010,7 +12013,7 @@ fn resolveCallingConventionValues(
1201012013 else => return self.fail("TODO implement function parameters and return values for {} on x86_64", .{cc}),
1201112014 }
1201212015
12013 result.stack_byte_count = mem.alignForward(u31, result.stack_byte_count, result.stack_align);
12016 result.stack_byte_count = @intCast(result.stack_align.forward(result.stack_byte_count));
1201412017 return result;
1201512018}
1201612019
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+54-47
......@@ -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,9 +702,9 @@ 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,
705 .Packed => if (mod.typeToStruct(base_type.toType())) |struct_type|
706 math.divExact(u16, mod.structPackedFieldBitOffset(
707 struct_type,
701708 @intCast(field.index),
702709 ), 8) catch |err| switch (err) {
703710 error.UnexpectedRemainder => 0,
......@@ -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+138-140
......@@ -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 for (0..struct_type.field_types.len) |field_i| {
1314 const field_ty = struct_type.field_types.get(ip)[field_i].toType();
1315 if (struct_type.fieldIsComptime(ip, field_i)) continue;
1316 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
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.toIntern(),
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, 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);
......@@ -5230,7 +5226,8 @@ fn fieldLocation(
52305226 const container_ty = container_ptr_ty.childType(mod);
52315227 return switch (container_ty.zigTypeTag(mod)) {
52325228 .Struct => switch (container_ty.containerLayout(mod)) {
5233 .Auto, .Extern => for (field_index..container_ty.structFieldCount(mod)) |next_field_index| {
5229 .Auto, .Extern => for (field_index..container_ty.structFieldCount(mod)) |next_field_index_usize| {
5230 const next_field_index: u32 = @intCast(next_field_index_usize);
52345231 if (container_ty.structFieldIsComptime(next_field_index, mod)) continue;
52355232 const field_ty = container_ty.structFieldType(next_field_index, mod);
52365233 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
......@@ -5238,7 +5235,7 @@ fn fieldLocation(
52385235 break .{ .field = if (container_ty.isSimpleTuple(mod))
52395236 .{ .field = next_field_index }
52405237 else
5241 .{ .identifier = ip.stringToSlice(container_ty.structFieldName(next_field_index, mod)) } };
5238 .{ .identifier = ip.stringToSlice(container_ty.legacyStructFieldName(next_field_index, mod)) } };
52425239 } else if (container_ty.hasRuntimeBitsIgnoreComptime(mod)) .end else .begin,
52435240 .Packed => if (field_ptr_ty.ptrInfo(mod).packed_offset.host_size == 0)
52445241 .{ .byte_offset = container_ty.packedStructFieldByteOffset(field_index, mod) + @divExact(container_ptr_ty.ptrInfo(mod).packed_offset.bit_offset, 8) }
......@@ -5425,14 +5422,14 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
54255422 .Auto, .Extern => if (struct_ty.isSimpleTuple(mod))
54265423 .{ .field = extra.field_index }
54275424 else
5428 .{ .identifier = ip.stringToSlice(struct_ty.structFieldName(extra.field_index, mod)) },
5425 .{ .identifier = ip.stringToSlice(struct_ty.legacyStructFieldName(extra.field_index, mod)) },
54295426 .Packed => {
5430 const struct_obj = mod.typeToStruct(struct_ty).?;
5427 const struct_type = mod.typeToStruct(struct_ty).?;
54315428 const int_info = struct_ty.intInfo(mod);
54325429
54335430 const bit_offset_ty = try mod.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1));
54345431
5435 const bit_offset = struct_obj.packedFieldBitOffset(mod, extra.field_index);
5432 const bit_offset = mod.structPackedFieldBitOffset(struct_type, extra.field_index);
54365433 const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset);
54375434
54385435 const field_int_signedness = if (inst_ty.isAbiInt(mod))
......@@ -5487,7 +5484,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
54875484 .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len == 0)
54885485 .{ .field = extra.field_index }
54895486 else
5490 .{ .identifier = ip.stringToSlice(struct_ty.structFieldName(extra.field_index, mod)) },
5487 .{ .identifier = ip.stringToSlice(struct_ty.legacyStructFieldName(extra.field_index, mod)) },
54915488
54925489 .union_type => |union_type| field_name: {
54935490 const union_obj = ip.loadUnionType(union_type);
......@@ -6820,7 +6817,8 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
68206817 }
68216818 },
68226819 .Struct => switch (inst_ty.containerLayout(mod)) {
6823 .Auto, .Extern => for (resolved_elements, 0..) |element, field_i| {
6820 .Auto, .Extern => for (resolved_elements, 0..) |element, field_i_usize| {
6821 const field_i: u32 = @intCast(field_i_usize);
68246822 if (inst_ty.structFieldIsComptime(field_i, mod)) continue;
68256823 const field_ty = inst_ty.structFieldType(field_i, mod);
68266824 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
......@@ -6829,7 +6827,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
68296827 try f.writeCValueMember(writer, local, if (inst_ty.isSimpleTuple(mod))
68306828 .{ .field = field_i }
68316829 else
6832 .{ .identifier = ip.stringToSlice(inst_ty.structFieldName(field_i, mod)) });
6830 .{ .identifier = ip.stringToSlice(inst_ty.legacyStructFieldName(field_i, mod)) });
68336831 try a.assign(f, writer);
68346832 try f.writeCValue(writer, element, .Other);
68356833 try a.end(f, writer);
src/codegen/c/type.zig+24-15
......@@ -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) {
......@@ -1947,7 +1953,8 @@ pub const CType = extern union {
19471953
19481954 const fields_pl = try arena.alloc(Payload.Fields.Field, c_fields_len);
19491955 var c_field_i: usize = 0;
1950 for (0..fields_len) |field_i| {
1956 for (0..fields_len) |field_i_usize| {
1957 const field_i: u32 = @intCast(field_i_usize);
19511958 const field_ty = ty.structFieldType(field_i, mod);
19521959 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or
19531960 !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
......@@ -1958,7 +1965,7 @@ pub const CType = extern union {
19581965 std.fmt.allocPrintZ(arena, "f{}", .{field_i})
19591966 else
19601967 arena.dupeZ(u8, ip.stringToSlice(switch (zig_ty_tag) {
1961 .Struct => ty.structFieldName(field_i, mod),
1968 .Struct => ty.legacyStructFieldName(field_i, mod),
19621969 .Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i],
19631970 else => unreachable,
19641971 })),
......@@ -2091,7 +2098,8 @@ pub const CType = extern union {
20912098 .Struct => ty.structFieldCount(mod),
20922099 .Union => mod.typeToUnion(ty).?.field_names.len,
20932100 else => unreachable,
2094 }) |field_i| {
2101 }) |field_i_usize| {
2102 const field_i: u32 = @intCast(field_i_usize);
20952103 const field_ty = ty.structFieldType(field_i, mod);
20962104 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or
20972105 !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
......@@ -2110,7 +2118,7 @@ pub const CType = extern union {
21102118 std.fmt.bufPrintZ(&name_buf, "f{}", .{field_i}) catch unreachable
21112119 else
21122120 ip.stringToSlice(switch (zig_ty_tag) {
2113 .Struct => ty.structFieldName(field_i, mod),
2121 .Struct => ty.legacyStructFieldName(field_i, mod),
21142122 .Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i],
21152123 else => unreachable,
21162124 }),
......@@ -2219,7 +2227,8 @@ pub const CType = extern union {
22192227 .Struct => ty.structFieldCount(mod),
22202228 .Union => mod.typeToUnion(ty).?.field_names.len,
22212229 else => unreachable,
2222 }) |field_i| {
2230 }) |field_i_usize| {
2231 const field_i: u32 = @intCast(field_i_usize);
22232232 const field_ty = ty.structFieldType(field_i, mod);
22242233 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or
22252234 !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
......@@ -2234,7 +2243,7 @@ pub const CType = extern union {
22342243 std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable
22352244 else
22362245 mod.intern_pool.stringToSlice(switch (zig_ty_tag) {
2237 .Struct => ty.structFieldName(field_i, mod),
2246 .Struct => ty.legacyStructFieldName(field_i, mod),
22382247 .Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i],
22392248 else => unreachable,
22402249 }));
src/codegen/llvm.zig+341-295
......@@ -833,7 +833,10 @@ pub const Object = struct {
833833
834834 /// When an LLVM struct type is created, an entry is inserted into this
835835 /// table for every zig source field of the struct that has a corresponding
836 /// LLVM struct field. comptime fields and 0 bit fields are not included.
836 /// LLVM struct field. comptime fields are not included. Zero-bit fields are
837 /// mapped to a field at the correct byte, which may be a padding field, or
838 /// are not mapped, in which case they are sematically at the end of the
839 /// struct.
837840 /// The value is the LLVM struct field index.
838841 /// This is denormalized data.
839842 struct_field_map: std.AutoHashMapUnmanaged(ZigStructField, c_uint),
......@@ -1076,7 +1079,7 @@ pub const Object = struct {
10761079 table_variable_index.setMutability(.constant, &o.builder);
10771080 table_variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
10781081 table_variable_index.setAlignment(
1079 Builder.Alignment.fromByteUnits(slice_ty.abiAlignment(mod)),
1082 slice_ty.abiAlignment(mod).toLlvm(),
10801083 &o.builder,
10811084 );
10821085
......@@ -1318,8 +1321,9 @@ pub const Object = struct {
13181321 _ = try attributes.removeFnAttr(.@"noinline");
13191322 }
13201323
1321 if (func.analysis(ip).stack_alignment.toByteUnitsOptional()) |alignment| {
1322 try attributes.addFnAttr(.{ .alignstack = Builder.Alignment.fromByteUnits(alignment) }, &o.builder);
1324 const stack_alignment = func.analysis(ip).stack_alignment;
1325 if (stack_alignment != .none) {
1326 try attributes.addFnAttr(.{ .alignstack = stack_alignment.toLlvm() }, &o.builder);
13231327 try attributes.addFnAttr(.@"noinline", &o.builder);
13241328 } else {
13251329 _ = try attributes.removeFnAttr(.alignstack);
......@@ -1407,7 +1411,7 @@ pub const Object = struct {
14071411 const param = wip.arg(llvm_arg_i);
14081412
14091413 if (isByRef(param_ty, mod)) {
1410 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
1414 const alignment = param_ty.abiAlignment(mod).toLlvm();
14111415 const param_llvm_ty = param.typeOfWip(&wip);
14121416 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
14131417 _ = try wip.store(.normal, param, arg_ptr, alignment);
......@@ -1423,7 +1427,7 @@ pub const Object = struct {
14231427 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
14241428 const param_llvm_ty = try o.lowerType(param_ty);
14251429 const param = wip.arg(llvm_arg_i);
1426 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
1430 const alignment = param_ty.abiAlignment(mod).toLlvm();
14271431
14281432 try o.addByRefParamAttrs(&attributes, llvm_arg_i, alignment, it.byval_attr, param_llvm_ty);
14291433 llvm_arg_i += 1;
......@@ -1438,7 +1442,7 @@ pub const Object = struct {
14381442 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
14391443 const param_llvm_ty = try o.lowerType(param_ty);
14401444 const param = wip.arg(llvm_arg_i);
1441 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
1445 const alignment = param_ty.abiAlignment(mod).toLlvm();
14421446
14431447 try attributes.addParamAttr(llvm_arg_i, .noundef, &o.builder);
14441448 llvm_arg_i += 1;
......@@ -1456,7 +1460,7 @@ pub const Object = struct {
14561460 llvm_arg_i += 1;
14571461
14581462 const param_llvm_ty = try o.lowerType(param_ty);
1459 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
1463 const alignment = param_ty.abiAlignment(mod).toLlvm();
14601464 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
14611465 _ = try wip.store(.normal, param, arg_ptr, alignment);
14621466
......@@ -1481,10 +1485,10 @@ pub const Object = struct {
14811485 if (ptr_info.flags.is_const) {
14821486 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
14831487 }
1484 const elem_align = Builder.Alignment.fromByteUnits(
1485 ptr_info.flags.alignment.toByteUnitsOptional() orelse
1486 @max(ptr_info.child.toType().abiAlignment(mod), 1),
1487 );
1488 const elem_align = (if (ptr_info.flags.alignment != .none)
1489 @as(InternPool.Alignment, ptr_info.flags.alignment)
1490 else
1491 ptr_info.child.toType().abiAlignment(mod).max(.@"1")).toLlvm();
14881492 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
14891493 const ptr_param = wip.arg(llvm_arg_i);
14901494 llvm_arg_i += 1;
......@@ -1501,7 +1505,7 @@ pub const Object = struct {
15011505 const field_types = it.types_buffer[0..it.types_len];
15021506 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
15031507 const param_llvm_ty = try o.lowerType(param_ty);
1504 const param_alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
1508 const param_alignment = param_ty.abiAlignment(mod).toLlvm();
15051509 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, param_alignment, target);
15061510 const llvm_ty = try o.builder.structType(.normal, field_types);
15071511 for (0..field_types.len) |field_i| {
......@@ -1531,7 +1535,7 @@ pub const Object = struct {
15311535 const param = wip.arg(llvm_arg_i);
15321536 llvm_arg_i += 1;
15331537
1534 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
1538 const alignment = param_ty.abiAlignment(mod).toLlvm();
15351539 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
15361540 _ = try wip.store(.normal, param, arg_ptr, alignment);
15371541
......@@ -1546,7 +1550,7 @@ pub const Object = struct {
15461550 const param = wip.arg(llvm_arg_i);
15471551 llvm_arg_i += 1;
15481552
1549 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
1553 const alignment = param_ty.abiAlignment(mod).toLlvm();
15501554 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
15511555 _ = try wip.store(.normal, param, arg_ptr, alignment);
15521556
......@@ -1967,7 +1971,7 @@ pub const Object = struct {
19671971 di_file,
19681972 owner_decl.src_node + 1,
19691973 ty.abiSize(mod) * 8,
1970 ty.abiAlignment(mod) * 8,
1974 ty.abiAlignment(mod).toByteUnits(0) * 8,
19711975 enumerators.ptr,
19721976 @intCast(enumerators.len),
19731977 try o.lowerDebugType(int_ty, .full),
......@@ -2055,7 +2059,7 @@ pub const Object = struct {
20552059
20562060 var offset: u64 = 0;
20572061 offset += ptr_size;
2058 offset = std.mem.alignForward(u64, offset, len_align);
2062 offset = len_align.forward(offset);
20592063 const len_offset = offset;
20602064
20612065 const fields: [2]*llvm.DIType = .{
......@@ -2065,7 +2069,7 @@ pub const Object = struct {
20652069 di_file,
20662070 line,
20672071 ptr_size * 8, // size in bits
2068 ptr_align * 8, // align in bits
2072 ptr_align.toByteUnits(0) * 8, // align in bits
20692073 0, // offset in bits
20702074 0, // flags
20712075 try o.lowerDebugType(ptr_ty, .full),
......@@ -2076,7 +2080,7 @@ pub const Object = struct {
20762080 di_file,
20772081 line,
20782082 len_size * 8, // size in bits
2079 len_align * 8, // align in bits
2083 len_align.toByteUnits(0) * 8, // align in bits
20802084 len_offset * 8, // offset in bits
20812085 0, // flags
20822086 try o.lowerDebugType(len_ty, .full),
......@@ -2089,7 +2093,7 @@ pub const Object = struct {
20892093 di_file,
20902094 line,
20912095 ty.abiSize(mod) * 8, // size in bits
2092 ty.abiAlignment(mod) * 8, // align in bits
2096 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
20932097 0, // flags
20942098 null, // derived from
20952099 &fields,
......@@ -2110,7 +2114,7 @@ pub const Object = struct {
21102114 const ptr_di_ty = dib.createPointerType(
21112115 elem_di_ty,
21122116 target.ptrBitWidth(),
2113 ty.ptrAlignment(mod) * 8,
2117 ty.ptrAlignment(mod).toByteUnits(0) * 8,
21142118 name,
21152119 );
21162120 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
......@@ -2142,7 +2146,7 @@ pub const Object = struct {
21422146 .Array => {
21432147 const array_di_ty = dib.createArrayType(
21442148 ty.abiSize(mod) * 8,
2145 ty.abiAlignment(mod) * 8,
2149 ty.abiAlignment(mod).toByteUnits(0) * 8,
21462150 try o.lowerDebugType(ty.childType(mod), .full),
21472151 @intCast(ty.arrayLen(mod)),
21482152 );
......@@ -2174,7 +2178,7 @@ pub const Object = struct {
21742178
21752179 const vector_di_ty = dib.createVectorType(
21762180 ty.abiSize(mod) * 8,
2177 ty.abiAlignment(mod) * 8,
2181 @intCast(ty.abiAlignment(mod).toByteUnits(0) * 8),
21782182 elem_di_type,
21792183 ty.vectorLen(mod),
21802184 );
......@@ -2223,7 +2227,7 @@ pub const Object = struct {
22232227
22242228 var offset: u64 = 0;
22252229 offset += payload_size;
2226 offset = std.mem.alignForward(u64, offset, non_null_align);
2230 offset = non_null_align.forward(offset);
22272231 const non_null_offset = offset;
22282232
22292233 const fields: [2]*llvm.DIType = .{
......@@ -2233,7 +2237,7 @@ pub const Object = struct {
22332237 di_file,
22342238 line,
22352239 payload_size * 8, // size in bits
2236 payload_align * 8, // align in bits
2240 payload_align.toByteUnits(0) * 8, // align in bits
22372241 0, // offset in bits
22382242 0, // flags
22392243 try o.lowerDebugType(child_ty, .full),
......@@ -2244,7 +2248,7 @@ pub const Object = struct {
22442248 di_file,
22452249 line,
22462250 non_null_size * 8, // size in bits
2247 non_null_align * 8, // align in bits
2251 non_null_align.toByteUnits(0) * 8, // align in bits
22482252 non_null_offset * 8, // offset in bits
22492253 0, // flags
22502254 try o.lowerDebugType(non_null_ty, .full),
......@@ -2257,7 +2261,7 @@ pub const Object = struct {
22572261 di_file,
22582262 line,
22592263 ty.abiSize(mod) * 8, // size in bits
2260 ty.abiAlignment(mod) * 8, // align in bits
2264 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
22612265 0, // flags
22622266 null, // derived from
22632267 &fields,
......@@ -2306,16 +2310,16 @@ pub const Object = struct {
23062310 var payload_index: u32 = undefined;
23072311 var error_offset: u64 = undefined;
23082312 var payload_offset: u64 = undefined;
2309 if (error_align > payload_align) {
2313 if (error_align.compare(.gt, payload_align)) {
23102314 error_index = 0;
23112315 payload_index = 1;
23122316 error_offset = 0;
2313 payload_offset = std.mem.alignForward(u64, error_size, payload_align);
2317 payload_offset = payload_align.forward(error_size);
23142318 } else {
23152319 payload_index = 0;
23162320 error_index = 1;
23172321 payload_offset = 0;
2318 error_offset = std.mem.alignForward(u64, payload_size, error_align);
2322 error_offset = error_align.forward(payload_size);
23192323 }
23202324
23212325 var fields: [2]*llvm.DIType = undefined;
......@@ -2325,7 +2329,7 @@ pub const Object = struct {
23252329 di_file,
23262330 line,
23272331 error_size * 8, // size in bits
2328 error_align * 8, // align in bits
2332 error_align.toByteUnits(0) * 8, // align in bits
23292333 error_offset * 8, // offset in bits
23302334 0, // flags
23312335 try o.lowerDebugType(Type.anyerror, .full),
......@@ -2336,7 +2340,7 @@ pub const Object = struct {
23362340 di_file,
23372341 line,
23382342 payload_size * 8, // size in bits
2339 payload_align * 8, // align in bits
2343 payload_align.toByteUnits(0) * 8, // align in bits
23402344 payload_offset * 8, // offset in bits
23412345 0, // flags
23422346 try o.lowerDebugType(payload_ty, .full),
......@@ -2348,7 +2352,7 @@ pub const Object = struct {
23482352 di_file,
23492353 line,
23502354 ty.abiSize(mod) * 8, // size in bits
2351 ty.abiAlignment(mod) * 8, // align in bits
2355 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
23522356 0, // flags
23532357 null, // derived from
23542358 &fields,
......@@ -2374,10 +2378,10 @@ pub const Object = struct {
23742378 const name = try o.allocTypeName(ty);
23752379 defer gpa.free(name);
23762380
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);
2381 if (mod.typeToPackedStruct(ty)) |struct_type| {
2382 const backing_int_ty = struct_type.backingIntType(ip).*;
2383 if (backing_int_ty != .none) {
2384 const info = backing_int_ty.toType().intInfo(mod);
23812385 const dwarf_encoding: c_uint = switch (info.signedness) {
23822386 .signed => DW.ATE.signed,
23832387 .unsigned => DW.ATE.unsigned,
......@@ -2417,7 +2421,7 @@ pub const Object = struct {
24172421
24182422 const field_size = field_ty.toType().abiSize(mod);
24192423 const field_align = field_ty.toType().abiAlignment(mod);
2420 const field_offset = std.mem.alignForward(u64, offset, field_align);
2424 const field_offset = field_align.forward(offset);
24212425 offset = field_offset + field_size;
24222426
24232427 const field_name = if (tuple.names.len != 0)
......@@ -2432,7 +2436,7 @@ pub const Object = struct {
24322436 null, // file
24332437 0, // line
24342438 field_size * 8, // size in bits
2435 field_align * 8, // align in bits
2439 field_align.toByteUnits(0) * 8, // align in bits
24362440 field_offset * 8, // offset in bits
24372441 0, // flags
24382442 try o.lowerDebugType(field_ty.toType(), .full),
......@@ -2445,7 +2449,7 @@ pub const Object = struct {
24452449 null, // file
24462450 0, // line
24472451 ty.abiSize(mod) * 8, // size in bits
2448 ty.abiAlignment(mod) * 8, // align in bits
2452 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
24492453 0, // flags
24502454 null, // derived from
24512455 di_fields.items.ptr,
......@@ -2459,10 +2463,8 @@ pub const Object = struct {
24592463 try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(full_di_ty));
24602464 return full_di_ty;
24612465 },
2462 .struct_type => |struct_type| s: {
2463 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :s;
2464
2465 if (!struct_obj.haveFieldTypes()) {
2466 .struct_type => |struct_type| {
2467 if (!struct_type.haveFieldTypes(ip)) {
24662468 // This can happen if a struct type makes it all the way to
24672469 // flush() without ever being instantiated or referenced (even
24682470 // via pointer). The only reason we are hearing about it now is
......@@ -2492,37 +2494,41 @@ pub const Object = struct {
24922494 return struct_di_ty;
24932495 }
24942496
2495 const fields = ty.structFields(mod);
2496 const layout = ty.containerLayout(mod);
2497 const struct_type = mod.typeToStruct(ty).?;
24972498
24982499 var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
24992500 defer di_fields.deinit(gpa);
25002501
2501 try di_fields.ensureUnusedCapacity(gpa, fields.count());
2502 try di_fields.ensureUnusedCapacity(gpa, struct_type.field_types.len);
25022503
25032504 comptime assert(struct_layout_version == 2);
2504 var offset: u64 = 0;
2505 var it = struct_type.iterateRuntimeOrder(ip);
2506 while (it.next()) |field_index| {
2507 const field_ty = struct_type.field_types.get(ip)[field_index].toType();
2508 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
2509 const field_size = field_ty.abiSize(mod);
2510 const field_align = mod.structFieldAlignment(
2511 struct_type.fieldAlign(ip, field_index),
2512 field_ty,
2513 struct_type.layout,
2514 );
2515 const field_offset = ty.structFieldOffset(field_index, mod);
25052516
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);
2512 offset = field_offset + field_size;
2517 const field_name = struct_type.fieldName(ip, field_index).unwrap() orelse
2518 try ip.getOrPutStringFmt(gpa, "{d}", .{field_index});
25132519
2514 const field_name = ip.stringToSlice(fields.keys()[field_and_index.index]);
2520 const field_di_ty = try o.lowerDebugType(field_ty, .full);
25152521
25162522 try di_fields.append(gpa, dib.createMemberType(
25172523 fwd_decl.toScope(),
2518 field_name,
2524 ip.stringToSlice(field_name),
25192525 null, // file
25202526 0, // line
25212527 field_size * 8, // size in bits
2522 field_align * 8, // align in bits
2528 field_align.toByteUnits(0) * 8, // align in bits
25232529 field_offset * 8, // offset in bits
25242530 0, // flags
2525 try o.lowerDebugType(field.ty, .full),
2531 field_di_ty,
25262532 ));
25272533 }
25282534
......@@ -2532,7 +2538,7 @@ pub const Object = struct {
25322538 null, // file
25332539 0, // line
25342540 ty.abiSize(mod) * 8, // size in bits
2535 ty.abiAlignment(mod) * 8, // align in bits
2541 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
25362542 0, // flags
25372543 null, // derived from
25382544 di_fields.items.ptr,
......@@ -2588,7 +2594,7 @@ pub const Object = struct {
25882594 null, // file
25892595 0, // line
25902596 ty.abiSize(mod) * 8, // size in bits
2591 ty.abiAlignment(mod) * 8, // align in bits
2597 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
25922598 0, // flags
25932599 null, // derived from
25942600 &di_fields,
......@@ -2624,7 +2630,7 @@ pub const Object = struct {
26242630 null, // file
26252631 0, // line
26262632 field_size * 8, // size in bits
2627 field_align * 8, // align in bits
2633 field_align.toByteUnits(0) * 8, // align in bits
26282634 0, // offset in bits
26292635 0, // flags
26302636 field_di_ty,
......@@ -2644,7 +2650,7 @@ pub const Object = struct {
26442650 null, // file
26452651 0, // line
26462652 ty.abiSize(mod) * 8, // size in bits
2647 ty.abiAlignment(mod) * 8, // align in bits
2653 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
26482654 0, // flags
26492655 di_fields.items.ptr,
26502656 @intCast(di_fields.items.len),
......@@ -2661,12 +2667,12 @@ pub const Object = struct {
26612667
26622668 var tag_offset: u64 = undefined;
26632669 var payload_offset: u64 = undefined;
2664 if (layout.tag_align >= layout.payload_align) {
2670 if (layout.tag_align.compare(.gte, layout.payload_align)) {
26652671 tag_offset = 0;
2666 payload_offset = std.mem.alignForward(u64, layout.tag_size, layout.payload_align);
2672 payload_offset = layout.payload_align.forward(layout.tag_size);
26672673 } else {
26682674 payload_offset = 0;
2669 tag_offset = std.mem.alignForward(u64, layout.payload_size, layout.tag_align);
2675 tag_offset = layout.tag_align.forward(layout.payload_size);
26702676 }
26712677
26722678 const tag_di = dib.createMemberType(
......@@ -2675,7 +2681,7 @@ pub const Object = struct {
26752681 null, // file
26762682 0, // line
26772683 layout.tag_size * 8,
2678 layout.tag_align * 8, // align in bits
2684 layout.tag_align.toByteUnits(0) * 8,
26792685 tag_offset * 8, // offset in bits
26802686 0, // flags
26812687 try o.lowerDebugType(union_obj.enum_tag_ty.toType(), .full),
......@@ -2687,14 +2693,14 @@ pub const Object = struct {
26872693 null, // file
26882694 0, // line
26892695 layout.payload_size * 8, // size in bits
2690 layout.payload_align * 8, // align in bits
2696 layout.payload_align.toByteUnits(0) * 8,
26912697 payload_offset * 8, // offset in bits
26922698 0, // flags
26932699 union_di_ty,
26942700 );
26952701
26962702 const full_di_fields: [2]*llvm.DIType =
2697 if (layout.tag_align >= layout.payload_align)
2703 if (layout.tag_align.compare(.gte, layout.payload_align))
26982704 .{ tag_di, payload_di }
26992705 else
27002706 .{ payload_di, tag_di };
......@@ -2705,7 +2711,7 @@ pub const Object = struct {
27052711 null, // file
27062712 0, // line
27072713 ty.abiSize(mod) * 8, // size in bits
2708 ty.abiAlignment(mod) * 8, // align in bits
2714 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
27092715 0, // flags
27102716 null, // derived from
27112717 &full_di_fields,
......@@ -2925,8 +2931,8 @@ pub const Object = struct {
29252931 else => function_index.setCallConv(toLlvmCallConv(fn_info.cc, target), &o.builder),
29262932 }
29272933
2928 if (fn_info.alignment.toByteUnitsOptional()) |alignment|
2929 function_index.setAlignment(Builder.Alignment.fromByteUnits(alignment), &o.builder);
2934 if (fn_info.alignment != .none)
2935 function_index.setAlignment(fn_info.alignment.toLlvm(), &o.builder);
29302936
29312937 // Function attributes that are independent of analysis results of the function body.
29322938 try o.addCommonFnAttributes(&attributes);
......@@ -2949,9 +2955,8 @@ pub const Object = struct {
29492955 .byref => {
29502956 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1];
29512957 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);
2958 const alignment = param_ty.toType().abiAlignment(mod);
2959 try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment.toLlvm(), it.byval_attr, param_llvm_ty);
29552960 },
29562961 .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder),
29572962 // No attributes needed for these.
......@@ -3248,21 +3253,21 @@ pub const Object = struct {
32483253
32493254 var fields: [3]Builder.Type = undefined;
32503255 var fields_len: usize = 2;
3251 const padding_len = if (error_align > payload_align) pad: {
3256 const padding_len = if (error_align.compare(.gt, payload_align)) pad: {
32523257 fields[0] = error_type;
32533258 fields[1] = payload_type;
32543259 const payload_end =
3255 std.mem.alignForward(u64, error_size, payload_align) +
3260 payload_align.forward(error_size) +
32563261 payload_size;
3257 const abi_size = std.mem.alignForward(u64, payload_end, error_align);
3262 const abi_size = error_align.forward(payload_end);
32583263 break :pad abi_size - payload_end;
32593264 } else pad: {
32603265 fields[0] = payload_type;
32613266 fields[1] = error_type;
32623267 const error_end =
3263 std.mem.alignForward(u64, payload_size, error_align) +
3268 error_align.forward(payload_size) +
32643269 error_size;
3265 const abi_size = std.mem.alignForward(u64, error_end, payload_align);
3270 const abi_size = payload_align.forward(error_end);
32663271 break :pad abi_size - error_end;
32673272 };
32683273 if (padding_len > 0) {
......@@ -3276,60 +3281,74 @@ pub const Object = struct {
32763281 const gop = try o.type_map.getOrPut(o.gpa, t.toIntern());
32773282 if (gop.found_existing) return gop.value_ptr.*;
32783283
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);
3284 if (struct_type.layout == .Packed) {
3285 const int_ty = try o.lowerType(struct_type.backingIntType(ip).toType());
32833286 gop.value_ptr.* = int_ty;
32843287 return int_ty;
32853288 }
32863289
32873290 const name = try o.builder.string(ip.stringToSlice(
3288 try struct_obj.getFullyQualifiedName(mod),
3291 try mod.declPtr(struct_type.decl.unwrap().?).getFullyQualifiedName(mod),
32893292 ));
32903293 const ty = try o.builder.opaqueType(name);
32913294 gop.value_ptr.* = ty; // must be done before any recursive calls
32923295
3293 assert(struct_obj.haveFieldTypes());
3294
32953296 var llvm_field_types = std.ArrayListUnmanaged(Builder.Type){};
32963297 defer llvm_field_types.deinit(o.gpa);
32973298 // Although we can estimate how much capacity to add, these cannot be
32983299 // 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()));
3300 try llvm_field_types.ensureUnusedCapacity(o.gpa, struct_type.field_types.len);
3301 try o.struct_field_map.ensureUnusedCapacity(o.gpa, struct_type.field_types.len);
33013302
33023303 comptime assert(struct_layout_version == 2);
33033304 var offset: u64 = 0;
3304 var big_align: u32 = 1;
3305 var big_align: InternPool.Alignment = .@"1";
33053306 var struct_kind: Builder.Type.Structure.Kind = .normal;
3306
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);
3307 // When we encounter a zero-bit field, we place it here so we know to map it to the next non-zero-bit field (if any).
3308 var it = struct_type.iterateRuntimeOrder(ip);
3309 while (it.next()) |field_index| {
3310 const field_ty = struct_type.field_types.get(ip)[field_index].toType();
3311 const field_align = mod.structFieldAlignment(
3312 struct_type.fieldAlign(ip, field_index),
3313 field_ty,
3314 struct_type.layout,
3315 );
3316 const field_ty_align = field_ty.abiAlignment(mod);
3317 if (field_align.compare(.lt, field_ty_align)) struct_kind = .@"packed";
3318 big_align = big_align.max(field_align);
33143319 const prev_offset = offset;
3315 offset = std.mem.alignForward(u64, offset, field_align);
3320 offset = field_align.forward(offset);
33163321
33173322 const padding_len = offset - prev_offset;
33183323 if (padding_len > 0) try llvm_field_types.append(
33193324 o.gpa,
33203325 try o.builder.arrayType(padding_len, .i8),
33213326 );
3327
3328 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) {
3329 // This is a zero-bit field. If there are runtime bits after this field,
3330 // map to the next LLVM field (which we know exists): otherwise, don't
3331 // map the field, indicating it's at the end of the struct.
3332 if (offset != struct_type.size(ip).*) {
3333 try o.struct_field_map.put(o.gpa, .{
3334 .struct_ty = t.toIntern(),
3335 .field_index = field_index,
3336 }, @intCast(llvm_field_types.items.len));
3337 }
3338 continue;
3339 }
3340
33223341 try o.struct_field_map.put(o.gpa, .{
33233342 .struct_ty = t.toIntern(),
3324 .field_index = field_and_index.index,
3343 .field_index = field_index,
33253344 }, @intCast(llvm_field_types.items.len));
3326 try llvm_field_types.append(o.gpa, try o.lowerType(field.ty));
3345 try llvm_field_types.append(o.gpa, try o.lowerType(field_ty));
33273346
3328 offset += field.ty.abiSize(mod);
3347 offset += field_ty.abiSize(mod);
33293348 }
33303349 {
33313350 const prev_offset = offset;
3332 offset = std.mem.alignForward(u64, offset, big_align);
3351 offset = big_align.forward(offset);
33333352 const padding_len = offset - prev_offset;
33343353 if (padding_len > 0) try llvm_field_types.append(
33353354 o.gpa,
......@@ -3353,25 +3372,39 @@ pub const Object = struct {
33533372
33543373 comptime assert(struct_layout_version == 2);
33553374 var offset: u64 = 0;
3356 var big_align: u32 = 0;
3375 var big_align: InternPool.Alignment = .none;
3376
3377 const struct_size = t.abiSize(mod);
33573378
33583379 for (
33593380 anon_struct_type.types.get(ip),
33603381 anon_struct_type.values.get(ip),
33613382 0..,
33623383 ) |field_ty, field_val, field_index| {
3363 if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue;
3384 if (field_val != .none) continue;
33643385
33653386 const field_align = field_ty.toType().abiAlignment(mod);
3366 big_align = @max(big_align, field_align);
3387 big_align = big_align.max(field_align);
33673388 const prev_offset = offset;
3368 offset = std.mem.alignForward(u64, offset, field_align);
3389 offset = field_align.forward(offset);
33693390
33703391 const padding_len = offset - prev_offset;
33713392 if (padding_len > 0) try llvm_field_types.append(
33723393 o.gpa,
33733394 try o.builder.arrayType(padding_len, .i8),
33743395 );
3396 if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) {
3397 // This is a zero-bit field. If there are runtime bits after this field,
3398 // map to the next LLVM field (which we know exists): otherwise, don't
3399 // map the field, indicating it's at the end of the struct.
3400 if (offset != struct_size) {
3401 try o.struct_field_map.put(o.gpa, .{
3402 .struct_ty = t.toIntern(),
3403 .field_index = @intCast(field_index),
3404 }, @intCast(llvm_field_types.items.len));
3405 }
3406 continue;
3407 }
33753408 try o.struct_field_map.put(o.gpa, .{
33763409 .struct_ty = t.toIntern(),
33773410 .field_index = @intCast(field_index),
......@@ -3382,7 +3415,7 @@ pub const Object = struct {
33823415 }
33833416 {
33843417 const prev_offset = offset;
3385 offset = std.mem.alignForward(u64, offset, big_align);
3418 offset = big_align.forward(offset);
33863419 const padding_len = offset - prev_offset;
33873420 if (padding_len > 0) try llvm_field_types.append(
33883421 o.gpa,
......@@ -3447,7 +3480,7 @@ pub const Object = struct {
34473480 var llvm_fields: [3]Builder.Type = undefined;
34483481 var llvm_fields_len: usize = 2;
34493482
3450 if (layout.tag_align >= layout.payload_align) {
3483 if (layout.tag_align.compare(.gte, layout.payload_align)) {
34513484 llvm_fields = .{ enum_tag_ty, payload_ty, .none };
34523485 } else {
34533486 llvm_fields = .{ payload_ty, enum_tag_ty, .none };
......@@ -3687,7 +3720,7 @@ pub const Object = struct {
36873720
36883721 var fields: [3]Builder.Type = undefined;
36893722 var vals: [3]Builder.Constant = undefined;
3690 if (error_align > payload_align) {
3723 if (error_align.compare(.gt, payload_align)) {
36913724 vals[0] = llvm_error_value;
36923725 vals[1] = llvm_payload_value;
36933726 } else {
......@@ -3910,7 +3943,7 @@ pub const Object = struct {
39103943 comptime assert(struct_layout_version == 2);
39113944 var llvm_index: usize = 0;
39123945 var offset: u64 = 0;
3913 var big_align: u32 = 0;
3946 var big_align: InternPool.Alignment = .none;
39143947 var need_unnamed = false;
39153948 for (
39163949 tuple.types.get(ip),
......@@ -3921,9 +3954,9 @@ pub const Object = struct {
39213954 if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
39223955
39233956 const field_align = field_ty.toType().abiAlignment(mod);
3924 big_align = @max(big_align, field_align);
3957 big_align = big_align.max(field_align);
39253958 const prev_offset = offset;
3926 offset = std.mem.alignForward(u64, offset, field_align);
3959 offset = field_align.forward(offset);
39273960
39283961 const padding_len = offset - prev_offset;
39293962 if (padding_len > 0) {
......@@ -3946,7 +3979,7 @@ pub const Object = struct {
39463979 }
39473980 {
39483981 const prev_offset = offset;
3949 offset = std.mem.alignForward(u64, offset, big_align);
3982 offset = big_align.forward(offset);
39503983 const padding_len = offset - prev_offset;
39513984 if (padding_len > 0) {
39523985 fields[llvm_index] = try o.builder.arrayType(padding_len, .i8);
......@@ -3963,22 +3996,21 @@ pub const Object = struct {
39633996 struct_ty, vals);
39643997 },
39653998 .struct_type => |struct_type| {
3966 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
3967 assert(struct_obj.haveLayout());
3999 assert(struct_type.haveLayout(ip));
39684000 const struct_ty = try o.lowerType(ty);
3969 if (struct_obj.layout == .Packed) {
4001 if (struct_type.layout == .Packed) {
39704002 comptime assert(Type.packed_struct_layout_version == 2);
39714003 var running_int = try o.builder.intConst(struct_ty, 0);
39724004 var running_bits: u16 = 0;
3973 for (struct_obj.fields.values(), 0..) |field, field_index| {
3974 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
4005 for (struct_type.field_types.get(ip), 0..) |field_ty, field_index| {
4006 if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
39754007
39764008 const non_int_val =
39774009 try o.lowerValue((try val.fieldValue(mod, field_index)).toIntern());
3978 const ty_bit_size: u16 = @intCast(field.ty.bitSize(mod));
4010 const ty_bit_size: u16 = @intCast(field_ty.toType().bitSize(mod));
39794011 const small_int_ty = try o.builder.intType(ty_bit_size);
39804012 const small_int_val = try o.builder.castConst(
3981 if (field.ty.isPtrAtRuntime(mod)) .ptrtoint else .bitcast,
4013 if (field_ty.toType().isPtrAtRuntime(mod)) .ptrtoint else .bitcast,
39824014 non_int_val,
39834015 small_int_ty,
39844016 );
......@@ -4010,15 +4042,19 @@ pub const Object = struct {
40104042 comptime assert(struct_layout_version == 2);
40114043 var llvm_index: usize = 0;
40124044 var offset: u64 = 0;
4013 var big_align: u32 = 0;
4045 var big_align: InternPool.Alignment = .@"1";
40144046 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);
4047 var field_it = struct_type.iterateRuntimeOrder(ip);
4048 while (field_it.next()) |field_index| {
4049 const field_ty = struct_type.field_types.get(ip)[field_index].toType();
4050 const field_align = mod.structFieldAlignment(
4051 struct_type.fieldAlign(ip, field_index),
4052 field_ty,
4053 struct_type.layout,
4054 );
4055 big_align = big_align.max(field_align);
40204056 const prev_offset = offset;
4021 offset = std.mem.alignForward(u64, offset, field_align);
4057 offset = field_align.forward(offset);
40224058
40234059 const padding_len = offset - prev_offset;
40244060 if (padding_len > 0) {
......@@ -4031,19 +4067,24 @@ pub const Object = struct {
40314067 llvm_index += 1;
40324068 }
40334069
4070 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) {
4071 // This is a zero-bit field - we only needed it for the alignment.
4072 continue;
4073 }
4074
40344075 vals[llvm_index] = try o.lowerValue(
4035 (try val.fieldValue(mod, field_and_index.index)).toIntern(),
4076 (try val.fieldValue(mod, field_index)).toIntern(),
40364077 );
40374078 fields[llvm_index] = vals[llvm_index].typeOf(&o.builder);
40384079 if (fields[llvm_index] != struct_ty.structFields(&o.builder)[llvm_index])
40394080 need_unnamed = true;
40404081 llvm_index += 1;
40414082
4042 offset += field.ty.abiSize(mod);
4083 offset += field_ty.abiSize(mod);
40434084 }
40444085 {
40454086 const prev_offset = offset;
4046 offset = std.mem.alignForward(u64, offset, big_align);
4087 offset = big_align.forward(offset);
40474088 const padding_len = offset - prev_offset;
40484089 if (padding_len > 0) {
40494090 fields[llvm_index] = try o.builder.arrayType(padding_len, .i8);
......@@ -4093,7 +4134,7 @@ pub const Object = struct {
40934134 const payload = try o.lowerValue(un.val);
40944135 const payload_ty = payload.typeOf(&o.builder);
40954136 if (payload_ty != union_ty.structFields(&o.builder)[
4096 @intFromBool(layout.tag_align >= layout.payload_align)
4137 @intFromBool(layout.tag_align.compare(.gte, layout.payload_align))
40974138 ]) need_unnamed = true;
40984139 const field_size = field_ty.abiSize(mod);
40994140 if (field_size == layout.payload_size) break :p payload;
......@@ -4115,7 +4156,7 @@ pub const Object = struct {
41154156 var fields: [3]Builder.Type = undefined;
41164157 var vals: [3]Builder.Constant = undefined;
41174158 var len: usize = 2;
4118 if (layout.tag_align >= layout.payload_align) {
4159 if (layout.tag_align.compare(.gte, layout.payload_align)) {
41194160 fields = .{ tag_ty, payload_ty, undefined };
41204161 vals = .{ tag, payload, undefined };
41214162 } else {
......@@ -4174,14 +4215,15 @@ pub const Object = struct {
41744215
41754216 fn lowerParentPtr(o: *Object, ptr_val: Value, byte_aligned: bool) Allocator.Error!Builder.Constant {
41764217 const mod = o.module;
4177 return switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) {
4218 const ip = &mod.intern_pool;
4219 return switch (ip.indexToKey(ptr_val.toIntern()).ptr.addr) {
41784220 .decl => |decl| o.lowerParentPtrDecl(decl),
41794221 .mut_decl => |mut_decl| o.lowerParentPtrDecl(mut_decl.decl),
41804222 .int => |int| try o.lowerIntAsPtr(int),
41814223 .eu_payload => |eu_ptr| {
41824224 const parent_ptr = try o.lowerParentPtr(eu_ptr.toValue(), true);
41834225
4184 const eu_ty = mod.intern_pool.typeOf(eu_ptr).toType().childType(mod);
4226 const eu_ty = ip.typeOf(eu_ptr).toType().childType(mod);
41854227 const payload_ty = eu_ty.errorUnionPayload(mod);
41864228 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
41874229 // In this case, we represent pointer to error union the same as pointer
......@@ -4189,8 +4231,9 @@ pub const Object = struct {
41894231 return parent_ptr;
41904232 }
41914233
4192 const index: u32 =
4193 if (payload_ty.abiAlignment(mod) > Type.err_int.abiSize(mod)) 2 else 1;
4234 const payload_align = payload_ty.abiAlignment(mod);
4235 const err_align = Type.err_int.abiAlignment(mod);
4236 const index: u32 = if (payload_align.compare(.gt, err_align)) 2 else 1;
41944237 return o.builder.gepConst(.inbounds, try o.lowerType(eu_ty), parent_ptr, null, &.{
41954238 try o.builder.intConst(.i32, 0), try o.builder.intConst(.i32, index),
41964239 });
......@@ -4198,7 +4241,7 @@ pub const Object = struct {
41984241 .opt_payload => |opt_ptr| {
41994242 const parent_ptr = try o.lowerParentPtr(opt_ptr.toValue(), true);
42004243
4201 const opt_ty = mod.intern_pool.typeOf(opt_ptr).toType().childType(mod);
4244 const opt_ty = ip.typeOf(opt_ptr).toType().childType(mod);
42024245 const payload_ty = opt_ty.optionalChild(mod);
42034246 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod) or
42044247 payload_ty.optionalReprIsPayload(mod))
......@@ -4215,7 +4258,7 @@ pub const Object = struct {
42154258 .comptime_field => unreachable,
42164259 .elem => |elem_ptr| {
42174260 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);
4261 const elem_ty = ip.typeOf(elem_ptr.base).toType().elemType2(mod);
42194262
42204263 return o.builder.gepConst(.inbounds, try o.lowerType(elem_ty), parent_ptr, null, &.{
42214264 try o.builder.intConst(try o.lowerType(Type.usize), elem_ptr.index),
......@@ -4223,7 +4266,7 @@ pub const Object = struct {
42234266 },
42244267 .field => |field_ptr| {
42254268 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);
4269 const parent_ty = ip.typeOf(field_ptr.base).toType().childType(mod);
42274270
42284271 const field_index: u32 = @intCast(field_ptr.index);
42294272 switch (parent_ty.zigTypeTag(mod)) {
......@@ -4241,24 +4284,26 @@ pub const Object = struct {
42414284
42424285 const parent_llvm_ty = try o.lowerType(parent_ty);
42434286 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,
4287 try o.builder.intConst(.i32, 0),
4288 try o.builder.intConst(.i32, @intFromBool(
4289 layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align),
42464290 )),
42474291 });
42484292 },
42494293 .Struct => {
4250 if (parent_ty.containerLayout(mod) == .Packed) {
4294 if (mod.typeToPackedStruct(parent_ty)) |struct_type| {
42514295 if (!byte_aligned) return parent_ptr;
42524296 const llvm_usize = try o.lowerType(Type.usize);
42534297 const base_addr =
42544298 try o.builder.castConst(.ptrtoint, parent_ptr, llvm_usize);
42554299 // count bits of fields before this one
4300 // TODO https://github.com/ziglang/zig/issues/17178
42564301 const prev_bits = b: {
42574302 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));
4303 for (0..field_index) |i| {
4304 const field_ty = struct_type.field_types.get(ip)[i].toType();
4305 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
4306 b += @intCast(field_ty.bitSize(mod));
42624307 }
42634308 break :b b;
42644309 };
......@@ -4407,11 +4452,11 @@ pub const Object = struct {
44074452 if (ptr_info.flags.is_const) {
44084453 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
44094454 }
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);
4455 const elem_align = if (ptr_info.flags.alignment != .none)
4456 ptr_info.flags.alignment
4457 else
4458 ptr_info.child.toType().abiAlignment(mod).max(.@"1");
4459 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align.toLlvm() }, &o.builder);
44154460 } else if (ccAbiPromoteInt(fn_info.cc, mod, param_ty)) |s| switch (s) {
44164461 .signed => try attributes.addParamAttr(llvm_arg_i, .signext, &o.builder),
44174462 .unsigned => try attributes.addParamAttr(llvm_arg_i, .zeroext, &o.builder),
......@@ -4469,7 +4514,7 @@ pub const DeclGen = struct {
44694514 } else {
44704515 const variable_index = try o.resolveGlobalDecl(decl_index);
44714516 variable_index.setAlignment(
4472 Builder.Alignment.fromByteUnits(decl.getAlignment(mod)),
4517 decl.getAlignment(mod).toLlvm(),
44734518 &o.builder,
44744519 );
44754520 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |section|
......@@ -4611,9 +4656,7 @@ pub const FuncGen = struct {
46114656 variable_index.setLinkage(.private, &o.builder);
46124657 variable_index.setMutability(.constant, &o.builder);
46134658 variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
4614 variable_index.setAlignment(Builder.Alignment.fromByteUnits(
4615 tv.ty.abiAlignment(mod),
4616 ), &o.builder);
4659 variable_index.setAlignment(tv.ty.abiAlignment(mod).toLlvm(), &o.builder);
46174660 return o.builder.convConst(
46184661 .unneeded,
46194662 variable_index.toConst(&o.builder),
......@@ -4929,7 +4972,7 @@ pub const FuncGen = struct {
49294972 const llvm_ret_ty = try o.lowerType(return_type);
49304973 try attributes.addParamAttr(0, .{ .sret = llvm_ret_ty }, &o.builder);
49314974
4932 const alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod));
4975 const alignment = return_type.abiAlignment(mod).toLlvm();
49334976 const ret_ptr = try self.buildAlloca(llvm_ret_ty, alignment);
49344977 try llvm_args.append(ret_ptr);
49354978 break :blk ret_ptr;
......@@ -4951,7 +4994,7 @@ pub const FuncGen = struct {
49514994 const llvm_arg = try self.resolveInst(arg);
49524995 const llvm_param_ty = try o.lowerType(param_ty);
49534996 if (isByRef(param_ty, mod)) {
4954 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
4997 const alignment = param_ty.abiAlignment(mod).toLlvm();
49554998 const loaded = try self.wip.load(.normal, llvm_param_ty, llvm_arg, alignment, "");
49564999 try llvm_args.append(loaded);
49575000 } else {
......@@ -4965,7 +5008,7 @@ pub const FuncGen = struct {
49655008 if (isByRef(param_ty, mod)) {
49665009 try llvm_args.append(llvm_arg);
49675010 } else {
4968 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
5011 const alignment = param_ty.abiAlignment(mod).toLlvm();
49695012 const param_llvm_ty = llvm_arg.typeOfWip(&self.wip);
49705013 const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment);
49715014 _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment);
......@@ -4977,7 +5020,7 @@ pub const FuncGen = struct {
49775020 const param_ty = self.typeOf(arg);
49785021 const llvm_arg = try self.resolveInst(arg);
49795022
4980 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
5023 const alignment = param_ty.abiAlignment(mod).toLlvm();
49815024 const param_llvm_ty = try o.lowerType(param_ty);
49825025 const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment);
49835026 if (isByRef(param_ty, mod)) {
......@@ -4995,13 +5038,13 @@ pub const FuncGen = struct {
49955038 const int_llvm_ty = try o.builder.intType(@intCast(param_ty.abiSize(mod) * 8));
49965039
49975040 if (isByRef(param_ty, mod)) {
4998 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
5041 const alignment = param_ty.abiAlignment(mod).toLlvm();
49995042 const loaded = try self.wip.load(.normal, int_llvm_ty, llvm_arg, alignment, "");
50005043 try llvm_args.append(loaded);
50015044 } else {
50025045 // LLVM does not allow bitcasting structs so we must allocate
50035046 // a local, store as one type, and then load as another type.
5004 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
5047 const alignment = param_ty.abiAlignment(mod).toLlvm();
50055048 const int_ptr = try self.buildAlloca(int_llvm_ty, alignment);
50065049 _ = try self.wip.store(.normal, llvm_arg, int_ptr, alignment);
50075050 const loaded = try self.wip.load(.normal, int_llvm_ty, int_ptr, alignment, "");
......@@ -5022,7 +5065,7 @@ pub const FuncGen = struct {
50225065 const llvm_arg = try self.resolveInst(arg);
50235066 const is_by_ref = isByRef(param_ty, mod);
50245067 const arg_ptr = if (is_by_ref) llvm_arg else ptr: {
5025 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
5068 const alignment = param_ty.abiAlignment(mod).toLlvm();
50265069 const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment);
50275070 _ = try self.wip.store(.normal, llvm_arg, ptr, alignment);
50285071 break :ptr ptr;
......@@ -5048,7 +5091,7 @@ pub const FuncGen = struct {
50485091 const arg = args[it.zig_index - 1];
50495092 const arg_ty = self.typeOf(arg);
50505093 var llvm_arg = try self.resolveInst(arg);
5051 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
5094 const alignment = arg_ty.abiAlignment(mod).toLlvm();
50525095 if (!isByRef(arg_ty, mod)) {
50535096 const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment);
50545097 _ = try self.wip.store(.normal, llvm_arg, ptr, alignment);
......@@ -5066,7 +5109,7 @@ pub const FuncGen = struct {
50665109 const arg = args[it.zig_index - 1];
50675110 const arg_ty = self.typeOf(arg);
50685111 var llvm_arg = try self.resolveInst(arg);
5069 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
5112 const alignment = arg_ty.abiAlignment(mod).toLlvm();
50705113 if (!isByRef(arg_ty, mod)) {
50715114 const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment);
50725115 _ = try self.wip.store(.normal, llvm_arg, ptr, alignment);
......@@ -5097,7 +5140,7 @@ pub const FuncGen = struct {
50975140 const param_index = it.zig_index - 1;
50985141 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
50995142 const param_llvm_ty = try o.lowerType(param_ty);
5100 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));
5143 const alignment = param_ty.abiAlignment(mod).toLlvm();
51015144 try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
51025145 },
51035146 .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder),
......@@ -5128,10 +5171,10 @@ pub const FuncGen = struct {
51285171 if (ptr_info.flags.is_const) {
51295172 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
51305173 }
5131 const elem_align = Builder.Alignment.fromByteUnits(
5132 ptr_info.flags.alignment.toByteUnitsOptional() orelse
5133 @max(ptr_info.child.toType().abiAlignment(mod), 1),
5134 );
5174 const elem_align = (if (ptr_info.flags.alignment != .none)
5175 @as(InternPool.Alignment, ptr_info.flags.alignment)
5176 else
5177 ptr_info.child.toType().abiAlignment(mod).max(.@"1")).toLlvm();
51355178 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
51365179 },
51375180 };
......@@ -5166,7 +5209,7 @@ pub const FuncGen = struct {
51665209 return rp;
51675210 } else {
51685211 // our by-ref status disagrees with sret so we must load.
5169 const return_alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod));
5212 const return_alignment = return_type.abiAlignment(mod).toLlvm();
51705213 return self.wip.load(.normal, llvm_ret_ty, rp, return_alignment, "");
51715214 }
51725215 }
......@@ -5177,7 +5220,7 @@ pub const FuncGen = struct {
51775220 // In this case the function return type is honoring the calling convention by having
51785221 // a different LLVM type than the usual one. We solve this here at the callsite
51795222 // by using our canonical type, then loading it if necessary.
5180 const alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod));
5223 const alignment = return_type.abiAlignment(mod).toLlvm();
51815224 if (o.builder.useLibLlvm())
51825225 assert(o.target_data.abiSizeOfType(abi_ret_ty.toLlvm(&o.builder)) >=
51835226 o.target_data.abiSizeOfType(llvm_ret_ty.toLlvm(&o.builder)));
......@@ -5192,7 +5235,7 @@ pub const FuncGen = struct {
51925235 if (isByRef(return_type, mod)) {
51935236 // our by-ref status disagrees with sret so we must allocate, store,
51945237 // and return the allocation pointer.
5195 const alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod));
5238 const alignment = return_type.abiAlignment(mod).toLlvm();
51965239 const rp = try self.buildAlloca(llvm_ret_ty, alignment);
51975240 _ = try self.wip.store(.normal, call, rp, alignment);
51985241 return rp;
......@@ -5266,7 +5309,7 @@ pub const FuncGen = struct {
52665309
52675310 const abi_ret_ty = try lowerFnRetTy(o, fn_info);
52685311 const operand = try self.resolveInst(un_op);
5269 const alignment = Builder.Alignment.fromByteUnits(ret_ty.abiAlignment(mod));
5312 const alignment = ret_ty.abiAlignment(mod).toLlvm();
52705313
52715314 if (isByRef(ret_ty, mod)) {
52725315 // operand is a pointer however self.ret_ptr is null so that means
......@@ -5311,7 +5354,7 @@ pub const FuncGen = struct {
53115354 }
53125355 const ptr = try self.resolveInst(un_op);
53135356 const abi_ret_ty = try lowerFnRetTy(o, fn_info);
5314 const alignment = Builder.Alignment.fromByteUnits(ret_ty.abiAlignment(mod));
5357 const alignment = ret_ty.abiAlignment(mod).toLlvm();
53155358 _ = try self.wip.ret(try self.wip.load(.normal, abi_ret_ty, ptr, alignment, ""));
53165359 return .none;
53175360 }
......@@ -5334,7 +5377,7 @@ pub const FuncGen = struct {
53345377 const llvm_va_list_ty = try o.lowerType(va_list_ty);
53355378 const mod = o.module;
53365379
5337 const result_alignment = Builder.Alignment.fromByteUnits(va_list_ty.abiAlignment(mod));
5380 const result_alignment = va_list_ty.abiAlignment(mod).toLlvm();
53385381 const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment);
53395382
53405383 _ = try self.wip.callIntrinsic(.normal, .none, .va_copy, &.{}, &.{ dest_list, src_list }, "");
......@@ -5358,7 +5401,7 @@ pub const FuncGen = struct {
53585401 const va_list_ty = self.typeOfIndex(inst);
53595402 const llvm_va_list_ty = try o.lowerType(va_list_ty);
53605403
5361 const result_alignment = Builder.Alignment.fromByteUnits(va_list_ty.abiAlignment(mod));
5404 const result_alignment = va_list_ty.abiAlignment(mod).toLlvm();
53625405 const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment);
53635406
53645407 _ = try self.wip.callIntrinsic(.normal, .none, .va_start, &.{}, &.{dest_list}, "");
......@@ -5690,7 +5733,7 @@ pub const FuncGen = struct {
56905733 return fg.wip.gepStruct(err_union_llvm_ty, err_union, offset, "");
56915734 } else if (isByRef(err_union_ty, mod)) {
56925735 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));
5736 const payload_alignment = payload_ty.abiAlignment(mod).toLlvm();
56945737 if (isByRef(payload_ty, mod)) {
56955738 if (can_elide_load)
56965739 return payload_ptr;
......@@ -5997,7 +6040,7 @@ pub const FuncGen = struct {
59976040 if (self.canElideLoad(body_tail))
59986041 return ptr;
59996042
6000 const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
6043 const elem_alignment = elem_ty.abiAlignment(mod).toLlvm();
60016044 return self.loadByRef(ptr, elem_ty, elem_alignment, .normal);
60026045 }
60036046
......@@ -6037,7 +6080,7 @@ pub const FuncGen = struct {
60376080 const elem_ptr =
60386081 try self.wip.gep(.inbounds, array_llvm_ty, array_llvm_val, &indices, "");
60396082 if (canElideLoad(self, body_tail)) return elem_ptr;
6040 const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
6083 const elem_alignment = elem_ty.abiAlignment(mod).toLlvm();
60416084 return self.loadByRef(elem_ptr, elem_ty, elem_alignment, .normal);
60426085 } else {
60436086 const elem_llvm_ty = try o.lowerType(elem_ty);
......@@ -6097,7 +6140,7 @@ pub const FuncGen = struct {
60976140 &.{rhs}, "");
60986141 if (isByRef(elem_ty, mod)) {
60996142 if (self.canElideLoad(body_tail)) return ptr;
6100 const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
6143 const elem_alignment = elem_ty.abiAlignment(mod).toLlvm();
61016144 return self.loadByRef(ptr, elem_ty, elem_alignment, .normal);
61026145 }
61036146
......@@ -6111,7 +6154,7 @@ pub const FuncGen = struct {
61116154 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
61126155 const ptr_ty = self.typeOf(bin_op.lhs);
61136156 const elem_ty = ptr_ty.childType(mod);
6114 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return (try o.lowerPtrToVoid(ptr_ty)).toValue();
6157 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return self.resolveInst(bin_op.lhs);
61156158
61166159 const base_ptr = try self.resolveInst(bin_op.lhs);
61176160 const rhs = try self.resolveInst(bin_op.rhs);
......@@ -6163,8 +6206,8 @@ pub const FuncGen = struct {
61636206 switch (struct_ty.zigTypeTag(mod)) {
61646207 .Struct => switch (struct_ty.containerLayout(mod)) {
61656208 .Packed => {
6166 const struct_obj = mod.typeToStruct(struct_ty).?;
6167 const bit_offset = struct_obj.packedFieldBitOffset(mod, field_index);
6209 const struct_type = mod.typeToStruct(struct_ty).?;
6210 const bit_offset = mod.structPackedFieldBitOffset(struct_type, field_index);
61686211 const containing_int = struct_llvm_val;
61696212 const shift_amt =
61706213 try o.builder.intValue(containing_int.typeOfWip(&self.wip), bit_offset);
......@@ -6220,16 +6263,14 @@ pub const FuncGen = struct {
62206263 const alignment = struct_ty.structFieldAlign(field_index, mod);
62216264 const field_ptr_ty = try mod.ptrType(.{
62226265 .child = field_ty.toIntern(),
6223 .flags = .{
6224 .alignment = InternPool.Alignment.fromNonzeroByteUnits(alignment),
6225 },
6266 .flags = .{ .alignment = alignment },
62266267 });
62276268 if (isByRef(field_ty, mod)) {
62286269 if (canElideLoad(self, body_tail))
62296270 return field_ptr;
62306271
6231 assert(alignment != 0);
6232 const field_alignment = Builder.Alignment.fromByteUnits(alignment);
6272 assert(alignment != .none);
6273 const field_alignment = alignment.toLlvm();
62336274 return self.loadByRef(field_ptr, field_ty, field_alignment, .normal);
62346275 } else {
62356276 return self.load(field_ptr, field_ptr_ty);
......@@ -6238,11 +6279,11 @@ pub const FuncGen = struct {
62386279 .Union => {
62396280 const union_llvm_ty = try o.lowerType(struct_ty);
62406281 const layout = struct_ty.unionGetLayout(mod);
6241 const payload_index = @intFromBool(layout.tag_align >= layout.payload_align);
6282 const payload_index = @intFromBool(layout.tag_align.compare(.gte, layout.payload_align));
62426283 const field_ptr =
62436284 try self.wip.gepStruct(union_llvm_ty, struct_llvm_val, payload_index, "");
62446285 const llvm_field_ty = try o.lowerType(field_ty);
6245 const payload_alignment = Builder.Alignment.fromByteUnits(layout.payload_align);
6286 const payload_alignment = layout.payload_align.toLlvm();
62466287 if (isByRef(field_ty, mod)) {
62476288 if (canElideLoad(self, body_tail)) return field_ptr;
62486289 return self.loadByRef(field_ptr, field_ty, payload_alignment, .normal);
......@@ -6457,7 +6498,7 @@ pub const FuncGen = struct {
64576498 if (isByRef(operand_ty, mod)) {
64586499 _ = dib.insertDeclareAtEnd(operand.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
64596500 } else if (o.module.comp.bin_file.options.optimize_mode == .Debug) {
6460 const alignment = Builder.Alignment.fromByteUnits(operand_ty.abiAlignment(mod));
6501 const alignment = operand_ty.abiAlignment(mod).toLlvm();
64616502 const alloca = try self.buildAlloca(operand.typeOfWip(&self.wip), alignment);
64626503 _ = try self.wip.store(.normal, operand, alloca, alignment);
64636504 _ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
......@@ -6612,7 +6653,7 @@ pub const FuncGen = struct {
66126653 llvm_param_values[llvm_param_i] = arg_llvm_value;
66136654 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
66146655 } else {
6615 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
6656 const alignment = arg_ty.abiAlignment(mod).toLlvm();
66166657 const arg_llvm_ty = try o.lowerType(arg_ty);
66176658 const load_inst =
66186659 try self.wip.load(.normal, arg_llvm_ty, arg_llvm_value, alignment, "");
......@@ -6624,7 +6665,7 @@ pub const FuncGen = struct {
66246665 llvm_param_values[llvm_param_i] = arg_llvm_value;
66256666 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
66266667 } else {
6627 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));
6668 const alignment = arg_ty.abiAlignment(mod).toLlvm();
66286669 const arg_ptr = try self.buildAlloca(arg_llvm_value.typeOfWip(&self.wip), alignment);
66296670 _ = try self.wip.store(.normal, arg_llvm_value, arg_ptr, alignment);
66306671 llvm_param_values[llvm_param_i] = arg_ptr;
......@@ -6676,7 +6717,7 @@ pub const FuncGen = struct {
66766717 llvm_param_values[llvm_param_i] = llvm_rw_val;
66776718 llvm_param_types[llvm_param_i] = llvm_rw_val.typeOfWip(&self.wip);
66786719 } else {
6679 const alignment = Builder.Alignment.fromByteUnits(rw_ty.abiAlignment(mod));
6720 const alignment = rw_ty.abiAlignment(mod).toLlvm();
66806721 const loaded = try self.wip.load(.normal, llvm_elem_ty, llvm_rw_val, alignment, "");
66816722 llvm_param_values[llvm_param_i] = loaded;
66826723 llvm_param_types[llvm_param_i] = llvm_elem_ty;
......@@ -6837,7 +6878,7 @@ pub const FuncGen = struct {
68376878 const output_ptr = try self.resolveInst(output);
68386879 const output_ptr_ty = self.typeOf(output);
68396880
6840 const alignment = Builder.Alignment.fromByteUnits(output_ptr_ty.ptrAlignment(mod));
6881 const alignment = output_ptr_ty.ptrAlignment(mod).toLlvm();
68416882 _ = try self.wip.store(.normal, output_value, output_ptr, alignment);
68426883 } else {
68436884 ret_val = output_value;
......@@ -7030,7 +7071,7 @@ pub const FuncGen = struct {
70307071 if (operand_is_ptr) {
70317072 return self.wip.gepStruct(err_union_llvm_ty, operand, offset, "");
70327073 } else if (isByRef(err_union_ty, mod)) {
7033 const payload_alignment = Builder.Alignment.fromByteUnits(payload_ty.abiAlignment(mod));
7074 const payload_alignment = payload_ty.abiAlignment(mod).toLlvm();
70347075 const payload_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, offset, "");
70357076 if (isByRef(payload_ty, mod)) {
70367077 if (self.canElideLoad(body_tail)) return payload_ptr;
......@@ -7093,7 +7134,7 @@ pub const FuncGen = struct {
70937134 }
70947135 const err_union_llvm_ty = try o.lowerType(err_union_ty);
70957136 {
7096 const error_alignment = Builder.Alignment.fromByteUnits(Type.err_int.abiAlignment(mod));
7137 const error_alignment = Type.err_int.abiAlignment(mod).toLlvm();
70977138 const error_offset = errUnionErrorOffset(payload_ty, mod);
70987139 // First set the non-error value.
70997140 const non_null_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, error_offset, "");
......@@ -7133,9 +7174,7 @@ pub const FuncGen = struct {
71337174 const field_ty = struct_ty.structFieldType(field_index, mod);
71347175 const field_ptr_ty = try mod.ptrType(.{
71357176 .child = field_ty.toIntern(),
7136 .flags = .{
7137 .alignment = InternPool.Alignment.fromNonzeroByteUnits(field_alignment),
7138 },
7177 .flags = .{ .alignment = field_alignment },
71397178 });
71407179 return self.load(field_ptr, field_ptr_ty);
71417180 }
......@@ -7153,7 +7192,7 @@ pub const FuncGen = struct {
71537192 if (optional_ty.optionalReprIsPayload(mod)) return operand;
71547193 const llvm_optional_ty = try o.lowerType(optional_ty);
71557194 if (isByRef(optional_ty, mod)) {
7156 const alignment = Builder.Alignment.fromByteUnits(optional_ty.abiAlignment(mod));
7195 const alignment = optional_ty.abiAlignment(mod).toLlvm();
71577196 const optional_ptr = try self.buildAlloca(llvm_optional_ty, alignment);
71587197 const payload_ptr = try self.wip.gepStruct(llvm_optional_ty, optional_ptr, 0, "");
71597198 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);
......@@ -7181,10 +7220,10 @@ pub const FuncGen = struct {
71817220 const payload_offset = errUnionPayloadOffset(payload_ty, mod);
71827221 const error_offset = errUnionErrorOffset(payload_ty, mod);
71837222 if (isByRef(err_un_ty, mod)) {
7184 const alignment = Builder.Alignment.fromByteUnits(err_un_ty.abiAlignment(mod));
7223 const alignment = err_un_ty.abiAlignment(mod).toLlvm();
71857224 const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment);
71867225 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));
7226 const error_alignment = Type.err_int.abiAlignment(mod).toLlvm();
71887227 _ = try self.wip.store(.normal, ok_err_code, err_ptr, error_alignment);
71897228 const payload_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, payload_offset, "");
71907229 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);
......@@ -7210,10 +7249,10 @@ pub const FuncGen = struct {
72107249 const payload_offset = errUnionPayloadOffset(payload_ty, mod);
72117250 const error_offset = errUnionErrorOffset(payload_ty, mod);
72127251 if (isByRef(err_un_ty, mod)) {
7213 const alignment = Builder.Alignment.fromByteUnits(err_un_ty.abiAlignment(mod));
7252 const alignment = err_un_ty.abiAlignment(mod).toLlvm();
72147253 const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment);
72157254 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));
7255 const error_alignment = Type.err_int.abiAlignment(mod).toLlvm();
72177256 _ = try self.wip.store(.normal, operand, err_ptr, error_alignment);
72187257 const payload_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, payload_offset, "");
72197258 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);
......@@ -7260,7 +7299,7 @@ pub const FuncGen = struct {
72607299 const access_kind: Builder.MemoryAccessKind =
72617300 if (vector_ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal;
72627301 const elem_llvm_ty = try o.lowerType(vector_ptr_ty.childType(mod));
7263 const alignment = Builder.Alignment.fromByteUnits(vector_ptr_ty.ptrAlignment(mod));
7302 const alignment = vector_ptr_ty.ptrAlignment(mod).toLlvm();
72647303 const loaded = try self.wip.load(access_kind, elem_llvm_ty, vector_ptr, alignment, "");
72657304
72667305 const new_vector = try self.wip.insertElement(loaded, operand, index, "");
......@@ -7690,7 +7729,7 @@ pub const FuncGen = struct {
76907729 const overflow_index = o.llvmFieldIndex(inst_ty, 1).?;
76917730
76927731 if (isByRef(inst_ty, mod)) {
7693 const result_alignment = Builder.Alignment.fromByteUnits(inst_ty.abiAlignment(mod));
7732 const result_alignment = inst_ty.abiAlignment(mod).toLlvm();
76947733 const alloca_inst = try self.buildAlloca(llvm_inst_ty, result_alignment);
76957734 {
76967735 const field_ptr = try self.wip.gepStruct(llvm_inst_ty, alloca_inst, result_index, "");
......@@ -8048,7 +8087,7 @@ pub const FuncGen = struct {
80488087 const overflow_index = o.llvmFieldIndex(dest_ty, 1).?;
80498088
80508089 if (isByRef(dest_ty, mod)) {
8051 const result_alignment = Builder.Alignment.fromByteUnits(dest_ty.abiAlignment(mod));
8090 const result_alignment = dest_ty.abiAlignment(mod).toLlvm();
80528091 const alloca_inst = try self.buildAlloca(llvm_dest_ty, result_alignment);
80538092 {
80548093 const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, result_index, "");
......@@ -8321,7 +8360,7 @@ pub const FuncGen = struct {
83218360 const array_ptr = try self.buildAlloca(llvm_dest_ty, .default);
83228361 const bitcast_ok = elem_ty.bitSize(mod) == elem_ty.abiSize(mod) * 8;
83238362 if (bitcast_ok) {
8324 const alignment = Builder.Alignment.fromByteUnits(inst_ty.abiAlignment(mod));
8363 const alignment = inst_ty.abiAlignment(mod).toLlvm();
83258364 _ = try self.wip.store(.normal, operand, array_ptr, alignment);
83268365 } else {
83278366 // If the ABI size of the element type is not evenly divisible by size in bits;
......@@ -8349,7 +8388,7 @@ pub const FuncGen = struct {
83498388 if (bitcast_ok) {
83508389 // The array is aligned to the element's alignment, while the vector might have a completely
83518390 // different alignment. This means we need to enforce the alignment of this load.
8352 const alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
8391 const alignment = elem_ty.abiAlignment(mod).toLlvm();
83538392 return self.wip.load(.normal, llvm_vector_ty, operand, alignment, "");
83548393 } else {
83558394 // If the ABI size of the element type is not evenly divisible by size in bits;
......@@ -8374,14 +8413,12 @@ pub const FuncGen = struct {
83748413 }
83758414
83768415 if (operand_is_ref) {
8377 const alignment = Builder.Alignment.fromByteUnits(operand_ty.abiAlignment(mod));
8416 const alignment = operand_ty.abiAlignment(mod).toLlvm();
83788417 return self.wip.load(.normal, llvm_dest_ty, operand, alignment, "");
83798418 }
83808419
83818420 if (result_is_ref) {
8382 const alignment = Builder.Alignment.fromByteUnits(
8383 @max(operand_ty.abiAlignment(mod), inst_ty.abiAlignment(mod)),
8384 );
8421 const alignment = operand_ty.abiAlignment(mod).max(inst_ty.abiAlignment(mod)).toLlvm();
83858422 const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment);
83868423 _ = try self.wip.store(.normal, operand, result_ptr, alignment);
83878424 return result_ptr;
......@@ -8393,9 +8430,7 @@ pub const FuncGen = struct {
83938430 // Both our operand and our result are values, not pointers,
83948431 // but LLVM won't let us bitcast struct values or vectors with padding bits.
83958432 // 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 );
8433 const alignment = operand_ty.abiAlignment(mod).max(inst_ty.abiAlignment(mod)).toLlvm();
83998434 const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment);
84008435 _ = try self.wip.store(.normal, operand, result_ptr, alignment);
84018436 return self.wip.load(.normal, llvm_dest_ty, result_ptr, alignment, "");
......@@ -8441,7 +8476,7 @@ pub const FuncGen = struct {
84418476 if (isByRef(inst_ty, mod)) {
84428477 _ = dib.insertDeclareAtEnd(arg_val.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
84438478 } else if (o.module.comp.bin_file.options.optimize_mode == .Debug) {
8444 const alignment = Builder.Alignment.fromByteUnits(inst_ty.abiAlignment(mod));
8479 const alignment = inst_ty.abiAlignment(mod).toLlvm();
84458480 const alloca = try self.buildAlloca(arg_val.typeOfWip(&self.wip), alignment);
84468481 _ = try self.wip.store(.normal, arg_val, alloca, alignment);
84478482 _ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
......@@ -8462,7 +8497,7 @@ pub const FuncGen = struct {
84628497 return (try o.lowerPtrToVoid(ptr_ty)).toValue();
84638498
84648499 const pointee_llvm_ty = try o.lowerType(pointee_type);
8465 const alignment = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
8500 const alignment = ptr_ty.ptrAlignment(mod).toLlvm();
84668501 return self.buildAlloca(pointee_llvm_ty, alignment);
84678502 }
84688503
......@@ -8475,7 +8510,7 @@ pub const FuncGen = struct {
84758510 return (try o.lowerPtrToVoid(ptr_ty)).toValue();
84768511 if (self.ret_ptr != .none) return self.ret_ptr;
84778512 const ret_llvm_ty = try o.lowerType(ret_ty);
8478 const alignment = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
8513 const alignment = ptr_ty.ptrAlignment(mod).toLlvm();
84798514 return self.buildAlloca(ret_llvm_ty, alignment);
84808515 }
84818516
......@@ -8515,7 +8550,7 @@ pub const FuncGen = struct {
85158550 const len = try o.builder.intValue(try o.lowerType(Type.usize), operand_ty.abiSize(mod));
85168551 _ = try self.wip.callMemSet(
85178552 dest_ptr,
8518 Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod)),
8553 ptr_ty.ptrAlignment(mod).toLlvm(),
85198554 if (safety) try o.builder.intValue(.i8, 0xaa) else try o.builder.undefValue(.i8),
85208555 len,
85218556 if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal,
......@@ -8646,7 +8681,7 @@ pub const FuncGen = struct {
86468681 self.sync_scope,
86478682 toLlvmAtomicOrdering(extra.successOrder()),
86488683 toLlvmAtomicOrdering(extra.failureOrder()),
8649 Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod)),
8684 ptr_ty.ptrAlignment(mod).toLlvm(),
86508685 "",
86518686 );
86528687
......@@ -8685,7 +8720,7 @@ pub const FuncGen = struct {
86858720
86868721 const access_kind: Builder.MemoryAccessKind =
86878722 if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal;
8688 const ptr_alignment = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
8723 const ptr_alignment = ptr_ty.ptrAlignment(mod).toLlvm();
86898724
86908725 if (llvm_abi_ty != .none) {
86918726 // operand needs widening and truncating or bitcasting.
......@@ -8741,9 +8776,10 @@ pub const FuncGen = struct {
87418776 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none;
87428777 const ordering = toLlvmAtomicOrdering(atomic_load.order);
87438778 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 );
8779 const ptr_alignment = (if (info.flags.alignment != .none)
8780 @as(InternPool.Alignment, info.flags.alignment)
8781 else
8782 info.child.toType().abiAlignment(mod)).toLlvm();
87478783 const access_kind: Builder.MemoryAccessKind =
87488784 if (info.flags.is_volatile) .@"volatile" else .normal;
87498785 const elem_llvm_ty = try o.lowerType(elem_ty);
......@@ -8807,7 +8843,7 @@ pub const FuncGen = struct {
88078843 const dest_slice = try self.resolveInst(bin_op.lhs);
88088844 const ptr_ty = self.typeOf(bin_op.lhs);
88098845 const elem_ty = self.typeOf(bin_op.rhs);
8810 const dest_ptr_align = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
8846 const dest_ptr_align = ptr_ty.ptrAlignment(mod).toLlvm();
88118847 const dest_ptr = try self.sliceOrArrayPtr(dest_slice, ptr_ty);
88128848 const access_kind: Builder.MemoryAccessKind =
88138849 if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal;
......@@ -8911,15 +8947,13 @@ pub const FuncGen = struct {
89118947
89128948 self.wip.cursor = .{ .block = body_block };
89138949 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 );
8950 const it_ptr_align = InternPool.Alignment.fromLlvm(dest_ptr_align).min(elem_abi_align).toLlvm();
89178951 if (isByRef(elem_ty, mod)) {
89188952 _ = try self.wip.callMemCpy(
89198953 it_ptr.toValue(),
89208954 it_ptr_align,
89218955 value,
8922 Builder.Alignment.fromByteUnits(elem_abi_align),
8956 elem_abi_align.toLlvm(),
89238957 try o.builder.intValue(llvm_usize_ty, elem_abi_size),
89248958 access_kind,
89258959 );
......@@ -8985,9 +9019,9 @@ pub const FuncGen = struct {
89859019 self.wip.cursor = .{ .block = memcpy_block };
89869020 _ = try self.wip.callMemCpy(
89879021 dest_ptr,
8988 Builder.Alignment.fromByteUnits(dest_ptr_ty.ptrAlignment(mod)),
9022 dest_ptr_ty.ptrAlignment(mod).toLlvm(),
89899023 src_ptr,
8990 Builder.Alignment.fromByteUnits(src_ptr_ty.ptrAlignment(mod)),
9024 src_ptr_ty.ptrAlignment(mod).toLlvm(),
89919025 len,
89929026 access_kind,
89939027 );
......@@ -8998,9 +9032,9 @@ pub const FuncGen = struct {
89989032
89999033 _ = try self.wip.callMemCpy(
90009034 dest_ptr,
9001 Builder.Alignment.fromByteUnits(dest_ptr_ty.ptrAlignment(mod)),
9035 dest_ptr_ty.ptrAlignment(mod).toLlvm(),
90029036 src_ptr,
9003 Builder.Alignment.fromByteUnits(src_ptr_ty.ptrAlignment(mod)),
9037 src_ptr_ty.ptrAlignment(mod).toLlvm(),
90049038 len,
90059039 access_kind,
90069040 );
......@@ -9021,7 +9055,7 @@ pub const FuncGen = struct {
90219055 _ = try self.wip.store(.normal, new_tag, union_ptr, .default);
90229056 return .none;
90239057 }
9024 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);
9058 const tag_index = @intFromBool(layout.tag_align.compare(.lt, layout.payload_align));
90259059 const tag_field_ptr = try self.wip.gepStruct(try o.lowerType(un_ty), union_ptr, tag_index, "");
90269060 // TODO alignment on this store
90279061 _ = try self.wip.store(.normal, new_tag, tag_field_ptr, .default);
......@@ -9040,13 +9074,13 @@ pub const FuncGen = struct {
90409074 const llvm_un_ty = try o.lowerType(un_ty);
90419075 if (layout.payload_size == 0)
90429076 return self.wip.load(.normal, llvm_un_ty, union_handle, .default, "");
9043 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);
9077 const tag_index = @intFromBool(layout.tag_align.compare(.lt, layout.payload_align));
90449078 const tag_field_ptr = try self.wip.gepStruct(llvm_un_ty, union_handle, tag_index, "");
90459079 const llvm_tag_ty = llvm_un_ty.structFields(&o.builder)[tag_index];
90469080 return self.wip.load(.normal, llvm_tag_ty, tag_field_ptr, .default, "");
90479081 } else {
90489082 if (layout.payload_size == 0) return union_handle;
9049 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);
9083 const tag_index = @intFromBool(layout.tag_align.compare(.lt, layout.payload_align));
90509084 return self.wip.extractValue(union_handle, &.{tag_index}, "");
90519085 }
90529086 }
......@@ -9605,6 +9639,7 @@ pub const FuncGen = struct {
96059639 fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
96069640 const o = self.dg.object;
96079641 const mod = o.module;
9642 const ip = &mod.intern_pool;
96089643 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
96099644 const result_ty = self.typeOfIndex(inst);
96109645 const len: usize = @intCast(result_ty.arrayLen(mod));
......@@ -9622,23 +9657,21 @@ pub const FuncGen = struct {
96229657 return vector;
96239658 },
96249659 .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);
9660 if (mod.typeToPackedStruct(result_ty)) |struct_type| {
9661 const backing_int_ty = struct_type.backingIntType(ip).*;
9662 assert(backing_int_ty != .none);
9663 const big_bits = backing_int_ty.toType().bitSize(mod);
96299664 const int_ty = try o.builder.intType(@intCast(big_bits));
9630 const fields = struct_obj.fields.values();
96319665 comptime assert(Type.packed_struct_layout_version == 2);
96329666 var running_int = try o.builder.intValue(int_ty, 0);
96339667 var running_bits: u16 = 0;
9634 for (elements, 0..) |elem, i| {
9635 const field = fields[i];
9636 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
9668 for (elements, struct_type.field_types.get(ip)) |elem, field_ty| {
9669 if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
96379670
96389671 const non_int_val = try self.resolveInst(elem);
9639 const ty_bit_size: u16 = @intCast(field.ty.bitSize(mod));
9672 const ty_bit_size: u16 = @intCast(field_ty.toType().bitSize(mod));
96409673 const small_int_ty = try o.builder.intType(ty_bit_size);
9641 const small_int_val = if (field.ty.isPtrAtRuntime(mod))
9674 const small_int_val = if (field_ty.toType().isPtrAtRuntime(mod))
96429675 try self.wip.cast(.ptrtoint, non_int_val, small_int_ty, "")
96439676 else
96449677 try self.wip.cast(.bitcast, non_int_val, small_int_ty, "");
......@@ -9652,10 +9685,12 @@ pub const FuncGen = struct {
96529685 return running_int;
96539686 }
96549687
9688 assert(result_ty.containerLayout(mod) != .Packed);
9689
96559690 if (isByRef(result_ty, mod)) {
96569691 // TODO in debug builds init to undef so that the padding will be 0xaa
96579692 // even if we fully populate the fields.
9658 const alignment = Builder.Alignment.fromByteUnits(result_ty.abiAlignment(mod));
9693 const alignment = result_ty.abiAlignment(mod).toLlvm();
96599694 const alloca_inst = try self.buildAlloca(llvm_result_ty, alignment);
96609695
96619696 for (elements, 0..) |elem, i| {
......@@ -9668,9 +9703,7 @@ pub const FuncGen = struct {
96689703 const field_ptr_ty = try mod.ptrType(.{
96699704 .child = self.typeOf(elem).toIntern(),
96709705 .flags = .{
9671 .alignment = InternPool.Alignment.fromNonzeroByteUnits(
9672 result_ty.structFieldAlign(i, mod),
9673 ),
9706 .alignment = result_ty.structFieldAlign(i, mod),
96749707 },
96759708 });
96769709 try self.store(field_ptr, field_ptr_ty, llvm_elem, .none);
......@@ -9694,7 +9727,7 @@ pub const FuncGen = struct {
96949727
96959728 const llvm_usize = try o.lowerType(Type.usize);
96969729 const usize_zero = try o.builder.intValue(llvm_usize, 0);
9697 const alignment = Builder.Alignment.fromByteUnits(result_ty.abiAlignment(mod));
9730 const alignment = result_ty.abiAlignment(mod).toLlvm();
96989731 const alloca_inst = try self.buildAlloca(llvm_result_ty, alignment);
96999732
97009733 const array_info = result_ty.arrayInfo(mod);
......@@ -9770,7 +9803,7 @@ pub const FuncGen = struct {
97709803 // necessarily match the format that we need, depending on which tag is active.
97719804 // We must construct the correct unnamed struct type here, in order to then set
97729805 // the fields appropriately.
9773 const alignment = Builder.Alignment.fromByteUnits(layout.abi_align);
9806 const alignment = layout.abi_align.toLlvm();
97749807 const result_ptr = try self.buildAlloca(union_llvm_ty, alignment);
97759808 const llvm_payload = try self.resolveInst(extra.init);
97769809 const field_ty = union_obj.field_types.get(ip)[extra.field_index].toType();
......@@ -9799,7 +9832,7 @@ pub const FuncGen = struct {
97999832 const tag_ty = try o.lowerType(union_obj.enum_tag_ty.toType());
98009833 var fields: [3]Builder.Type = undefined;
98019834 var fields_len: usize = 2;
9802 if (layout.tag_align >= layout.payload_align) {
9835 if (layout.tag_align.compare(.gte, layout.payload_align)) {
98039836 fields = .{ tag_ty, payload_ty, undefined };
98049837 } else {
98059838 fields = .{ payload_ty, tag_ty, undefined };
......@@ -9815,7 +9848,7 @@ pub const FuncGen = struct {
98159848 // tag and the payload.
98169849 const field_ptr_ty = try mod.ptrType(.{
98179850 .child = field_ty.toIntern(),
9818 .flags = .{ .alignment = InternPool.Alignment.fromNonzeroByteUnits(field_align) },
9851 .flags = .{ .alignment = field_align },
98199852 });
98209853 if (layout.tag_size == 0) {
98219854 const indices = [3]Builder.Value{ usize_zero, i32_zero, i32_zero };
......@@ -9827,7 +9860,7 @@ pub const FuncGen = struct {
98279860 }
98289861
98299862 {
9830 const payload_index = @intFromBool(layout.tag_align >= layout.payload_align);
9863 const payload_index = @intFromBool(layout.tag_align.compare(.gte, layout.payload_align));
98319864 const indices: [3]Builder.Value =
98329865 .{ usize_zero, try o.builder.intValue(.i32, payload_index), i32_zero };
98339866 const len: usize = if (field_size == layout.payload_size) 2 else 3;
......@@ -9836,12 +9869,12 @@ pub const FuncGen = struct {
98369869 try self.store(field_ptr, field_ptr_ty, llvm_payload, .none);
98379870 }
98389871 {
9839 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);
9872 const tag_index = @intFromBool(layout.tag_align.compare(.lt, layout.payload_align));
98409873 const indices: [2]Builder.Value = .{ usize_zero, try o.builder.intValue(.i32, tag_index) };
98419874 const field_ptr = try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, &indices, "");
98429875 const tag_ty = try o.lowerType(union_obj.enum_tag_ty.toType());
98439876 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));
9877 const tag_alignment = union_obj.enum_tag_ty.toType().abiAlignment(mod).toLlvm();
98459878 _ = try self.wip.store(.normal, llvm_tag, field_ptr, tag_alignment);
98469879 }
98479880
......@@ -9978,7 +10011,7 @@ pub const FuncGen = struct {
997810011 variable_index.setMutability(.constant, &o.builder);
997910012 variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
998010013 variable_index.setAlignment(
9981 Builder.Alignment.fromByteUnits(Type.slice_const_u8_sentinel_0.abiAlignment(mod)),
10014 Type.slice_const_u8_sentinel_0.abiAlignment(mod).toLlvm(),
998210015 &o.builder,
998310016 );
998410017
......@@ -10023,7 +10056,7 @@ pub const FuncGen = struct {
1002310056 // We have a pointer and we need to return a pointer to the first field.
1002410057 const payload_ptr = try fg.wip.gepStruct(opt_llvm_ty, opt_handle, 0, "");
1002510058
10026 const payload_alignment = Builder.Alignment.fromByteUnits(payload_ty.abiAlignment(mod));
10059 const payload_alignment = payload_ty.abiAlignment(mod).toLlvm();
1002710060 if (isByRef(payload_ty, mod)) {
1002810061 if (can_elide_load)
1002910062 return payload_ptr;
......@@ -10050,7 +10083,7 @@ pub const FuncGen = struct {
1005010083 const mod = o.module;
1005110084
1005210085 if (isByRef(optional_ty, mod)) {
10053 const payload_alignment = Builder.Alignment.fromByteUnits(optional_ty.abiAlignment(mod));
10086 const payload_alignment = optional_ty.abiAlignment(mod).toLlvm();
1005410087 const alloca_inst = try self.buildAlloca(optional_llvm_ty, payload_alignment);
1005510088
1005610089 {
......@@ -10123,7 +10156,7 @@ pub const FuncGen = struct {
1012310156 .Union => {
1012410157 const layout = struct_ty.unionGetLayout(mod);
1012510158 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);
10159 const payload_index = @intFromBool(layout.tag_align.compare(.gte, layout.payload_align));
1012710160 const union_llvm_ty = try o.lowerType(struct_ty);
1012810161 return self.wip.gepStruct(union_llvm_ty, struct_ptr, payload_index, "");
1012910162 },
......@@ -10142,9 +10175,7 @@ pub const FuncGen = struct {
1014210175 const o = fg.dg.object;
1014310176 const mod = o.module;
1014410177 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 );
10178 const result_align = InternPool.Alignment.fromLlvm(ptr_alignment).max(pointee_type.abiAlignment(mod)).toLlvm();
1014810179 const result_ptr = try fg.buildAlloca(pointee_llvm_ty, result_align);
1014910180 const size_bytes = pointee_type.abiSize(mod);
1015010181 _ = try fg.wip.callMemCpy(
......@@ -10168,9 +10199,11 @@ pub const FuncGen = struct {
1016810199 const elem_ty = info.child.toType();
1016910200 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none;
1017010201
10171 const ptr_alignment = Builder.Alignment.fromByteUnits(
10172 info.flags.alignment.toByteUnitsOptional() orelse elem_ty.abiAlignment(mod),
10173 );
10202 const ptr_alignment = (if (info.flags.alignment != .none)
10203 @as(InternPool.Alignment, info.flags.alignment)
10204 else
10205 elem_ty.abiAlignment(mod)).toLlvm();
10206
1017410207 const access_kind: Builder.MemoryAccessKind =
1017510208 if (info.flags.is_volatile) .@"volatile" else .normal;
1017610209
......@@ -10201,7 +10234,7 @@ pub const FuncGen = struct {
1020110234 const elem_llvm_ty = try o.lowerType(elem_ty);
1020210235
1020310236 if (isByRef(elem_ty, mod)) {
10204 const result_align = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
10237 const result_align = elem_ty.abiAlignment(mod).toLlvm();
1020510238 const result_ptr = try self.buildAlloca(elem_llvm_ty, result_align);
1020610239
1020710240 const same_size_int = try o.builder.intType(@intCast(elem_bits));
......@@ -10239,7 +10272,7 @@ pub const FuncGen = struct {
1023910272 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) {
1024010273 return;
1024110274 }
10242 const ptr_alignment = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
10275 const ptr_alignment = ptr_ty.ptrAlignment(mod).toLlvm();
1024310276 const access_kind: Builder.MemoryAccessKind =
1024410277 if (info.flags.is_volatile) .@"volatile" else .normal;
1024510278
......@@ -10305,7 +10338,7 @@ pub const FuncGen = struct {
1030510338 ptr,
1030610339 ptr_alignment,
1030710340 elem,
10308 Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod)),
10341 elem_ty.abiAlignment(mod).toLlvm(),
1030910342 try o.builder.intValue(try o.lowerType(Type.usize), elem_ty.abiSize(mod)),
1031010343 access_kind,
1031110344 );
......@@ -10337,7 +10370,7 @@ pub const FuncGen = struct {
1033710370 if (!target_util.hasValgrindSupport(target)) return default_value;
1033810371
1033910372 const llvm_usize = try o.lowerType(Type.usize);
10340 const usize_alignment = Builder.Alignment.fromByteUnits(Type.usize.abiAlignment(mod));
10373 const usize_alignment = Type.usize.abiAlignment(mod).toLlvm();
1034110374
1034210375 const array_llvm_ty = try o.builder.arrayType(6, llvm_usize);
1034310376 const array_ptr = if (fg.valgrind_client_request_array == .none) a: {
......@@ -10718,6 +10751,7 @@ fn lowerWin64FnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Err
1071810751
1071910752fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type {
1072010753 const mod = o.module;
10754 const ip = &mod.intern_pool;
1072110755 const return_type = fn_info.return_type.toType();
1072210756 if (isScalar(mod, return_type)) {
1072310757 return o.lowerType(return_type);
......@@ -10761,12 +10795,16 @@ fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.E
1076110795 const first_non_integer = std.mem.indexOfNone(x86_64_abi.Class, &classes, &.{.integer});
1076210796 if (first_non_integer == null or classes[first_non_integer.?] == .none) {
1076310797 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));
10798 switch (ip.indexToKey(return_type.toIntern())) {
10799 .struct_type => |struct_type| {
10800 assert(struct_type.haveLayout(ip));
10801 const size: u64 = struct_type.size(ip).*;
10802 assert((std.math.divCeil(u64, size, 8) catch unreachable) == types_index);
10803 if (size % 8 > 0) {
10804 types_buffer[types_index - 1] = try o.builder.intType(@intCast(size % 8 * 8));
10805 }
10806 },
10807 else => {},
1077010808 }
1077110809 if (types_index == 1) return types_buffer[0];
1077210810 }
......@@ -10982,6 +11020,7 @@ const ParamTypeIterator = struct {
1098211020
1098311021 fn nextSystemV(it: *ParamTypeIterator, ty: Type) Allocator.Error!?Lowering {
1098411022 const mod = it.object.module;
11023 const ip = &mod.intern_pool;
1098511024 const classes = x86_64_abi.classifySystemV(ty, mod, .arg);
1098611025 if (classes[0] == .memory) {
1098711026 it.zig_index += 1;
......@@ -11037,12 +11076,17 @@ const ParamTypeIterator = struct {
1103711076 it.llvm_index += 1;
1103811077 return .abi_sized_int;
1103911078 }
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));
11079 switch (ip.indexToKey(ty.toIntern())) {
11080 .struct_type => |struct_type| {
11081 assert(struct_type.haveLayout(ip));
11082 const size: u64 = struct_type.size(ip).*;
11083 assert((std.math.divCeil(u64, size, 8) catch unreachable) == types_index);
11084 if (size % 8 > 0) {
11085 types_buffer[types_index - 1] =
11086 try it.object.builder.intType(@intCast(size % 8 * 8));
11087 }
11088 },
11089 else => {},
1104611090 }
1104711091 }
1104811092 it.types_len = types_index;
......@@ -11137,8 +11181,6 @@ fn isByRef(ty: Type, mod: *Module) bool {
1113711181
1113811182 .Array, .Frame => return ty.hasRuntimeBits(mod),
1113911183 .Struct => {
11140 // Packed structs are represented to LLVM as integers.
11141 if (ty.containerLayout(mod) == .Packed) return false;
1114211184 const struct_type = switch (ip.indexToKey(ty.toIntern())) {
1114311185 .anon_struct_type => |tuple| {
1114411186 var count: usize = 0;
......@@ -11154,14 +11196,18 @@ fn isByRef(ty: Type, mod: *Module) bool {
1115411196 .struct_type => |s| s,
1115511197 else => unreachable,
1115611198 };
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;
1116111199
11200 // Packed structs are represented to LLVM as integers.
11201 if (struct_type.layout == .Packed) return false;
11202
11203 const field_types = struct_type.field_types.get(ip);
11204 var it = struct_type.iterateRuntimeOrder(ip);
11205 var count: usize = 0;
11206 while (it.next()) |field_index| {
1116211207 count += 1;
1116311208 if (count > max_fields_byval) return true;
11164 if (isByRef(field.ty, mod)) return true;
11209 const field_ty = field_types[field_index].toType();
11210 if (isByRef(field_ty, mod)) return true;
1116511211 }
1116611212 return false;
1116711213 },
......@@ -11362,11 +11408,11 @@ fn buildAllocaInner(
1136211408}
1136311409
1136411410fn errUnionPayloadOffset(payload_ty: Type, mod: *Module) u1 {
11365 return @intFromBool(Type.err_int.abiAlignment(mod) > payload_ty.abiAlignment(mod));
11411 return @intFromBool(Type.err_int.abiAlignment(mod).compare(.gt, payload_ty.abiAlignment(mod)));
1136611412}
1136711413
1136811414fn errUnionErrorOffset(payload_ty: Type, mod: *Module) u1 {
11369 return @intFromBool(Type.err_int.abiAlignment(mod) <= payload_ty.abiAlignment(mod));
11415 return @intFromBool(Type.err_int.abiAlignment(mod).compare(.lte, payload_ty.abiAlignment(mod)));
1137011416}
1137111417
1137211418/// 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+42-28
......@@ -341,37 +341,51 @@ 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
355 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;
361 const field_name = ip.stringToSlice(field_name_ip);
362 // DW.AT.member
363 try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2);
364 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevKind.struct_member));
365 // DW.AT.name, DW.FORM.string
366 dbg_info_buffer.appendSliceAssumeCapacity(field_name);
367 dbg_info_buffer.appendAssumeCapacity(0);
368 // DW.AT.type, DW.FORM.ref4
369 var index = dbg_info_buffer.items.len;
370 try dbg_info_buffer.resize(index + 4);
371 try self.addTypeRelocGlobal(atom_index, field.ty, @as(u32, @intCast(index)));
372 // DW.AT.data_member_location, DW.FORM.udata
373 const field_off = ty.structFieldOffset(field_index, mod);
374 try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
354 if (struct_type.isTuple(ip)) {
355 for (struct_type.field_types.get(ip), struct_type.offsets.get(ip), 0..) |field_ty, field_off, field_index| {
356 if (!field_ty.toType().hasRuntimeBits(mod)) continue;
357 // DW.AT.member
358 try dbg_info_buffer.append(@intFromEnum(AbbrevKind.struct_member));
359 // DW.AT.name, DW.FORM.string
360 try dbg_info_buffer.writer().print("{d}\x00", .{field_index});
361 // DW.AT.type, DW.FORM.ref4
362 var index = dbg_info_buffer.items.len;
363 try dbg_info_buffer.resize(index + 4);
364 try self.addTypeRelocGlobal(atom_index, field_ty.toType(), @as(u32, @intCast(index)));
365 // DW.AT.data_member_location, DW.FORM.udata
366 try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
367 }
368 } else {
369 for (
370 struct_type.field_names.get(ip),
371 struct_type.field_types.get(ip),
372 struct_type.offsets.get(ip),
373 ) |field_name_ip, field_ty, field_off| {
374 if (!field_ty.toType().hasRuntimeBits(mod)) continue;
375 const field_name = ip.stringToSlice(field_name_ip);
376 // DW.AT.member
377 try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2);
378 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevKind.struct_member));
379 // DW.AT.name, DW.FORM.string
380 dbg_info_buffer.appendSliceAssumeCapacity(field_name);
381 dbg_info_buffer.appendAssumeCapacity(0);
382 // DW.AT.type, DW.FORM.ref4
383 var index = dbg_info_buffer.items.len;
384 try dbg_info_buffer.resize(index + 4);
385 try self.addTypeRelocGlobal(atom_index, field_ty.toType(), @intCast(index));
386 // DW.AT.data_member_location, DW.FORM.udata
387 try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
388 }
375389 }
376390 },
377391 else => unreachable,
......@@ -416,8 +430,8 @@ pub const DeclState = struct {
416430 .Union => {
417431 const union_obj = mod.typeToUnion(ty).?;
418432 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;
433 const payload_offset = if (layout.tag_align.compare(.gte, layout.payload_align)) layout.tag_size else 0;
434 const tag_offset = if (layout.tag_align.compare(.gte, layout.payload_align)) 0 else layout.payload_size;
421435 // TODO this is temporary to match current state of unions in Zig - we don't yet have
422436 // safety checks implemented meaning the implicit tag is not yet stored and generated
423437 // for untagged unions.
......@@ -496,11 +510,11 @@ pub const DeclState = struct {
496510 .ErrorUnion => {
497511 const error_ty = ty.errorUnionSet(mod);
498512 const payload_ty = ty.errorUnionPayload(mod);
499 const payload_align = if (payload_ty.isNoReturn(mod)) 0 else payload_ty.abiAlignment(mod);
513 const payload_align = if (payload_ty.isNoReturn(mod)) .none else payload_ty.abiAlignment(mod);
500514 const error_align = Type.anyerror.abiAlignment(mod);
501515 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);
516 const payload_off = if (error_align.compare(.gte, payload_align)) Type.anyerror.abiSize(mod) else 0;
517 const error_off = if (error_align.compare(.gte, payload_align)) 0 else payload_ty.abiSize(mod);
504518
505519 // DW.AT.structure_type
506520 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+265-402
......@@ -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,9 +197,11 @@ 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);
201 try writer.print("align({d}", .{alignment});
204 try writer.print("align({d}", .{alignment.toByteUnits(0)});
202205
203206 if (info.packed_offset.bit_offset != 0 or info.packed_offset.host_size != 0) {
204207 try writer.print(":{d}:{d}", .{
......@@ -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 /// Never returns `none`. Asserts that all necessary type resolution is already done.
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.toByteUnits(0)),
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 = .@"1" },
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 = .@"1" };
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,50 @@ 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 .type_info,
933 => return .{
934 .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)),
935 },
936
937 .c_char => return .{ .scalar = cTypeAlign(target, .char) },
938 .c_short => return .{ .scalar = cTypeAlign(target, .short) },
939 .c_ushort => return .{ .scalar = cTypeAlign(target, .ushort) },
940 .c_int => return .{ .scalar = cTypeAlign(target, .int) },
941 .c_uint => return .{ .scalar = cTypeAlign(target, .uint) },
942 .c_long => return .{ .scalar = cTypeAlign(target, .long) },
943 .c_ulong => return .{ .scalar = cTypeAlign(target, .ulong) },
944 .c_longlong => return .{ .scalar = cTypeAlign(target, .longlong) },
945 .c_ulonglong => return .{ .scalar = cTypeAlign(target, .ulonglong) },
946 .c_longdouble => return .{ .scalar = cTypeAlign(target, .longdouble) },
947
948 .f16 => return .{ .scalar = .@"2" },
949 .f32 => return .{ .scalar = cTypeAlign(target, .float) },
950950 .f64 => switch (target.c_type_bit_size(.double)) {
951 64 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.double) },
952 else => return AbiAlignmentAdvanced{ .scalar = 8 },
951 64 => return .{ .scalar = cTypeAlign(target, .double) },
952 else => return .{ .scalar = .@"8" },
953953 },
954954 .f80 => switch (target.c_type_bit_size(.longdouble)) {
955 80 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) },
955 80 => return .{ .scalar = cTypeAlign(target, .longdouble) },
956956 else => {
957957 const u80_ty: Type = .{ .ip_index = .u80_type };
958 return AbiAlignmentAdvanced{ .scalar = abiAlignment(u80_ty, mod) };
958 return .{ .scalar = abiAlignment(u80_ty, mod) };
959959 },
960960 },
961961 .f128 => switch (target.c_type_bit_size(.longdouble)) {
962 128 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) },
963 else => return AbiAlignmentAdvanced{ .scalar = 16 },
962 128 => return .{ .scalar = cTypeAlign(target, .longdouble) },
963 else => return .{ .scalar = .@"16" },
964964 },
965965
966966 // TODO revisit this when we have the concept of the error tag type
967967 .anyerror,
968968 .adhoc_inferred_error_set,
969 => return AbiAlignmentAdvanced{ .scalar = 2 },
969 => return .{ .scalar = .@"2" },
970970
971971 .void,
972972 .type,
......@@ -975,90 +975,46 @@ pub const Type = struct {
975975 .null,
976976 .undefined,
977977 .enum_literal,
978 .type_info,
979 => return AbiAlignmentAdvanced{ .scalar = 0 },
978 => return .{ .scalar = .@"1" },
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() },
1012 .eager => {},
1013 }
1014 assert(struct_obj.haveLayout());
1015 return AbiAlignmentAdvanced{ .scalar = struct_obj.backing_int_ty.abiAlignment(mod) };
1016 }
1017
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;
1028
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 = .{
987 .lazy => if (struct_type.backingIntType(ip).* == .none) return .{
988 .val = (try mod.intern(.{ .int = .{
1036989 .ty = .comptime_int_type,
1037990 .storage = .{ .lazy_align = ty.toIntern() },
1038 } })).toValue() },
991 } })).toValue(),
1039992 },
1040 }));
1041 big_align = @max(big_align, field_align);
1042
1043 // This logic is duplicated in Module.Struct.Field.alignment.
1044 if (struct_obj.layout == .Extern or target.ofmt == .c) {
1045 if (field.ty.isAbiInt(mod) and field.ty.intInfo(mod).bits >= 128) {
1046 // The C ABI requires 128 bit integer fields of structs
1047 // to be 16-bytes aligned.
1048 big_align = @max(big_align, 16);
1049 }
993 .eager => {},
1050994 }
995 return .{ .scalar = struct_type.backingIntType(ip).toType().abiAlignment(mod) };
1051996 }
1052 return AbiAlignmentAdvanced{ .scalar = big_align };
997
998 const flags = struct_type.flagsPtr(ip).*;
999 if (flags.alignment != .none) return .{ .scalar = flags.alignment };
1000
1001 return switch (strat) {
1002 .eager => unreachable, // struct alignment not resolved
1003 .sema => |sema| .{
1004 .scalar = try sema.resolveStructAlignment(ty.toIntern(), struct_type),
1005 },
1006 .lazy => .{ .val = (try mod.intern(.{ .int = .{
1007 .ty = .comptime_int_type,
1008 .storage = .{ .lazy_align = ty.toIntern() },
1009 } })).toValue() },
1010 };
10531011 },
10541012 .anon_struct_type => |tuple| {
1055 var big_align: u32 = 0;
1013 var big_align: Alignment = .@"1";
10561014 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
10571015 if (val != .none) continue; // comptime field
1058 if (!(field_ty.toType().hasRuntimeBits(mod))) continue;
1059
10601016 switch (try field_ty.toType().abiAlignmentAdvanced(mod, strat)) {
1061 .scalar => |field_align| big_align = @max(big_align, field_align),
1017 .scalar => |field_align| big_align = big_align.max(field_align),
10621018 .val => switch (strat) {
10631019 .eager => unreachable, // field type alignment not resolved
10641020 .sema => unreachable, // passed to abiAlignmentAdvanced above
......@@ -1069,7 +1025,7 @@ pub const Type = struct {
10691025 },
10701026 }
10711027 }
1072 return AbiAlignmentAdvanced{ .scalar = big_align };
1028 return .{ .scalar = big_align };
10731029 },
10741030
10751031 .union_type => |union_type| {
......@@ -1078,7 +1034,7 @@ pub const Type = struct {
10781034 // We'll guess "pointer-aligned", if the union has an
10791035 // underaligned pointer field then some allocations
10801036 // might require explicit alignment.
1081 return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) };
1037 return .{ .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)) };
10821038 }
10831039 _ = try sema.resolveTypeFields(ty);
10841040 }
......@@ -1095,13 +1051,11 @@ pub const Type = struct {
10951051 if (union_obj.hasTag(ip)) {
10961052 return abiAlignmentAdvanced(union_obj.enum_tag_ty.toType(), mod, strat);
10971053 } else {
1098 return AbiAlignmentAdvanced{
1099 .scalar = @intFromBool(union_obj.flagsPtr(ip).layout == .Extern),
1100 };
1054 return .{ .scalar = .@"1" };
11011055 }
11021056 }
11031057
1104 var max_align: u32 = 0;
1058 var max_align: Alignment = .@"1";
11051059 if (union_obj.hasTag(ip)) max_align = union_obj.enum_tag_ty.toType().abiAlignment(mod);
11061060 for (0..union_obj.field_names.len) |field_index| {
11071061 const field_ty = union_obj.field_types.get(ip)[field_index].toType();
......@@ -1117,8 +1071,9 @@ pub const Type = struct {
11171071 else => |e| return e,
11181072 })) continue;
11191073
1120 const field_align_bytes: u32 = @intCast(field_align.toByteUnitsOptional() orelse
1121 switch (try field_ty.abiAlignmentAdvanced(mod, strat)) {
1074 const field_align_bytes: Alignment = if (field_align != .none)
1075 field_align
1076 else switch (try field_ty.abiAlignmentAdvanced(mod, strat)) {
11221077 .scalar => |a| a,
11231078 .val => switch (strat) {
11241079 .eager => unreachable, // struct layout not resolved
......@@ -1128,13 +1083,15 @@ pub const Type = struct {
11281083 .storage = .{ .lazy_align = ty.toIntern() },
11291084 } })).toValue() },
11301085 },
1131 });
1132 max_align = @max(max_align, field_align_bytes);
1086 };
1087 max_align = max_align.max(field_align_bytes);
11331088 }
1134 return AbiAlignmentAdvanced{ .scalar = max_align };
1089 return .{ .scalar = max_align };
1090 },
1091 .opaque_type => return .{ .scalar = .@"1" },
1092 .enum_type => |enum_type| return .{
1093 .scalar = enum_type.tag_ty.toType().abiAlignment(mod),
11351094 },
1136 .opaque_type => return AbiAlignmentAdvanced{ .scalar = 1 },
1137 .enum_type => |enum_type| return AbiAlignmentAdvanced{ .scalar = enum_type.tag_ty.toType().abiAlignment(mod) },
11381095
11391096 // values, not types
11401097 .undef,
......@@ -1179,20 +1136,15 @@ pub const Type = struct {
11791136 } })).toValue() },
11801137 else => |e| return e,
11811138 })) {
1182 return AbiAlignmentAdvanced{ .scalar = code_align };
1139 return .{ .scalar = code_align };
11831140 }
1184 return AbiAlignmentAdvanced{ .scalar = @max(
1185 code_align,
1141 return .{ .scalar = code_align.max(
11861142 (try payload_ty.abiAlignmentAdvanced(mod, strat)).scalar,
11871143 ) };
11881144 },
11891145 .lazy => {
11901146 switch (try payload_ty.abiAlignmentAdvanced(mod, strat)) {
1191 .scalar => |payload_align| {
1192 return AbiAlignmentAdvanced{
1193 .scalar = @max(code_align, payload_align),
1194 };
1195 },
1147 .scalar => |payload_align| return .{ .scalar = code_align.max(payload_align) },
11961148 .val => {},
11971149 }
11981150 return .{ .val = (try mod.intern(.{ .int = .{
......@@ -1212,9 +1164,11 @@ pub const Type = struct {
12121164 const child_type = ty.optionalChild(mod);
12131165
12141166 switch (child_type.zigTypeTag(mod)) {
1215 .Pointer => return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) },
1167 .Pointer => return .{
1168 .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)),
1169 },
12161170 .ErrorSet => return abiAlignmentAdvanced(Type.anyerror, mod, strat),
1217 .NoReturn => return AbiAlignmentAdvanced{ .scalar = 0 },
1171 .NoReturn => return .{ .scalar = .@"1" },
12181172 else => {},
12191173 }
12201174
......@@ -1227,12 +1181,12 @@ pub const Type = struct {
12271181 } })).toValue() },
12281182 else => |e| return e,
12291183 })) {
1230 return AbiAlignmentAdvanced{ .scalar = 1 };
1184 return .{ .scalar = .@"1" };
12311185 }
12321186 return child_type.abiAlignmentAdvanced(mod, strat);
12331187 },
12341188 .lazy => switch (try child_type.abiAlignmentAdvanced(mod, strat)) {
1235 .scalar => |x| return AbiAlignmentAdvanced{ .scalar = @max(x, 1) },
1189 .scalar => |x| return .{ .scalar = x.max(.@"1") },
12361190 .val => return .{ .val = (try mod.intern(.{ .int = .{
12371191 .ty = .comptime_int_type,
12381192 .storage = .{ .lazy_align = ty.toIntern() },
......@@ -1310,8 +1264,7 @@ pub const Type = struct {
13101264 .storage = .{ .lazy_size = ty.toIntern() },
13111265 } })).toValue() },
13121266 };
1313 const elem_bits_u64 = try vector_type.child.toType().bitSizeAdvanced(mod, opt_sema);
1314 const elem_bits = @as(u32, @intCast(elem_bits_u64));
1267 const elem_bits = try vector_type.child.toType().bitSizeAdvanced(mod, opt_sema);
13151268 const total_bits = elem_bits * vector_type.len;
13161269 const total_bytes = (total_bits + 7) / 8;
13171270 const alignment = switch (try ty.abiAlignmentAdvanced(mod, strat)) {
......@@ -1321,8 +1274,7 @@ pub const Type = struct {
13211274 .storage = .{ .lazy_size = ty.toIntern() },
13221275 } })).toValue() },
13231276 };
1324 const result = std.mem.alignForward(u32, total_bytes, alignment);
1325 return AbiSizeAdvanced{ .scalar = result };
1277 return AbiSizeAdvanced{ .scalar = alignment.forward(total_bytes) };
13261278 },
13271279
13281280 .opt_type => return ty.abiSizeAdvancedOptional(mod, strat),
......@@ -1360,16 +1312,16 @@ pub const Type = struct {
13601312 };
13611313
13621314 var size: u64 = 0;
1363 if (code_align > payload_align) {
1315 if (code_align.compare(.gt, payload_align)) {
13641316 size += code_size;
1365 size = std.mem.alignForward(u64, size, payload_align);
1317 size = payload_align.forward(size);
13661318 size += payload_size;
1367 size = std.mem.alignForward(u64, size, code_align);
1319 size = code_align.forward(size);
13681320 } else {
13691321 size += payload_size;
1370 size = std.mem.alignForward(u64, size, code_align);
1322 size = code_align.forward(size);
13711323 size += code_size;
1372 size = std.mem.alignForward(u64, size, payload_align);
1324 size = payload_align.forward(size);
13731325 }
13741326 return AbiSizeAdvanced{ .scalar = size };
13751327 },
......@@ -1435,41 +1387,35 @@ pub const Type = struct {
14351387 .noreturn => unreachable,
14361388 .generic_poison => unreachable,
14371389 },
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() };
1390 .struct_type => |struct_type| {
1391 switch (strat) {
1392 .sema => |sema| try sema.resolveTypeLayout(ty),
1393 .lazy => switch (struct_type.layout) {
1394 .Packed => {
1395 if (struct_type.backingIntType(ip).* == .none) return .{
1396 .val = (try mod.intern(.{ .int = .{
1397 .ty = .comptime_int_type,
1398 .storage = .{ .lazy_size = ty.toIntern() },
1399 } })).toValue(),
1400 };
14641401 },
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 },
1402 .Auto, .Extern => {
1403 if (!struct_type.haveLayout(ip)) return .{
1404 .val = (try mod.intern(.{ .int = .{
1405 .ty = .comptime_int_type,
1406 .storage = .{ .lazy_size = ty.toIntern() },
1407 } })).toValue(),
1408 };
1409 },
1410 },
1411 .eager => {},
1412 }
1413 return switch (struct_type.layout) {
1414 .Packed => .{
1415 .scalar = struct_type.backingIntType(ip).toType().abiSize(mod),
1416 },
1417 .Auto, .Extern => .{ .scalar = struct_type.size(ip).* },
1418 };
14731419 },
14741420 .anon_struct_type => |tuple| {
14751421 switch (strat) {
......@@ -1565,20 +1511,19 @@ pub const Type = struct {
15651511 // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
15661512 // to the child type's ABI alignment.
15671513 return AbiSizeAdvanced{
1568 .scalar = child_ty.abiAlignment(mod) + payload_size,
1514 .scalar = child_ty.abiAlignment(mod).toByteUnits(0) + payload_size,
15691515 };
15701516 }
15711517
15721518 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);
1519 return intAbiAlignment(bits, target).forward(@as(u16, @intCast((@as(u17, bits) + 7) / 8)));
15751520 }
15761521
1577 fn intAbiAlignment(bits: u16, target: Target) u32 {
1578 return @min(
1522 fn intAbiAlignment(bits: u16, target: Target) Alignment {
1523 return Alignment.fromByteUnits(@min(
15791524 std.math.ceilPowerOfTwoPromote(u16, @as(u16, @intCast((@as(u17, bits) + 7) / 8))),
15801525 target.maxIntAlignment(),
1581 );
1526 ));
15821527 }
15831528
15841529 pub fn bitSize(ty: Type, mod: *Module) u64 {
......@@ -1610,7 +1555,7 @@ pub const Type = struct {
16101555 const len = array_type.len + @intFromBool(array_type.sentinel != .none);
16111556 if (len == 0) return 0;
16121557 const elem_ty = array_type.child.toType();
1613 const elem_size = @max(elem_ty.abiAlignment(mod), elem_ty.abiSize(mod));
1558 const elem_size = @max(elem_ty.abiAlignment(mod).toByteUnits(0), elem_ty.abiSize(mod));
16141559 if (elem_size == 0) return 0;
16151560 const elem_bit_size = try bitSizeAdvanced(elem_ty, mod, opt_sema);
16161561 return (len - 1) * 8 * elem_size + elem_bit_size;
......@@ -1675,35 +1620,33 @@ pub const Type = struct {
16751620 .enum_literal => unreachable,
16761621 .generic_poison => unreachable,
16771622
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
1623 .atomic_order => unreachable,
1624 .atomic_rmw_op => unreachable,
1625 .calling_convention => unreachable,
1626 .address_space => unreachable,
1627 .float_mode => unreachable,
1628 .reduce_op => unreachable,
1629 .call_modifier => unreachable,
1630 .prefetch_options => unreachable,
1631 .export_options => unreachable,
1632 .extern_options => unreachable,
1633 .type_info => unreachable,
16891634 },
16901635 .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;
1636 if (struct_type.layout == .Packed) {
1637 if (opt_sema) |sema| try sema.resolveTypeLayout(ty);
1638 return try struct_type.backingIntType(ip).*.toType().bitSizeAdvanced(mod, opt_sema);
16941639 }
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);
1640 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
16981641 },
16991642
17001643 .anon_struct_type => {
1701 if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty);
1644 if (opt_sema) |sema| try sema.resolveTypeFields(ty);
17021645 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
17031646 },
17041647
17051648 .union_type => |union_type| {
1706 if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty);
1649 if (opt_sema) |sema| try sema.resolveTypeFields(ty);
17071650 if (ty.containerLayout(mod) != .Packed) {
17081651 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
17091652 }
......@@ -1749,13 +1692,7 @@ pub const Type = struct {
17491692 pub fn layoutIsResolved(ty: Type, mod: *Module) bool {
17501693 const ip = &mod.intern_pool;
17511694 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 },
1695 .struct_type => |struct_type| struct_type.haveLayout(ip),
17591696 .union_type => |union_type| union_type.haveLayout(ip),
17601697 .array_type => |array_type| {
17611698 if ((array_type.len + @intFromBool(array_type.sentinel != .none)) == 0) return true;
......@@ -2020,10 +1957,7 @@ pub const Type = struct {
20201957 pub fn containerLayout(ty: Type, mod: *Module) std.builtin.Type.ContainerLayout {
20211958 const ip = &mod.intern_pool;
20221959 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 },
1960 .struct_type => |struct_type| struct_type.layout,
20271961 .anon_struct_type => .Auto,
20281962 .union_type => |union_type| union_type.flagsPtr(ip).layout,
20291963 else => unreachable,
......@@ -2136,10 +2070,7 @@ pub const Type = struct {
21362070 return switch (ip.indexToKey(ty.toIntern())) {
21372071 .vector_type => |vector_type| vector_type.len,
21382072 .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 },
2073 .struct_type => |struct_type| struct_type.field_types.len,
21432074 .anon_struct_type => |tuple| tuple.types.len,
21442075
21452076 else => unreachable,
......@@ -2214,6 +2145,7 @@ pub const Type = struct {
22142145
22152146 /// Asserts the type is an integer, enum, error set, or vector of one of them.
22162147 pub fn intInfo(starting_ty: Type, mod: *Module) InternPool.Key.IntType {
2148 const ip = &mod.intern_pool;
22172149 const target = mod.getTarget();
22182150 var ty = starting_ty;
22192151
......@@ -2233,13 +2165,9 @@ pub const Type = struct {
22332165 .c_ulong_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulong) },
22342166 .c_longlong_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.longlong) },
22352167 .c_ulonglong_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulonglong) },
2236 else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2168 else => switch (ip.indexToKey(ty.toIntern())) {
22372169 .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 },
2170 .struct_type => |t| ty = t.backingIntType(ip).*.toType(),
22432171 .enum_type => |enum_type| ty = enum_type.tag_ty.toType(),
22442172 .vector_type => |vector_type| ty = vector_type.child.toType(),
22452173
......@@ -2503,33 +2431,28 @@ pub const Type = struct {
25032431 .generic_poison => unreachable,
25042432 },
25052433 .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;
2434 assert(struct_type.haveFieldTypes(ip));
2435 if (struct_type.knownNonOpv(ip))
2436 return null;
2437 const field_vals = try mod.gpa.alloc(InternPool.Index, struct_type.field_types.len);
2438 defer mod.gpa.free(field_vals);
2439 for (field_vals, 0..) |*field_val, i_usize| {
2440 const i: u32 = @intCast(i_usize);
2441 if (struct_type.fieldIsComptime(ip, i)) {
2442 field_val.* = struct_type.field_inits.get(ip)[i];
2443 continue;
25182444 }
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();
2445 const field_ty = struct_type.field_types.get(ip)[i].toType();
2446 if (try field_ty.onePossibleValue(mod)) |field_opv| {
2447 field_val.* = try field_opv.intern(field_ty, mod);
2448 } else return null;
25262449 }
25272450
2528 // In this case the struct has no fields at all and
2451 // In this case the struct has no runtime-known fields and
25292452 // therefore has one possible value.
25302453 return (try mod.intern(.{ .aggregate = .{
25312454 .ty = ty.toIntern(),
2532 .storage = .{ .elems = &.{} },
2455 .storage = .{ .elems = field_vals },
25332456 } })).toValue();
25342457 },
25352458
......@@ -2715,18 +2638,20 @@ pub const Type = struct {
27152638 => true,
27162639 },
27172640 .struct_type => |struct_type| {
2641 // packed structs cannot be comptime-only because they have a well-defined
2642 // memory layout and every field has a well-defined bit pattern.
2643 if (struct_type.layout == .Packed)
2644 return false;
2645
27182646 // 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 }
2647 return switch (struct_type.flagsPtr(ip).requires_comptime) {
2648 // Return false to avoid incorrect dependency loops.
2649 // This will be handled correctly once merged with
2650 // `Sema.typeRequiresComptime`.
2651 .wip, .unknown => false,
2652 .no => false,
2653 .yes => true,
2654 };
27302655 },
27312656
27322657 .anon_struct_type => |tuple| {
......@@ -2982,37 +2907,31 @@ pub const Type = struct {
29822907 return enum_type.tagValueIndex(ip, int_tag);
29832908 }
29842909
2985 pub fn structFields(ty: Type, mod: *Module) Module.Struct.Fields {
2986 switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2987 .struct_type => |struct_type| {
2988 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return .{};
2989 assert(struct_obj.haveFieldTypes());
2990 return struct_obj.fields;
2991 },
2992 else => unreachable,
2993 }
2994 }
2995
2996 pub fn structFieldName(ty: Type, field_index: usize, mod: *Module) InternPool.NullTerminatedString {
2910 /// Returns none in the case of a tuple which uses the integer index as the field name.
2911 pub fn structFieldName(ty: Type, field_index: u32, mod: *Module) InternPool.OptionalNullTerminatedString {
29972912 const ip = &mod.intern_pool;
29982913 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 },
3004 .anon_struct_type => |anon_struct| anon_struct.names.get(ip)[field_index],
2914 .struct_type => |struct_type| struct_type.fieldName(ip, field_index),
2915 .anon_struct_type => |anon_struct| anon_struct.fieldName(ip, field_index),
30052916 else => unreachable,
30062917 };
30072918 }
30082919
3009 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 },
2920 /// When struct types have no field names, the names are implicitly understood to be
2921 /// strings corresponding to the field indexes in declaration order. It used to be the
2922 /// case that a NullTerminatedString would be stored for each field in this case, however,
2923 /// now, callers must handle the possibility that there are no names stored at all.
2924 /// Here we fake the previous behavior. Probably something better could be done by examining
2925 /// all the callsites of this function.
2926 pub fn legacyStructFieldName(ty: Type, i: u32, mod: *Module) InternPool.NullTerminatedString {
2927 return ty.structFieldName(i, mod).unwrap() orelse
2928 mod.intern_pool.getOrPutStringFmt(mod.gpa, "{d}", .{i}) catch @panic("OOM");
2929 }
2930
2931 pub fn structFieldCount(ty: Type, mod: *Module) u32 {
2932 const ip = &mod.intern_pool;
2933 return switch (ip.indexToKey(ty.toIntern())) {
2934 .struct_type => |struct_type| struct_type.field_types.len,
30162935 .anon_struct_type => |anon_struct| anon_struct.types.len,
30172936 else => unreachable,
30182937 };
......@@ -3022,11 +2941,7 @@ pub const Type = struct {
30222941 pub fn structFieldType(ty: Type, index: usize, mod: *Module) Type {
30232942 const ip = &mod.intern_pool;
30242943 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 },
2944 .struct_type => |struct_type| struct_type.field_types.get(ip)[index].toType(),
30302945 .union_type => |union_type| {
30312946 const union_obj = ip.loadUnionType(union_type);
30322947 return union_obj.field_types.get(ip)[index].toType();
......@@ -3036,13 +2951,14 @@ pub const Type = struct {
30362951 };
30372952 }
30382953
3039 pub fn structFieldAlign(ty: Type, index: usize, mod: *Module) u32 {
2954 pub fn structFieldAlign(ty: Type, index: usize, mod: *Module) Alignment {
30402955 const ip = &mod.intern_pool;
30412956 switch (ip.indexToKey(ty.toIntern())) {
30422957 .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);
2958 assert(struct_type.layout != .Packed);
2959 const explicit_align = struct_type.fieldAlign(ip, index);
2960 const field_ty = struct_type.field_types.get(ip)[index].toType();
2961 return mod.structFieldAlignment(explicit_align, field_ty, struct_type.layout);
30462962 },
30472963 .anon_struct_type => |anon_struct| {
30482964 return anon_struct.types.get(ip)[index].toType().abiAlignment(mod);
......@@ -3059,8 +2975,7 @@ pub const Type = struct {
30592975 const ip = &mod.intern_pool;
30602976 switch (ip.indexToKey(ty.toIntern())) {
30612977 .struct_type => |struct_type| {
3062 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
3063 const val = struct_obj.fields.values()[index].default_val;
2978 const val = struct_type.fieldInit(ip, index);
30642979 // TODO: avoid using `unreachable` to indicate this.
30652980 if (val == .none) return Value.@"unreachable";
30662981 return val.toValue();
......@@ -3079,12 +2994,10 @@ pub const Type = struct {
30792994 const ip = &mod.intern_pool;
30802995 switch (ip.indexToKey(ty.toIntern())) {
30812996 .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();
2997 if (struct_type.fieldIsComptime(ip, index)) {
2998 return struct_type.field_inits.get(ip)[index].toValue();
30862999 } else {
3087 return field.ty.onePossibleValue(mod);
3000 return struct_type.field_types.get(ip)[index].toType().onePossibleValue(mod);
30883001 }
30893002 },
30903003 .anon_struct_type => |tuple| {
......@@ -3102,30 +3015,25 @@ pub const Type = struct {
31023015 pub fn structFieldIsComptime(ty: Type, index: usize, mod: *Module) bool {
31033016 const ip = &mod.intern_pool;
31043017 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 },
3018 .struct_type => |struct_type| struct_type.fieldIsComptime(ip, index),
31113019 .anon_struct_type => |anon_struct| anon_struct.values.get(ip)[index] != .none,
31123020 else => unreachable,
31133021 };
31143022 }
31153023
31163024 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);
3025 const ip = &mod.intern_pool;
3026 const struct_type = ip.indexToKey(ty.toIntern()).struct_type;
3027 assert(struct_type.layout == .Packed);
31203028 comptime assert(Type.packed_struct_layout_version == 2);
31213029
31223030 var bit_offset: u16 = undefined;
31233031 var elem_size_bits: u16 = undefined;
31243032 var running_bits: u16 = 0;
3125 for (struct_obj.fields.values(), 0..) |f, i| {
3126 if (!f.ty.hasRuntimeBits(mod)) continue;
3033 for (struct_type.field_types.get(ip), 0..) |field_ty, i| {
3034 if (!field_ty.toType().hasRuntimeBits(mod)) continue;
31273035
3128 const field_bits = @as(u16, @intCast(f.ty.bitSize(mod)));
3036 const field_bits: u16 = @intCast(field_ty.toType().bitSize(mod));
31293037 if (i == field_index) {
31303038 bit_offset = running_bits;
31313039 elem_size_bits = field_bits;
......@@ -3141,68 +3049,19 @@ pub const Type = struct {
31413049 offset: u64,
31423050 };
31433051
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
31863052 /// Supports structs and unions.
31873053 pub fn structFieldOffset(ty: Type, index: usize, mod: *Module) u64 {
31883054 const ip = &mod.intern_pool;
31893055 switch (ip.indexToKey(ty.toIntern())) {
31903056 .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));
3057 assert(struct_type.haveLayout(ip));
3058 assert(struct_type.layout != .Packed);
3059 return struct_type.offsets.get(ip)[index];
32013060 },
32023061
32033062 .anon_struct_type => |tuple| {
32043063 var offset: u64 = 0;
3205 var big_align: u32 = 0;
3064 var big_align: Alignment = .none;
32063065
32073066 for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, field_val, i| {
32083067 if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) {
......@@ -3212,12 +3071,12 @@ pub const Type = struct {
32123071 }
32133072
32143073 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);
3074 big_align = big_align.max(field_align);
3075 offset = field_align.forward(offset);
32173076 if (i == index) return offset;
32183077 offset += field_ty.toType().abiSize(mod);
32193078 }
3220 offset = std.mem.alignForward(u64, offset, @max(big_align, 1));
3079 offset = big_align.max(.@"1").forward(offset);
32213080 return offset;
32223081 },
32233082
......@@ -3226,9 +3085,9 @@ pub const Type = struct {
32263085 return 0;
32273086 const union_obj = ip.loadUnionType(union_type);
32283087 const layout = mod.getUnionLayout(union_obj);
3229 if (layout.tag_align >= layout.payload_align) {
3088 if (layout.tag_align.compare(.gte, layout.payload_align)) {
32303089 // {Tag, Payload}
3231 return std.mem.alignForward(u64, layout.tag_size, layout.payload_align);
3090 return layout.payload_align.forward(layout.tag_size);
32323091 } else {
32333092 // {Payload, Tag}
32343093 return 0;
......@@ -3246,8 +3105,7 @@ pub const Type = struct {
32463105 pub fn declSrcLocOrNull(ty: Type, mod: *Module) ?Module.SrcLoc {
32473106 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
32483107 .struct_type => |struct_type| {
3249 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
3250 return struct_obj.srcLoc(mod);
3108 return mod.declPtr(struct_type.decl.unwrap() orelse return null).srcLoc(mod);
32513109 },
32523110 .union_type => |union_type| {
32533111 return mod.declPtr(union_type.decl).srcLoc(mod);
......@@ -3264,10 +3122,7 @@ pub const Type = struct {
32643122
32653123 pub fn getOwnerDeclOrNull(ty: Type, mod: *Module) ?Module.Decl.Index {
32663124 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 },
3125 .struct_type => |struct_type| struct_type.decl.unwrap(),
32713126 .union_type => |union_type| union_type.decl,
32723127 .opaque_type => |opaque_type| opaque_type.decl,
32733128 .enum_type => |enum_type| enum_type.decl,
......@@ -3280,10 +3135,12 @@ pub const Type = struct {
32803135 }
32813136
32823137 pub fn isTuple(ty: Type, mod: *Module) bool {
3283 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
3138 const ip = &mod.intern_pool;
3139 return switch (ip.indexToKey(ty.toIntern())) {
32843140 .struct_type => |struct_type| {
3285 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false;
3286 return struct_obj.is_tuple;
3141 if (struct_type.layout == .Packed) return false;
3142 if (struct_type.decl == .none) return false;
3143 return struct_type.flagsPtr(ip).is_tuple;
32873144 },
32883145 .anon_struct_type => |anon_struct| anon_struct.names.len == 0,
32893146 else => false,
......@@ -3299,10 +3156,12 @@ pub const Type = struct {
32993156 }
33003157
33013158 pub fn isTupleOrAnonStruct(ty: Type, mod: *Module) bool {
3302 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
3159 const ip = &mod.intern_pool;
3160 return switch (ip.indexToKey(ty.toIntern())) {
33033161 .struct_type => |struct_type| {
3304 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false;
3305 return struct_obj.is_tuple;
3162 if (struct_type.layout == .Packed) return false;
3163 if (struct_type.decl == .none) return false;
3164 return struct_type.flagsPtr(ip).is_tuple;
33063165 },
33073166 .anon_struct_type => true,
33083167 else => false,
......@@ -3391,3 +3250,7 @@ pub const Type = struct {
33913250 /// to packed struct layout to find out all the places in the codebase you need to edit!
33923251 pub const packed_struct_layout_version = 2;
33933252};
3253
3254fn cTypeAlign(target: Target, c_type: Target.CType) Alignment {
3255 return Alignment.fromByteUnits(target.c_type_alignment(c_type));
3256}
src/value.zig+131-115
......@@ -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 };
......@@ -1255,7 +1265,8 @@ pub const Value = struct {
12551265 .int => |int| switch (int.storage) {
12561266 .big_int => |big_int| big_int.orderAgainstScalar(0),
12571267 inline .u64, .i64 => |x| std.math.order(x, 0),
1258 .lazy_align, .lazy_size => |ty| return if (ty.toType().hasRuntimeBitsAdvanced(
1268 .lazy_align => .gt, // alignment is never 0
1269 .lazy_size => |ty| return if (ty.toType().hasRuntimeBitsAdvanced(
12591270 mod,
12601271 false,
12611272 if (opt_sema) |sema| .{ .sema = sema } else .eager,
......@@ -1510,33 +1521,38 @@ pub const Value = struct {
15101521 /// Asserts the value is a single-item pointer to an array, or an array,
15111522 /// or an unknown-length pointer, and returns the element value at the index.
15121523 pub fn elemValue(val: Value, mod: *Module, index: usize) Allocator.Error!Value {
1524 return (try val.maybeElemValue(mod, index)).?;
1525 }
1526
1527 /// Like `elemValue`, but returns `null` instead of asserting on failure.
1528 pub fn maybeElemValue(val: Value, mod: *Module, index: usize) Allocator.Error!?Value {
15131529 return switch (val.ip_index) {
15141530 .none => switch (val.tag()) {
15151531 .bytes => try mod.intValue(Type.u8, val.castTag(.bytes).?.data[index]),
15161532 .repeated => val.castTag(.repeated).?.data,
15171533 .aggregate => val.castTag(.aggregate).?.data[index],
1518 .slice => val.castTag(.slice).?.data.ptr.elemValue(mod, index),
1519 else => unreachable,
1534 .slice => val.castTag(.slice).?.data.ptr.maybeElemValue(mod, index),
1535 else => null,
15201536 },
15211537 else => switch (mod.intern_pool.indexToKey(val.toIntern())) {
15221538 .undef => |ty| (try mod.intern(.{
15231539 .undef = ty.toType().elemType2(mod).toIntern(),
15241540 })).toValue(),
15251541 .ptr => |ptr| switch (ptr.addr) {
1526 .decl => |decl| mod.declPtr(decl).val.elemValue(mod, index),
1542 .decl => |decl| mod.declPtr(decl).val.maybeElemValue(mod, index),
15271543 .mut_decl => |mut_decl| (try mod.declPtr(mut_decl.decl).internValue(mod))
1528 .toValue().elemValue(mod, index),
1529 .int, .eu_payload => unreachable,
1530 .opt_payload => |base| base.toValue().elemValue(mod, index),
1531 .comptime_field => |field_val| field_val.toValue().elemValue(mod, index),
1532 .elem => |elem| elem.base.toValue().elemValue(mod, index + @as(usize, @intCast(elem.index))),
1544 .toValue().maybeElemValue(mod, index),
1545 .int, .eu_payload => null,
1546 .opt_payload => |base| base.toValue().maybeElemValue(mod, index),
1547 .comptime_field => |field_val| field_val.toValue().maybeElemValue(mod, index),
1548 .elem => |elem| elem.base.toValue().maybeElemValue(mod, index + @as(usize, @intCast(elem.index))),
15331549 .field => |field| if (field.base.toValue().pointerDecl(mod)) |decl_index| {
15341550 const base_decl = mod.declPtr(decl_index);
15351551 const field_val = try base_decl.val.fieldValue(mod, @as(usize, @intCast(field.index)));
1536 return field_val.elemValue(mod, index);
1537 } else unreachable,
1552 return field_val.maybeElemValue(mod, index);
1553 } else null,
15381554 },
1539 .opt => |opt| opt.val.toValue().elemValue(mod, index),
1555 .opt => |opt| opt.val.toValue().maybeElemValue(mod, index),
15401556 .aggregate => |aggregate| {
15411557 const len = mod.intern_pool.aggregateTypeLen(aggregate.ty);
15421558 if (index < len) return switch (aggregate.storage) {
......@@ -1550,7 +1566,7 @@ pub const Value = struct {
15501566 assert(index == len);
15511567 return mod.intern_pool.indexToKey(aggregate.ty).array_type.sentinel.toValue();
15521568 },
1553 else => unreachable,
1569 else => null,
15541570 },
15551571 };
15561572 }
......@@ -1875,9 +1891,9 @@ pub const Value = struct {
18751891 },
18761892 inline .u64, .i64 => |x| floatFromIntInner(x, float_ty, mod),
18771893 .lazy_align => |ty| if (opt_sema) |sema| {
1878 return floatFromIntInner((try ty.toType().abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod);
1894 return floatFromIntInner((try ty.toType().abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar.toByteUnits(0), float_ty, mod);
18791895 } else {
1880 return floatFromIntInner(ty.toType().abiAlignment(mod), float_ty, mod);
1896 return floatFromIntInner(ty.toType().abiAlignment(mod).toByteUnits(0), float_ty, mod);
18811897 },
18821898 .lazy_size => |ty| if (opt_sema) |sema| {
18831899 return floatFromIntInner((try ty.toType().abiSizeAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod);
......@@ -1892,11 +1908,11 @@ pub const Value = struct {
18921908 fn floatFromIntInner(x: anytype, dest_ty: Type, mod: *Module) !Value {
18931909 const target = mod.getTarget();
18941910 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)) },
1911 16 => .{ .f16 = @floatFromInt(x) },
1912 32 => .{ .f32 = @floatFromInt(x) },
1913 64 => .{ .f64 = @floatFromInt(x) },
1914 80 => .{ .f80 = @floatFromInt(x) },
1915 128 => .{ .f128 = @floatFromInt(x) },
19001916 else => unreachable,
19011917 };
19021918 return (try mod.intern(.{ .float = .{
test/behavior/align.zig+55
......@@ -619,3 +619,58 @@ test "sub-aligned pointer field access" {
619619 .Little => try expect(x == 0x09080706),
620620 }
621621}
622
623test "alignment of zero-bit types is respected" {
624 if (true) return error.SkipZigTest; // TODO
625
626 const S = struct { arr: [0]usize = .{} };
627
628 comptime assert(@alignOf(void) == 1);
629 comptime assert(@alignOf(u0) == 1);
630 comptime assert(@alignOf([0]usize) == @alignOf(usize));
631 comptime assert(@alignOf(S) == @alignOf(usize));
632
633 var s: S = .{};
634 var v32: void align(32) = {};
635 var x32: u0 align(32) = 0;
636 var s32: S align(32) = .{};
637
638 var zero: usize = 0;
639
640 try expect(@intFromPtr(&s) % @alignOf(usize) == 0);
641 try expect(@intFromPtr(&s.arr) % @alignOf(usize) == 0);
642 try expect(@intFromPtr(s.arr[zero..zero].ptr) % @alignOf(usize) == 0);
643 try expect(@intFromPtr(&v32) % 32 == 0);
644 try expect(@intFromPtr(&x32) % 32 == 0);
645 try expect(@intFromPtr(&s32) % 32 == 0);
646 try expect(@intFromPtr(&s32.arr) % 32 == 0);
647 try expect(@intFromPtr(s32.arr[zero..zero].ptr) % 32 == 0);
648}
649
650test "zero-bit fields in extern struct pad fields appropriately" {
651 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
652 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
653 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
654 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
655 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
656
657 const S = extern struct {
658 x: u8,
659 a: [0]u16 = .{},
660 y: u8,
661 };
662
663 // `a` should give `S` alignment 2, and pad the `arr` field.
664 comptime assert(@alignOf(S) == 2);
665 comptime assert(@sizeOf(S) == 4);
666 comptime assert(@offsetOf(S, "x") == 0);
667 comptime assert(@offsetOf(S, "a") == 2);
668 comptime assert(@offsetOf(S, "y") == 2);
669
670 var s: S = .{ .x = 100, .y = 200 };
671
672 try expect(@intFromPtr(&s) % 2 == 0);
673 try expect(@intFromPtr(&s.y) - @intFromPtr(&s.x) == 2);
674 try expect(@intFromPtr(&s.y) == @intFromPtr(&s.a));
675 try expect(@fieldParentPtr(S, "a", &s.a) == &s);
676}
test/behavior/alignof.zig+7-18
......@@ -18,24 +18,13 @@ test "@alignOf(T) before referencing T" {
1818}
1919
2020test "comparison of @alignOf(T) against zero" {
21 {
22 const T = struct { x: u32 };
23 try expect(!(@alignOf(T) == 0));
24 try expect(@alignOf(T) != 0);
25 try expect(!(@alignOf(T) < 0));
26 try expect(!(@alignOf(T) <= 0));
27 try expect(@alignOf(T) > 0);
28 try expect(@alignOf(T) >= 0);
29 }
30 {
31 const T = struct {};
32 try expect(@alignOf(T) == 0);
33 try expect(!(@alignOf(T) != 0));
34 try expect(!(@alignOf(T) < 0));
35 try expect(@alignOf(T) <= 0);
36 try expect(!(@alignOf(T) > 0));
37 try expect(@alignOf(T) >= 0);
38 }
21 const T = struct { x: u32 };
22 try expect(!(@alignOf(T) == 0));
23 try expect(@alignOf(T) != 0);
24 try expect(!(@alignOf(T) < 0));
25 try expect(!(@alignOf(T) <= 0));
26 try expect(@alignOf(T) > 0);
27 try expect(@alignOf(T) >= 0);
3928}
4029
4130test "correct alignment for elements and slices of aligned array" {
test/behavior/empty_union.zig+1-1
......@@ -37,7 +37,7 @@ test "switch on empty tagged union" {
3737test "empty union" {
3838 const U = union {};
3939 try expect(@sizeOf(U) == 0);
40 try expect(@alignOf(U) == 0);
40 try expect(@alignOf(U) == 1);
4141}
4242
4343test "empty extern union" {