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(...@@ -4758,6 +4758,9 @@ fn structDeclInner(
4758 .known_non_opv = false,4758 .known_non_opv = false,
4759 .known_comptime_only = false,4759 .known_comptime_only = false,
4760 .is_tuple = false,4760 .is_tuple = false,
4761 .any_comptime_fields = false,
4762 .any_default_inits = false,
4763 .any_aligned_fields = false,
4761 });4764 });
4762 return indexToRef(decl_inst);4765 return indexToRef(decl_inst);
4763 }4766 }
...@@ -4881,6 +4884,9 @@ fn structDeclInner(...@@ -4881,6 +4884,9 @@ fn structDeclInner(
48814884
4882 var known_non_opv = false;4885 var known_non_opv = false;
4883 var known_comptime_only = false;4886 var known_comptime_only = false;
4887 var any_comptime_fields = false;
4888 var any_aligned_fields = false;
4889 var any_default_inits = false;
4884 for (container_decl.ast.members) |member_node| {4890 for (container_decl.ast.members) |member_node| {
4885 var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {4891 var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {
4886 .decl => continue,4892 .decl => continue,
...@@ -4910,13 +4916,13 @@ fn structDeclInner(...@@ -4910,13 +4916,13 @@ fn structDeclInner(
4910 const have_value = member.ast.value_expr != 0;4916 const have_value = member.ast.value_expr != 0;
4911 const is_comptime = member.comptime_token != null;4917 const is_comptime = member.comptime_token != null;
49124918
4913 if (is_comptime and layout == .Packed) {4919 if (is_comptime) {
4914 return astgen.failTok(member.comptime_token.?, "packed struct fields cannot be marked comptime", .{});4920 switch (layout) {
4915 } else if (is_comptime and layout == .Extern) {4921 .Packed => return astgen.failTok(member.comptime_token.?, "packed struct fields cannot be marked comptime", .{}),
4916 return astgen.failTok(member.comptime_token.?, "extern struct fields cannot be marked comptime", .{});4922 .Extern => return astgen.failTok(member.comptime_token.?, "extern struct fields cannot be marked comptime", .{}),
4917 }4923 .Auto => any_comptime_fields = true,
49184924 }
4919 if (!is_comptime) {4925 } else {
4920 known_non_opv = known_non_opv or4926 known_non_opv = known_non_opv or
4921 nodeImpliesMoreThanOnePossibleValue(tree, member.ast.type_expr);4927 nodeImpliesMoreThanOnePossibleValue(tree, member.ast.type_expr);
4922 known_comptime_only = known_comptime_only or4928 known_comptime_only = known_comptime_only or
...@@ -4942,6 +4948,7 @@ fn structDeclInner(...@@ -4942,6 +4948,7 @@ fn structDeclInner(
4942 if (layout == .Packed) {4948 if (layout == .Packed) {
4943 try astgen.appendErrorNode(member.ast.align_expr, "unable to override alignment of packed struct fields", .{});4949 try astgen.appendErrorNode(member.ast.align_expr, "unable to override alignment of packed struct fields", .{});
4944 }4950 }
4951 any_aligned_fields = true;
4945 const align_ref = try expr(&block_scope, &namespace.base, coerced_align_ri, member.ast.align_expr);4952 const align_ref = try expr(&block_scope, &namespace.base, coerced_align_ri, member.ast.align_expr);
4946 if (!block_scope.endsWithNoReturn()) {4953 if (!block_scope.endsWithNoReturn()) {
4947 _ = try block_scope.addBreak(.break_inline, decl_inst, align_ref);4954 _ = try block_scope.addBreak(.break_inline, decl_inst, align_ref);
...@@ -4955,6 +4962,7 @@ fn structDeclInner(...@@ -4955,6 +4962,7 @@ fn structDeclInner(
4955 }4962 }
49564963
4957 if (have_value) {4964 if (have_value) {
4965 any_default_inits = true;
4958 const ri: ResultInfo = .{ .rl = if (field_type == .none) .none else .{ .coerced_ty = field_type } };4966 const ri: ResultInfo = .{ .rl = if (field_type == .none) .none else .{ .coerced_ty = field_type } };
49594967
4960 const default_inst = try expr(&block_scope, &namespace.base, ri, member.ast.value_expr);4968 const default_inst = try expr(&block_scope, &namespace.base, ri, member.ast.value_expr);
...@@ -4982,6 +4990,9 @@ fn structDeclInner(...@@ -4982,6 +4990,9 @@ fn structDeclInner(
4982 .known_non_opv = known_non_opv,4990 .known_non_opv = known_non_opv,
4983 .known_comptime_only = known_comptime_only,4991 .known_comptime_only = known_comptime_only,
4984 .is_tuple = is_tuple,4992 .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,
4985 });4996 });
49864997
4987 wip_members.finishBits(bits_per_field);4998 wip_members.finishBits(bits_per_field);
...@@ -12080,6 +12091,9 @@ const GenZir = struct {...@@ -12080,6 +12091,9 @@ const GenZir = struct {
12080 known_non_opv: bool,12091 known_non_opv: bool,
12081 known_comptime_only: bool,12092 known_comptime_only: bool,
12082 is_tuple: bool,12093 is_tuple: bool,
12094 any_comptime_fields: bool,
12095 any_default_inits: bool,
12096 any_aligned_fields: bool,
12083 }) !void {12097 }) !void {
12084 const astgen = gz.astgen;12098 const astgen = gz.astgen;
12085 const gpa = astgen.gpa;12099 const gpa = astgen.gpa;
...@@ -12117,6 +12131,9 @@ const GenZir = struct {...@@ -12117,6 +12131,9 @@ const GenZir = struct {
12117 .is_tuple = args.is_tuple,12131 .is_tuple = args.is_tuple,
12118 .name_strategy = gz.anon_name_strategy,12132 .name_strategy = gz.anon_name_strategy,
12119 .layout = args.layout,12133 .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,
12120 }),12137 }),
12121 .operand = payload_index,12138 .operand = payload_index,
12122 } },12139 } },
src/InternPool.zig+911-195
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1//! All interned objects have both a value and a type.1//! All interned objects have both a value and a type.
2//! This data structure is self-contained, with the following exceptions:2//! This data structure is self-contained, with the following exceptions:
3//! * type_struct via Module.Struct.Index3//! * Module.Namespace has a pointer to Module.File
4//! * type_opaque via Module.Namespace.Index and Module.Decl.Index4//! * Module.Decl has a pointer to Module.CaptureScope
55
6/// Maps `Key` to `Index`. `Key` objects are not stored anywhere; they are6/// Maps `Key` to `Index`. `Key` objects are not stored anywhere; they are
7/// constructed lazily.7/// constructed lazily.
...@@ -39,17 +39,11 @@ allocated_namespaces: std.SegmentedList(Module.Namespace, 0) = .{},...@@ -39,17 +39,11 @@ allocated_namespaces: std.SegmentedList(Module.Namespace, 0) = .{},
39/// Same pattern as with `decls_free_list`.39/// Same pattern as with `decls_free_list`.
40namespaces_free_list: std.ArrayListUnmanaged(Module.Namespace.Index) = .{},40namespaces_free_list: std.ArrayListUnmanaged(Module.Namespace.Index) = .{},
4141
42/// Struct objects are stored in this data structure because:
43/// * They contain pointers such as the field maps.
44/// * They need to be mutated after creation.
45allocated_structs: std.SegmentedList(Module.Struct, 0) = .{},
46/// When a Struct object is freed from `allocated_structs`, it is pushed into this stack.
47structs_free_list: std.ArrayListUnmanaged(Module.Struct.Index) = .{},
48
49/// Some types such as enums, structs, and unions need to store mappings from field names42/// Some types such as enums, structs, and unions need to store mappings from field names
50/// to field index, or value to field index. In such cases, they will store the underlying43/// to field index, or value to field index. In such cases, they will store the underlying
51/// field names and values directly, relying on one of these maps, stored separately,44/// field names and values directly, relying on one of these maps, stored separately,
52/// to provide lookup.45/// to provide lookup.
46/// These are not serialized; it is computed upon deserialization.
53maps: std.ArrayListUnmanaged(FieldMap) = .{},47maps: std.ArrayListUnmanaged(FieldMap) = .{},
5448
55/// Used for finding the index inside `string_bytes`.49/// Used for finding the index inside `string_bytes`.
...@@ -365,11 +359,291 @@ pub const Key = union(enum) {...@@ -365,11 +359,291 @@ pub const Key = union(enum) {
365 namespace: Module.Namespace.Index,359 namespace: Module.Namespace.Index,
366 };360 };
367361
368 pub const StructType = extern struct {362 /// Although packed structs and non-packed structs are encoded differently,
369 /// The `none` tag is used to represent a struct with no fields.363 /// this struct is used for both categories since they share some common
370 index: Module.Struct.OptionalIndex,364 /// functionality.
371 /// May be `none` if the struct has no declarations.365 pub const StructType = struct {
366 extra_index: u32,
367 /// `none` when the struct is `@TypeOf(.{})`.
368 decl: Module.Decl.OptionalIndex,
369 /// `none` when the struct has no declarations.
372 namespace: Module.Namespace.OptionalIndex,370 namespace: Module.Namespace.OptionalIndex,
371 /// Index of the struct_decl ZIR instruction.
372 zir_index: Zir.Inst.Index,
373 layout: std.builtin.Type.ContainerLayout,
374 field_names: NullTerminatedString.Slice,
375 field_types: Index.Slice,
376 field_inits: Index.Slice,
377 field_aligns: Alignment.Slice,
378 runtime_order: RuntimeOrder.Slice,
379 comptime_bits: ComptimeBits,
380 offsets: Offsets,
381 names_map: 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 }
373 };647 };
374648
375 pub const AnonStructType = struct {649 pub const AnonStructType = struct {
...@@ -382,6 +656,17 @@ pub const Key = union(enum) {...@@ -382,6 +656,17 @@ pub const Key = union(enum) {
382 pub fn isTuple(self: AnonStructType) bool {656 pub fn isTuple(self: AnonStructType) bool {
383 return self.names.len == 0;657 return self.names.len == 0;
384 }658 }
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 }
385 };670 };
386671
387 /// Serves two purposes:672 /// Serves two purposes:
...@@ -870,7 +1155,6 @@ pub const Key = union(enum) {...@@ -870,7 +1155,6 @@ pub const Key = union(enum) {
870 .simple_type,1155 .simple_type,
871 .simple_value,1156 .simple_value,
872 .opt,1157 .opt,
873 .struct_type,
874 .undef,1158 .undef,
875 .err,1159 .err,
876 .enum_literal,1160 .enum_literal,
...@@ -893,6 +1177,7 @@ pub const Key = union(enum) {...@@ -893,6 +1177,7 @@ pub const Key = union(enum) {
893 .enum_type,1177 .enum_type,
894 .variable,1178 .variable,
895 .union_type,1179 .union_type,
1180 .struct_type,
896 => |x| Hash.hash(seed, asBytes(&x.decl)),1181 => |x| Hash.hash(seed, asBytes(&x.decl)),
8971182
898 .int => |int| {1183 .int => |int| {
...@@ -969,11 +1254,11 @@ pub const Key = union(enum) {...@@ -969,11 +1254,11 @@ pub const Key = union(enum) {
9691254
970 if (child == .u8_type) {1255 if (child == .u8_type) {
971 switch (aggregate.storage) {1256 switch (aggregate.storage) {
972 .bytes => |bytes| for (bytes[0..@as(usize, @intCast(len))]) |byte| {1257 .bytes => |bytes| for (bytes[0..@intCast(len)]) |byte| {
973 std.hash.autoHash(&hasher, KeyTag.int);1258 std.hash.autoHash(&hasher, KeyTag.int);
974 std.hash.autoHash(&hasher, byte);1259 std.hash.autoHash(&hasher, byte);
975 },1260 },
976 .elems => |elems| for (elems[0..@as(usize, @intCast(len))]) |elem| {1261 .elems => |elems| for (elems[0..@intCast(len)]) |elem| {
977 const elem_key = ip.indexToKey(elem);1262 const elem_key = ip.indexToKey(elem);
978 std.hash.autoHash(&hasher, @as(KeyTag, elem_key));1263 std.hash.autoHash(&hasher, @as(KeyTag, elem_key));
979 switch (elem_key) {1264 switch (elem_key) {
...@@ -1123,10 +1408,6 @@ pub const Key = union(enum) {...@@ -1123,10 +1408,6 @@ pub const Key = union(enum) {
1123 const b_info = b.opt;1408 const b_info = b.opt;
1124 return std.meta.eql(a_info, b_info);1409 return std.meta.eql(a_info, b_info);
1125 },1410 },
1126 .struct_type => |a_info| {
1127 const b_info = b.struct_type;
1128 return std.meta.eql(a_info, b_info);
1129 },
1130 .un => |a_info| {1411 .un => |a_info| {
1131 const b_info = b.un;1412 const b_info = b.un;
1132 return std.meta.eql(a_info, b_info);1413 return std.meta.eql(a_info, b_info);
...@@ -1298,6 +1579,10 @@ pub const Key = union(enum) {...@@ -1298,6 +1579,10 @@ pub const Key = union(enum) {
1298 const b_info = b.union_type;1579 const b_info = b.union_type;
1299 return a_info.decl == b_info.decl;1580 return a_info.decl == b_info.decl;
1300 },1581 },
1582 .struct_type => |a_info| {
1583 const b_info = b.struct_type;
1584 return a_info.decl == b_info.decl;
1585 },
1301 .aggregate => |a_info| {1586 .aggregate => |a_info| {
1302 const b_info = b.aggregate;1587 const b_info = b.aggregate;
1303 if (a_info.ty != b_info.ty) return false;1588 if (a_info.ty != b_info.ty) return false;
...@@ -1433,6 +1718,8 @@ pub const Key = union(enum) {...@@ -1433,6 +1718,8 @@ pub const Key = union(enum) {
1433 }1718 }
1434};1719};
14351720
1721pub const RequiresComptime = enum(u2) { no, yes, unknown, wip };
1722
1436// Unlike `Tag.TypeUnion` which is an encoding, and `Key.UnionType` which is a1723// Unlike `Tag.TypeUnion` which is an encoding, and `Key.UnionType` which is a
1437// minimal hashmap key, this type is a convenience type that contains info1724// minimal hashmap key, this type is a convenience type that contains info
1438// needed by semantic analysis.1725// needed by semantic analysis.
...@@ -1474,8 +1761,6 @@ pub const UnionType = struct {...@@ -1474,8 +1761,6 @@ pub const UnionType = struct {
1474 }1761 }
1475 };1762 };
14761763
1477 pub const RequiresComptime = enum(u2) { no, yes, unknown, wip };
1478
1479 pub const Status = enum(u3) {1764 pub const Status = enum(u3) {
1480 none,1765 none,
1481 field_types_wip,1766 field_types_wip,
...@@ -1814,9 +2099,11 @@ pub const Index = enum(u32) {...@@ -1814,9 +2099,11 @@ pub const Index = enum(u32) {
1814 type_enum_nonexhaustive: DataIsExtraIndexOfEnumExplicit,2099 type_enum_nonexhaustive: DataIsExtraIndexOfEnumExplicit,
1815 simple_type: struct { data: SimpleType },2100 simple_type: struct { data: SimpleType },
1816 type_opaque: struct { data: *Key.OpaqueType },2101 type_opaque: struct { data: *Key.OpaqueType },
1817 type_struct: struct { data: Module.Struct.OptionalIndex },2102 type_struct: struct { data: *Tag.TypeStruct },
1818 type_struct_ns: struct { data: Module.Namespace.Index },2103 type_struct_ns: struct { data: Module.Namespace.Index },
1819 type_struct_anon: DataIsExtraIndexOfTypeStructAnon,2104 type_struct_anon: DataIsExtraIndexOfTypeStructAnon,
2105 type_struct_packed: struct { data: *Tag.TypeStructPacked },
2106 type_struct_packed_inits: struct { data: *Tag.TypeStructPacked },
1820 type_tuple_anon: DataIsExtraIndexOfTypeStructAnon,2107 type_tuple_anon: DataIsExtraIndexOfTypeStructAnon,
1821 type_union: struct { data: *Tag.TypeUnion },2108 type_union: struct { data: *Tag.TypeUnion },
1822 type_function: struct {2109 type_function: struct {
...@@ -2241,17 +2528,22 @@ pub const Tag = enum(u8) {...@@ -2241,17 +2528,22 @@ pub const Tag = enum(u8) {
2241 /// An opaque type.2528 /// An opaque type.
2242 /// data is index of Key.OpaqueType in extra.2529 /// data is index of Key.OpaqueType in extra.
2243 type_opaque,2530 type_opaque,
2244 /// A struct type.2531 /// A non-packed struct type.
2245 /// data is Module.Struct.OptionalIndex2532 /// data is 0 or extra index of `TypeStruct`.
2246 /// The `none` tag is used to represent `@TypeOf(.{})`.2533 /// data == 0 represents `@TypeOf(.{})`.
2247 type_struct,2534 type_struct,
2248 /// A struct type that has only a namespace; no fields, and there is no2535 /// A non-packed struct type that has only a namespace; no fields.
2249 /// Module.Struct object allocated for it.
2250 /// data is Module.Namespace.Index.2536 /// data is Module.Namespace.Index.
2251 type_struct_ns,2537 type_struct_ns,
2252 /// An AnonStructType which stores types, names, and values for fields.2538 /// An AnonStructType which stores types, names, and values for fields.
2253 /// data is extra index of `TypeStructAnon`.2539 /// data is extra index of `TypeStructAnon`.
2254 type_struct_anon,2540 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,
2255 /// An AnonStructType which has only types and values for fields.2547 /// An AnonStructType which has only types and values for fields.
2256 /// data is extra index of `TypeStructAnon`.2548 /// data is extra index of `TypeStructAnon`.
2257 type_tuple_anon,2549 type_tuple_anon,
...@@ -2461,9 +2753,10 @@ pub const Tag = enum(u8) {...@@ -2461,9 +2753,10 @@ pub const Tag = enum(u8) {
2461 .type_enum_nonexhaustive => EnumExplicit,2753 .type_enum_nonexhaustive => EnumExplicit,
2462 .simple_type => unreachable,2754 .simple_type => unreachable,
2463 .type_opaque => OpaqueType,2755 .type_opaque => OpaqueType,
2464 .type_struct => unreachable,2756 .type_struct => TypeStruct,
2465 .type_struct_ns => unreachable,2757 .type_struct_ns => unreachable,
2466 .type_struct_anon => TypeStructAnon,2758 .type_struct_anon => TypeStructAnon,
2759 .type_struct_packed, .type_struct_packed_inits => TypeStructPacked,
2467 .type_tuple_anon => TypeStructAnon,2760 .type_tuple_anon => TypeStructAnon,
2468 .type_union => TypeUnion,2761 .type_union => TypeUnion,
2469 .type_function => TypeFunction,2762 .type_function => TypeFunction,
...@@ -2634,11 +2927,90 @@ pub const Tag = enum(u8) {...@@ -2634,11 +2927,90 @@ pub const Tag = enum(u8) {
2634 any_aligned_fields: bool,2927 any_aligned_fields: bool,
2635 layout: std.builtin.Type.ContainerLayout,2928 layout: std.builtin.Type.ContainerLayout,
2636 status: UnionType.Status,2929 status: UnionType.Status,
2637 requires_comptime: UnionType.RequiresComptime,2930 requires_comptime: RequiresComptime,
2638 assumed_runtime_bits: bool,2931 assumed_runtime_bits: bool,
2639 _: u21 = 0,2932 _: u21 = 0,
2640 };2933 };
2641 };2934 };
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 };
2642};3014};
26433015
2644/// State that is mutable during semantic analysis. This data is not used for3016/// State that is mutable during semantic analysis. This data is not used for
...@@ -2764,20 +3136,26 @@ pub const SimpleValue = enum(u32) {...@@ -2764,20 +3136,26 @@ pub const SimpleValue = enum(u32) {
27643136
2765/// Stored as a power-of-two, with one special value to indicate none.3137/// Stored as a power-of-two, with one special value to indicate none.
2766pub const Alignment = enum(u6) {3138pub const Alignment = enum(u6) {
3139 @"1" = 0,
3140 @"2" = 1,
3141 @"4" = 2,
3142 @"8" = 3,
3143 @"16" = 4,
3144 @"32" = 5,
2767 none = std.math.maxInt(u6),3145 none = std.math.maxInt(u6),
2768 _,3146 _,
27693147
2770 pub fn toByteUnitsOptional(a: Alignment) ?u64 {3148 pub fn toByteUnitsOptional(a: Alignment) ?u64 {
2771 return switch (a) {3149 return switch (a) {
2772 .none => null,3150 .none => null,
2773 _ => @as(u64, 1) << @intFromEnum(a),3151 else => @as(u64, 1) << @intFromEnum(a),
2774 };3152 };
2775 }3153 }
27763154
2777 pub fn toByteUnits(a: Alignment, default: u64) u64 {3155 pub fn toByteUnits(a: Alignment, default: u64) u64 {
2778 return switch (a) {3156 return switch (a) {
2779 .none => default,3157 .none => default,
2780 _ => @as(u64, 1) << @intFromEnum(a),3158 else => @as(u64, 1) << @intFromEnum(a),
2781 };3159 };
2782 }3160 }
27833161
...@@ -2792,16 +3170,95 @@ pub const Alignment = enum(u6) {...@@ -2792,16 +3170,95 @@ pub const Alignment = enum(u6) {
2792 return fromByteUnits(n);3170 return fromByteUnits(n);
2793 }3171 }
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
2795 pub fn order(lhs: Alignment, rhs: Alignment) std.math.Order {3186 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);
2797 return std.math.order(@intFromEnum(lhs), @intFromEnum(rhs));3189 return std.math.order(@intFromEnum(lhs), @intFromEnum(rhs));
2798 }3190 }
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
2800 /// An array of `Alignment` objects existing within the `extra` array.3256 /// An array of `Alignment` objects existing within the `extra` array.
2801 /// This type exists to provide a struct with lifetime that is3257 /// This type exists to provide a struct with lifetime that is
2802 /// not invalidated when items are added to the `InternPool`.3258 /// not invalidated when items are added to the `InternPool`.
2803 pub const Slice = struct {3259 pub const Slice = struct {
2804 start: u32,3260 start: u32,
3261 /// This is the number of alignment values, not the number of u32 elements.
2805 len: u32,3262 len: u32,
28063263
2807 pub fn get(slice: Slice, ip: *const InternPool) []Alignment {3264 pub fn get(slice: Slice, ip: *const InternPool) []Alignment {
...@@ -2811,6 +3268,23 @@ pub const Alignment = enum(u6) {...@@ -2811,6 +3268,23 @@ pub const Alignment = enum(u6) {
2811 return @ptrCast(bytes[0..slice.len]);3268 return @ptrCast(bytes[0..slice.len]);
2812 }3269 }
2813 };3270 };
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 }
2814};3288};
28153289
2816/// Used for non-sentineled arrays that have length fitting in u32, as well as3290/// 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 {...@@ -3065,9 +3539,6 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
3065 ip.limbs.deinit(gpa);3539 ip.limbs.deinit(gpa);
3066 ip.string_bytes.deinit(gpa);3540 ip.string_bytes.deinit(gpa);
30673541
3068 ip.structs_free_list.deinit(gpa);
3069 ip.allocated_structs.deinit(gpa);
3070
3071 ip.decls_free_list.deinit(gpa);3542 ip.decls_free_list.deinit(gpa);
3072 ip.allocated_decls.deinit(gpa);3543 ip.allocated_decls.deinit(gpa);
30733544
...@@ -3149,24 +3620,43 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -3149,24 +3620,43 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
3149 },3620 },
31503621
3151 .type_opaque => .{ .opaque_type = ip.extraData(Key.OpaqueType, data) },3622 .type_opaque => .{ .opaque_type = ip.extraData(Key.OpaqueType, data) },
3152 .type_struct => {3623
3153 const struct_index: Module.Struct.OptionalIndex = @enumFromInt(data);3624 .type_struct => .{ .struct_type = if (data == 0) .{
3154 const namespace = if (struct_index.unwrap()) |i|3625 .extra_index = 0,
3155 ip.structPtrConst(i).namespace.toOptional()3626 .namespace = .none,
3156 else3627 .decl = .none,
3157 .none;3628 .zir_index = @as(u32, undefined),
3158 return .{ .struct_type = .{3629 .layout = .Auto,
3159 .index = struct_index,3630 .field_names = .{ .start = 0, .len = 0 },
3160 .namespace = namespace,3631 .field_types = .{ .start = 0, .len = 0 },
3161 } };3632 .field_inits = .{ .start = 0, .len = 0 },
3162 },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
3163 .type_struct_ns => .{ .struct_type = .{3640 .type_struct_ns => .{ .struct_type = .{
3164 .index = .none,3641 .extra_index = 0,
3165 .namespace = @as(Module.Namespace.Index, @enumFromInt(data)).toOptional(),3642 .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,
3166 } },3654 } },
31673655
3168 .type_struct_anon => .{ .anon_struct_type = extraTypeStructAnon(ip, data) },3656 .type_struct_anon => .{ .anon_struct_type = extraTypeStructAnon(ip, data) },
3169 .type_tuple_anon => .{ .anon_struct_type = extraTypeTupleAnon(ip, data) },3657 .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) },
3170 .type_union => .{ .union_type = extraUnionType(ip, data) },3660 .type_union => .{ .union_type = extraUnionType(ip, data) },
31713661
3172 .type_enum_auto => {3662 .type_enum_auto => {
...@@ -3441,7 +3931,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -3441,7 +3931,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
3441 .func_decl => .{ .func = ip.extraFuncDecl(data) },3931 .func_decl => .{ .func = ip.extraFuncDecl(data) },
3442 .func_coerced => .{ .func = ip.extraFuncCoerced(data) },3932 .func_coerced => .{ .func = ip.extraFuncCoerced(data) },
3443 .only_possible_value => {3933 .only_possible_value => {
3444 const ty = @as(Index, @enumFromInt(data));3934 const ty: Index = @enumFromInt(data);
3445 const ty_item = ip.items.get(@intFromEnum(ty));3935 const ty_item = ip.items.get(@intFromEnum(ty));
3446 return switch (ty_item.tag) {3936 return switch (ty_item.tag) {
3447 .type_array_big => {3937 .type_array_big => {
...@@ -3454,20 +3944,33 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -3454,20 +3944,33 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
3454 .storage = .{ .elems = sentinel[0..@intFromBool(sentinel[0] != .none)] },3944 .storage = .{ .elems = sentinel[0..@intFromBool(sentinel[0] != .none)] },
3455 } };3945 } };
3456 },3946 },
3457 .type_array_small, .type_vector => .{ .aggregate = .{3947 .type_array_small,
3458 .ty = ty,3948 .type_vector,
3459 .storage = .{ .elems = &.{} },3949 .type_struct_ns,
3460 } },3950 .type_struct_packed,
3461 // TODO: migrate structs to properly use the InternPool rather3951 => .{ .aggregate = .{
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 = .{
3467 .ty = ty,3952 .ty = ty,
3468 .storage = .{ .elems = &.{} },3953 .storage = .{ .elems = &.{} },
3469 } },3954 } },
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
3471 // There is only one possible value precisely due to the3974 // There is only one possible value precisely due to the
3472 // fact that this values slice is fully populated!3975 // fact that this values slice is fully populated!
3473 .type_struct_anon, .type_tuple_anon => {3976 .type_struct_anon, .type_tuple_anon => {
...@@ -3476,7 +3979,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -3476,7 +3979,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
3476 const values = ip.extra.items[type_struct_anon.end + fields_len ..][0..fields_len];3979 const values = ip.extra.items[type_struct_anon.end + fields_len ..][0..fields_len];
3477 return .{ .aggregate = .{3980 return .{ .aggregate = .{
3478 .ty = ty,3981 .ty = ty,
3479 .storage = .{ .elems = @as([]const Index, @ptrCast(values)) },3982 .storage = .{ .elems = @ptrCast(values) },
3480 } };3983 } };
3481 },3984 },
34823985
...@@ -3490,7 +3993,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -3490,7 +3993,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
3490 },3993 },
3491 .bytes => {3994 .bytes => {
3492 const extra = ip.extraData(Bytes, data);3995 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));
3494 return .{ .aggregate = .{3997 return .{ .aggregate = .{
3495 .ty = extra.ty,3998 .ty = extra.ty,
3496 .storage = .{ .bytes = ip.string_bytes.items[@intFromEnum(extra.bytes)..][0..len] },3999 .storage = .{ .bytes = ip.string_bytes.items[@intFromEnum(extra.bytes)..][0..len] },
...@@ -3498,8 +4001,8 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -3498,8 +4001,8 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
3498 },4001 },
3499 .aggregate => {4002 .aggregate => {
3500 const extra = ip.extraDataTrail(Tag.Aggregate, data);4003 const extra = ip.extraDataTrail(Tag.Aggregate, data);
3501 const len = @as(u32, @intCast(ip.aggregateTypeLenIncludingSentinel(extra.data.ty)));4004 const len: u32 = @intCast(ip.aggregateTypeLenIncludingSentinel(extra.data.ty));
3502 const fields = @as([]const Index, @ptrCast(ip.extra.items[extra.end..][0..len]));4005 const fields: []const Index = @ptrCast(ip.extra.items[extra.end..][0..len]);
3503 return .{ .aggregate = .{4006 return .{ .aggregate = .{
3504 .ty = extra.data.ty,4007 .ty = extra.data.ty,
3505 .storage = .{ .elems = fields },4008 .storage = .{ .elems = fields },
...@@ -3603,6 +4106,109 @@ fn extraTypeTupleAnon(ip: *const InternPool, extra_index: u32) Key.AnonStructTyp...@@ -3603,6 +4106,109 @@ fn extraTypeTupleAnon(ip: *const InternPool, extra_index: u32) Key.AnonStructTyp
3603 };4106 };
3604}4107}
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
3606fn extraFuncType(ip: *const InternPool, extra_index: u32) Key.FuncType {4212fn extraFuncType(ip: *const InternPool, extra_index: u32) Key.FuncType {
3607 const type_function = ip.extraDataTrail(Tag.TypeFunction, extra_index);4213 const type_function = ip.extraDataTrail(Tag.TypeFunction, extra_index);
3608 var index: usize = type_function.end;4214 var index: usize = type_function.end;
...@@ -3831,8 +4437,9 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -3831,8 +4437,9 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
3831 .error_set_type => |error_set_type| {4437 .error_set_type => |error_set_type| {
3832 assert(error_set_type.names_map == .none);4438 assert(error_set_type.names_map == .none);
3833 assert(std.sort.isSorted(NullTerminatedString, error_set_type.names.get(ip), {}, NullTerminatedString.indexLessThan));4439 assert(std.sort.isSorted(NullTerminatedString, error_set_type.names.get(ip), {}, NullTerminatedString.indexLessThan));
3834 const names_map = try ip.addMap(gpa);4440 const names = error_set_type.names.get(ip);
3835 try addStringsToMap(ip, gpa, names_map, error_set_type.names.get(ip));4441 const names_map = try ip.addMap(gpa, names.len);
4442 addStringsToMap(ip, names_map, names);
3836 const names_len = error_set_type.names.len;4443 const names_len = error_set_type.names.len;
3837 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.ErrorSet).Struct.fields.len + names_len);4444 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.ErrorSet).Struct.fields.len + names_len);
3838 ip.items.appendAssumeCapacity(.{4445 ip.items.appendAssumeCapacity(.{
...@@ -3877,21 +4484,8 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -3877,21 +4484,8 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
3877 });4484 });
3878 },4485 },
38794486
3880 .struct_type => |struct_type| {4487 .struct_type => unreachable, // use getStructType() instead
3881 ip.items.appendAssumeCapacity(if (struct_type.index.unwrap()) |i| .{
3882 .tag = .type_struct,
3883 .data = @intFromEnum(i),
3884 } else if (struct_type.namespace.unwrap()) |i| .{
3885 .tag = .type_struct_ns,
3886 .data = @intFromEnum(i),
3887 } else .{
3888 .tag = .type_struct,
3889 .data = @intFromEnum(Module.Struct.OptionalIndex.none),
3890 });
3891 },
3892
3893 .anon_struct_type => unreachable, // use getAnonStructType() instead4488 .anon_struct_type => unreachable, // use getAnonStructType() instead
3894
3895 .union_type => unreachable, // use getUnionType() instead4489 .union_type => unreachable, // use getUnionType() instead
38964490
3897 .opaque_type => |opaque_type| {4491 .opaque_type => |opaque_type| {
...@@ -3994,7 +4588,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -3994,7 +4588,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
3994 },4588 },
3995 .struct_type => |struct_type| {4589 .struct_type => |struct_type| {
3996 assert(ptr.addr == .field);4590 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);
3998 },4592 },
3999 .union_type => |union_key| {4593 .union_type => |union_key| {
4000 const union_type = ip.loadUnionType(union_key);4594 const union_type = ip.loadUnionType(union_key);
...@@ -4388,12 +4982,9 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -4388,12 +4982,9 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
4388 assert(ip.typeOf(elem) == child);4982 assert(ip.typeOf(elem) == child);
4389 }4983 }
4390 },4984 },
4391 .struct_type => |struct_type| {4985 .struct_type => |t| {
4392 for (4986 for (aggregate.storage.values(), t.field_types.get(ip)) |elem, field_ty| {
4393 aggregate.storage.values(),4987 assert(ip.typeOf(elem) == field_ty);
4394 ip.structPtrUnwrapConst(struct_type.index).?.fields.values(),
4395 ) |elem, field| {
4396 assert(ip.typeOf(elem) == field.ty.toIntern());
4397 }4988 }
4398 },4989 },
4399 .anon_struct_type => |anon_struct_type| {4990 .anon_struct_type => |anon_struct_type| {
...@@ -4635,6 +5226,138 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, ini: UnionTypeInit) Allocat...@@ -4635,6 +5226,138 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, ini: UnionTypeInit) Allocat
4635 return @enumFromInt(ip.items.len - 1);5226 return @enumFromInt(ip.items.len - 1);
4636}5227}
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
4638pub const AnonStructTypeInit = struct {5361pub const AnonStructTypeInit = struct {
4639 types: []const Index,5362 types: []const Index,
4640 /// This may be empty, indicating this is a tuple.5363 /// This may be empty, indicating this is a tuple.
...@@ -4997,10 +5720,11 @@ pub fn getErrorSetType(...@@ -4997,10 +5720,11 @@ pub fn getErrorSetType(
4997 });5720 });
4998 errdefer ip.items.len -= 1;5721 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);
5001 errdefer _ = ip.maps.pop();5725 errdefer _ = ip.maps.pop();
50025726
5003 try addStringsToMap(ip, gpa, names_map, names);5727 addStringsToMap(ip, names_map, names);
50045728
5005 return @enumFromInt(ip.items.len - 1);5729 return @enumFromInt(ip.items.len - 1);
5006}5730}
...@@ -5299,19 +6023,9 @@ pub const IncompleteEnumType = struct {...@@ -5299,19 +6023,9 @@ pub const IncompleteEnumType = struct {
5299 pub fn addFieldName(6023 pub fn addFieldName(
5300 self: @This(),6024 self: @This(),
5301 ip: *InternPool,6025 ip: *InternPool,
5302 gpa: Allocator,
5303 name: NullTerminatedString,6026 name: NullTerminatedString,
5304 ) Allocator.Error!?u32 {6027 ) ?u32 {
5305 const map = &ip.maps.items[@intFromEnum(self.names_map)];6028 return ip.addFieldName(self.names_map, self.names_start, name);
5306 const field_index = map.count();
5307 const strings = ip.extra.items[self.names_start..][0..field_index];
5308 const adapter: NullTerminatedString.Adapter = .{
5309 .strings = @as([]const NullTerminatedString, @ptrCast(strings)),
5310 };
5311 const gop = try map.getOrPutAdapted(gpa, name, adapter);
5312 if (gop.found_existing) return @intCast(gop.index);
5313 ip.extra.items[self.names_start + field_index] = @intFromEnum(name);
5314 return null;
5315 }6029 }
53166030
5317 /// Returns the already-existing field with the same value, if any.6031 /// Returns the already-existing field with the same value, if any.
...@@ -5319,17 +6033,14 @@ pub const IncompleteEnumType = struct {...@@ -5319,17 +6033,14 @@ pub const IncompleteEnumType = struct {
5319 pub fn addFieldValue(6033 pub fn addFieldValue(
5320 self: @This(),6034 self: @This(),
5321 ip: *InternPool,6035 ip: *InternPool,
5322 gpa: Allocator,
5323 value: Index,6036 value: Index,
5324 ) Allocator.Error!?u32 {6037 ) ?u32 {
5325 assert(ip.typeOf(value) == @as(Index, @enumFromInt(ip.extra.items[self.tag_ty_index])));6038 assert(ip.typeOf(value) == @as(Index, @enumFromInt(ip.extra.items[self.tag_ty_index])));
5326 const map = &ip.maps.items[@intFromEnum(self.values_map.unwrap().?)];6039 const map = &ip.maps.items[@intFromEnum(self.values_map.unwrap().?)];
5327 const field_index = map.count();6040 const field_index = map.count();
5328 const indexes = ip.extra.items[self.values_start..][0..field_index];6041 const indexes = ip.extra.items[self.values_start..][0..field_index];
5329 const adapter: Index.Adapter = .{6042 const adapter: Index.Adapter = .{ .indexes = @ptrCast(indexes) };
5330 .indexes = @as([]const Index, @ptrCast(indexes)),6043 const gop = map.getOrPutAssumeCapacityAdapted(value, adapter);
5331 };
5332 const gop = try map.getOrPutAdapted(gpa, value, adapter);
5333 if (gop.found_existing) return @intCast(gop.index);6044 if (gop.found_existing) return @intCast(gop.index);
5334 ip.extra.items[self.values_start + field_index] = @intFromEnum(value);6045 ip.extra.items[self.values_start + field_index] = @intFromEnum(value);
5335 return null;6046 return null;
...@@ -5370,7 +6081,7 @@ fn getIncompleteEnumAuto(...@@ -5370,7 +6081,7 @@ fn getIncompleteEnumAuto(
5370 const gop = try ip.map.getOrPutAdapted(gpa, enum_type.toKey(), adapter);6081 const gop = try ip.map.getOrPutAdapted(gpa, enum_type.toKey(), adapter);
5371 assert(!gop.found_existing);6082 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
5375 const extra_fields_len: u32 = @typeInfo(EnumAuto).Struct.fields.len;6086 const extra_fields_len: u32 = @typeInfo(EnumAuto).Struct.fields.len;
5376 try ip.extra.ensureUnusedCapacity(gpa, extra_fields_len + enum_type.fields_len);6087 try ip.extra.ensureUnusedCapacity(gpa, extra_fields_len + enum_type.fields_len);
...@@ -5390,7 +6101,7 @@ fn getIncompleteEnumAuto(...@@ -5390,7 +6101,7 @@ fn getIncompleteEnumAuto(
5390 });6101 });
5391 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), enum_type.fields_len);6102 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), enum_type.fields_len);
5392 return .{6103 return .{
5393 .index = @as(Index, @enumFromInt(ip.items.len - 1)),6104 .index = @enumFromInt(ip.items.len - 1),
5394 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?,6105 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?,
5395 .names_map = names_map,6106 .names_map = names_map,
5396 .names_start = extra_index + extra_fields_len,6107 .names_start = extra_index + extra_fields_len,
...@@ -5412,9 +6123,9 @@ fn getIncompleteEnumExplicit(...@@ -5412,9 +6123,9 @@ fn getIncompleteEnumExplicit(
5412 const gop = try ip.map.getOrPutAdapted(gpa, enum_type.toKey(), adapter);6123 const gop = try ip.map.getOrPutAdapted(gpa, enum_type.toKey(), adapter);
5413 assert(!gop.found_existing);6124 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);
5416 const values_map: OptionalMapIndex = if (!enum_type.has_values) .none else m: {6127 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);
5418 break :m values_map.toOptional();6129 break :m values_map.toOptional();
5419 };6130 };
54206131
...@@ -5441,7 +6152,7 @@ fn getIncompleteEnumExplicit(...@@ -5441,7 +6152,7 @@ fn getIncompleteEnumExplicit(
5441 // This is both fields and values (if present).6152 // This is both fields and values (if present).
5442 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), reserved_len);6153 ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), reserved_len);
5443 return .{6154 return .{
5444 .index = @as(Index, @enumFromInt(ip.items.len - 1)),6155 .index = @enumFromInt(ip.items.len - 1),
5445 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumExplicit, "int_tag_type").?,6156 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumExplicit, "int_tag_type").?,
5446 .names_map = names_map,6157 .names_map = names_map,
5447 .names_start = extra_index + extra_fields_len,6158 .names_start = extra_index + extra_fields_len,
...@@ -5484,8 +6195,8 @@ pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Erro...@@ -5484,8 +6195,8 @@ pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Erro
54846195
5485 switch (ini.tag_mode) {6196 switch (ini.tag_mode) {
5486 .auto => {6197 .auto => {
5487 const names_map = try ip.addMap(gpa);6198 const names_map = try ip.addMap(gpa, ini.names.len);
5488 try addStringsToMap(ip, gpa, names_map, ini.names);6199 addStringsToMap(ip, names_map, ini.names);
54896200
5490 const fields_len: u32 = @intCast(ini.names.len);6201 const fields_len: u32 = @intCast(ini.names.len);
5491 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumAuto).Struct.fields.len +6202 try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumAuto).Struct.fields.len +
...@@ -5514,12 +6225,12 @@ pub fn finishGetEnum(...@@ -5514,12 +6225,12 @@ pub fn finishGetEnum(
5514 ini: GetEnumInit,6225 ini: GetEnumInit,
5515 tag: Tag,6226 tag: Tag,
5516) Allocator.Error!Index {6227) Allocator.Error!Index {
5517 const names_map = try ip.addMap(gpa);6228 const names_map = try ip.addMap(gpa, ini.names.len);
5518 try addStringsToMap(ip, gpa, names_map, ini.names);6229 addStringsToMap(ip, names_map, ini.names);
55196230
5520 const values_map: OptionalMapIndex = if (ini.values.len == 0) .none else m: {6231 const values_map: OptionalMapIndex = if (ini.values.len == 0) .none else m: {
5521 const values_map = try ip.addMap(gpa);6232 const values_map = try ip.addMap(gpa, ini.values.len);
5522 try addIndexesToMap(ip, gpa, values_map, ini.values);6233 addIndexesToMap(ip, values_map, ini.values);
5523 break :m values_map.toOptional();6234 break :m values_map.toOptional();
5524 };6235 };
5525 const fields_len: u32 = @intCast(ini.names.len);6236 const fields_len: u32 = @intCast(ini.names.len);
...@@ -5553,35 +6264,35 @@ pub fn getAssumeExists(ip: *const InternPool, key: Key) Index {...@@ -5553,35 +6264,35 @@ pub fn getAssumeExists(ip: *const InternPool, key: Key) Index {
55536264
5554fn addStringsToMap(6265fn addStringsToMap(
5555 ip: *InternPool,6266 ip: *InternPool,
5556 gpa: Allocator,
5557 map_index: MapIndex,6267 map_index: MapIndex,
5558 strings: []const NullTerminatedString,6268 strings: []const NullTerminatedString,
5559) Allocator.Error!void {6269) void {
5560 const map = &ip.maps.items[@intFromEnum(map_index)];6270 const map = &ip.maps.items[@intFromEnum(map_index)];
5561 const adapter: NullTerminatedString.Adapter = .{ .strings = strings };6271 const adapter: NullTerminatedString.Adapter = .{ .strings = strings };
5562 for (strings) |string| {6272 for (strings) |string| {
5563 const gop = try map.getOrPutAdapted(gpa, string, adapter);6273 const gop = map.getOrPutAssumeCapacityAdapted(string, adapter);
5564 assert(!gop.found_existing);6274 assert(!gop.found_existing);
5565 }6275 }
5566}6276}
55676277
5568fn addIndexesToMap(6278fn addIndexesToMap(
5569 ip: *InternPool,6279 ip: *InternPool,
5570 gpa: Allocator,
5571 map_index: MapIndex,6280 map_index: MapIndex,
5572 indexes: []const Index,6281 indexes: []const Index,
5573) Allocator.Error!void {6282) void {
5574 const map = &ip.maps.items[@intFromEnum(map_index)];6283 const map = &ip.maps.items[@intFromEnum(map_index)];
5575 const adapter: Index.Adapter = .{ .indexes = indexes };6284 const adapter: Index.Adapter = .{ .indexes = indexes };
5576 for (indexes) |index| {6285 for (indexes) |index| {
5577 const gop = try map.getOrPutAdapted(gpa, index, adapter);6286 const gop = map.getOrPutAssumeCapacityAdapted(index, adapter);
5578 assert(!gop.found_existing);6287 assert(!gop.found_existing);
5579 }6288 }
5580}6289}
55816290
5582fn addMap(ip: *InternPool, gpa: Allocator) Allocator.Error!MapIndex {6291fn addMap(ip: *InternPool, gpa: Allocator, cap: usize) Allocator.Error!MapIndex {
5583 const ptr = try ip.maps.addOne(gpa);6292 const ptr = try ip.maps.addOne(gpa);
6293 errdefer _ = ip.maps.pop();
5584 ptr.* = .{};6294 ptr.* = .{};
6295 try ptr.ensureTotalCapacity(gpa, cap);
5585 return @enumFromInt(ip.maps.items.len - 1);6296 return @enumFromInt(ip.maps.items.len - 1);
5586}6297}
55876298
...@@ -5632,8 +6343,9 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {...@@ -5632,8 +6343,9 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {
5632 Tag.TypePointer.Flags,6343 Tag.TypePointer.Flags,
5633 Tag.TypeFunction.Flags,6344 Tag.TypeFunction.Flags,
5634 Tag.TypePointer.PackedOffset,6345 Tag.TypePointer.PackedOffset,
5635 Tag.Variable.Flags,
5636 Tag.TypeUnion.Flags,6346 Tag.TypeUnion.Flags,
6347 Tag.TypeStruct.Flags,
6348 Tag.Variable.Flags,
5637 => @bitCast(@field(extra, field.name)),6349 => @bitCast(@field(extra, field.name)),
56386350
5639 else => @compileError("bad field type: " ++ @typeName(field.type)),6351 else => @compileError("bad field type: " ++ @typeName(field.type)),
...@@ -5705,6 +6417,7 @@ fn extraDataTrail(ip: *const InternPool, comptime T: type, index: usize) struct...@@ -5705,6 +6417,7 @@ fn extraDataTrail(ip: *const InternPool, comptime T: type, index: usize) struct
5705 Tag.TypeFunction.Flags,6417 Tag.TypeFunction.Flags,
5706 Tag.TypePointer.PackedOffset,6418 Tag.TypePointer.PackedOffset,
5707 Tag.TypeUnion.Flags,6419 Tag.TypeUnion.Flags,
6420 Tag.TypeStruct.Flags,
5708 Tag.Variable.Flags,6421 Tag.Variable.Flags,
5709 FuncAnalysis,6422 FuncAnalysis,
5710 => @bitCast(int32),6423 => @bitCast(int32),
...@@ -6093,8 +6806,7 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al...@@ -6093,8 +6806,7 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
6093 const new_elem_ty = switch (ip.indexToKey(new_ty)) {6806 const new_elem_ty = switch (ip.indexToKey(new_ty)) {
6094 inline .array_type, .vector_type => |seq_type| seq_type.child,6807 inline .array_type, .vector_type => |seq_type| seq_type.child,
6095 .anon_struct_type => |anon_struct_type| anon_struct_type.types.get(ip)[i],6808 .anon_struct_type => |anon_struct_type| anon_struct_type.types.get(ip)[i],
6096 .struct_type => |struct_type| ip.structPtr(struct_type.index.unwrap().?)6809 .struct_type => |struct_type| struct_type.field_types.get(ip)[i],
6097 .fields.values()[i].ty.toIntern(),
6098 else => unreachable,6810 else => unreachable,
6099 };6811 };
6100 elem.* = try ip.getCoerced(gpa, elem.*, new_elem_ty);6812 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...@@ -6206,25 +6918,6 @@ pub fn getCoercedInts(ip: *InternPool, gpa: Allocator, int: Key.Int, new_ty: Ind
6206 } });6918 } });
6207}6919}
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
6228pub fn indexToFuncType(ip: *const InternPool, val: Index) ?Key.FuncType {6921pub fn indexToFuncType(ip: *const InternPool, val: Index) ?Key.FuncType {
6229 assert(val != .none);6922 assert(val != .none);
6230 const tags = ip.items.items(.tag);6923 const tags = ip.items.items(.tag);
...@@ -6337,20 +7030,16 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {...@@ -6337,20 +7030,16 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
6337 const items_size = (1 + 4) * ip.items.len;7030 const items_size = (1 + 4) * ip.items.len;
6338 const extra_size = 4 * ip.extra.items.len;7031 const extra_size = 4 * ip.extra.items.len;
6339 const limbs_size = 8 * ip.limbs.items.len;7032 const limbs_size = 8 * ip.limbs.items.len;
6340 // TODO: fields size is not taken into account
6341 const structs_size = ip.allocated_structs.len *
6342 (@sizeOf(Module.Struct) + @sizeOf(Module.Namespace));
6343 const decls_size = ip.allocated_decls.len * @sizeOf(Module.Decl);7033 const decls_size = ip.allocated_decls.len * @sizeOf(Module.Decl);
63447034
6345 // TODO: map overhead size is not taken into account7035 // 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
6348 std.debug.print(7038 std.debug.print(
6349 \\InternPool size: {d} bytes7039 \\InternPool size: {d} bytes
6350 \\ {d} items: {d} bytes7040 \\ {d} items: {d} bytes
6351 \\ {d} extra: {d} bytes7041 \\ {d} extra: {d} bytes
6352 \\ {d} limbs: {d} bytes7042 \\ {d} limbs: {d} bytes
6353 \\ {d} structs: {d} bytes
6354 \\ {d} decls: {d} bytes7043 \\ {d} decls: {d} bytes
6355 \\7044 \\
6356 , .{7045 , .{
...@@ -6361,8 +7050,6 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {...@@ -6361,8 +7050,6 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
6361 extra_size,7050 extra_size,
6362 ip.limbs.items.len,7051 ip.limbs.items.len,
6363 limbs_size,7052 limbs_size,
6364 ip.allocated_structs.len,
6365 structs_size,
6366 ip.allocated_decls.len,7053 ip.allocated_decls.len,
6367 decls_size,7054 decls_size,
6368 });7055 });
...@@ -6399,17 +7086,40 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {...@@ -6399,17 +7086,40 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
6399 .type_enum_auto => @sizeOf(EnumAuto),7086 .type_enum_auto => @sizeOf(EnumAuto),
6400 .type_opaque => @sizeOf(Key.OpaqueType),7087 .type_opaque => @sizeOf(Key.OpaqueType),
6401 .type_struct => b: {7088 .type_struct => b: {
6402 const struct_index = @as(Module.Struct.Index, @enumFromInt(data));7089 const info = ip.extraData(Tag.TypeStruct, data);
6403 const struct_obj = ip.structPtrConst(struct_index);7090 var ints: usize = @typeInfo(Tag.TypeStruct).Struct.fields.len;
6404 break :b @sizeOf(Module.Struct) +7091 ints += info.fields_len; // types
6405 @sizeOf(Module.Namespace) +7092 if (!info.flags.is_tuple) {
6406 (struct_obj.fields.count() * @sizeOf(Module.Struct.Field));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;
6407 },7107 },
6408 .type_struct_ns => @sizeOf(Module.Namespace),7108 .type_struct_ns => @sizeOf(Module.Namespace),
6409 .type_struct_anon => b: {7109 .type_struct_anon => b: {
6410 const info = ip.extraData(TypeStructAnon, data);7110 const info = ip.extraData(TypeStructAnon, data);
6411 break :b @sizeOf(TypeStructAnon) + (@sizeOf(u32) * 3 * info.fields_len);7111 break :b @sizeOf(TypeStructAnon) + (@sizeOf(u32) * 3 * info.fields_len);
6412 },7112 },
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 },
6413 .type_tuple_anon => b: {7123 .type_tuple_anon => b: {
6414 const info = ip.extraData(TypeStructAnon, data);7124 const info = ip.extraData(TypeStructAnon, data);
6415 break :b @sizeOf(TypeStructAnon) + (@sizeOf(u32) * 2 * info.fields_len);7125 break :b @sizeOf(TypeStructAnon) + (@sizeOf(u32) * 2 * info.fields_len);
...@@ -6562,6 +7272,8 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {...@@ -6562,6 +7272,8 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
6562 .type_struct,7272 .type_struct,
6563 .type_struct_ns,7273 .type_struct_ns,
6564 .type_struct_anon,7274 .type_struct_anon,
7275 .type_struct_packed,
7276 .type_struct_packed_inits,
6565 .type_tuple_anon,7277 .type_tuple_anon,
6566 .type_union,7278 .type_union,
6567 .type_function,7279 .type_function,
...@@ -6677,18 +7389,6 @@ pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator)...@@ -6677,18 +7389,6 @@ pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator)
6677 try bw.flush();7389 try bw.flush();
6678}7390}
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
6692pub fn declPtr(ip: *InternPool, index: Module.Decl.Index) *Module.Decl {7392pub fn declPtr(ip: *InternPool, index: Module.Decl.Index) *Module.Decl {
6693 return ip.allocated_decls.at(@intFromEnum(index));7393 return ip.allocated_decls.at(@intFromEnum(index));
6694}7394}
...@@ -6701,28 +7401,6 @@ pub fn namespacePtr(ip: *InternPool, index: Module.Namespace.Index) *Module.Name...@@ -6701,28 +7401,6 @@ pub fn namespacePtr(ip: *InternPool, index: Module.Namespace.Index) *Module.Name
6701 return ip.allocated_namespaces.at(@intFromEnum(index));7401 return ip.allocated_namespaces.at(@intFromEnum(index));
6702}7402}
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
6726pub fn createDecl(7404pub fn createDecl(
6727 ip: *InternPool,7405 ip: *InternPool,
6728 gpa: Allocator,7406 gpa: Allocator,
...@@ -6967,6 +7645,8 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {...@@ -6967,6 +7645,8 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
6967 .type_struct,7645 .type_struct,
6968 .type_struct_ns,7646 .type_struct_ns,
6969 .type_struct_anon,7647 .type_struct_anon,
7648 .type_struct_packed,
7649 .type_struct_packed_inits,
6970 .type_tuple_anon,7650 .type_tuple_anon,
6971 .type_union,7651 .type_union,
6972 .type_function,7652 .type_function,
...@@ -7056,7 +7736,7 @@ pub fn toEnum(ip: *const InternPool, comptime E: type, i: Index) E {...@@ -7056,7 +7736,7 @@ pub fn toEnum(ip: *const InternPool, comptime E: type, i: Index) E {
70567736
7057pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 {7737pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 {
7058 return switch (ip.indexToKey(ty)) {7738 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,
7060 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,7740 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
7061 .array_type => |array_type| array_type.len,7741 .array_type => |array_type| array_type.len,
7062 .vector_type => |vector_type| vector_type.len,7742 .vector_type => |vector_type| vector_type.len,
...@@ -7066,7 +7746,7 @@ pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 {...@@ -7066,7 +7746,7 @@ pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 {
70667746
7067pub fn aggregateTypeLenIncludingSentinel(ip: *const InternPool, ty: Index) u64 {7747pub fn aggregateTypeLenIncludingSentinel(ip: *const InternPool, ty: Index) u64 {
7068 return switch (ip.indexToKey(ty)) {7748 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,
7070 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,7750 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
7071 .array_type => |array_type| array_type.len + @intFromBool(array_type.sentinel != .none),7751 .array_type => |array_type| array_type.len + @intFromBool(array_type.sentinel != .none),
7072 .vector_type => |vector_type| vector_type.len,7752 .vector_type => |vector_type| vector_type.len,
...@@ -7301,6 +7981,8 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois...@@ -7301,6 +7981,8 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois
7301 .type_struct,7981 .type_struct,
7302 .type_struct_ns,7982 .type_struct_ns,
7303 .type_struct_anon,7983 .type_struct_anon,
7984 .type_struct_packed,
7985 .type_struct_packed_inits,
7304 .type_tuple_anon,7986 .type_tuple_anon,
7305 => .Struct,7987 => .Struct,
73067988
...@@ -7526,6 +8208,40 @@ pub fn resolveBuiltinType(ip: *InternPool, want_index: Index, resolved_index: In...@@ -7526,6 +8208,40 @@ pub fn resolveBuiltinType(ip: *InternPool, want_index: Index, resolved_index: In
7526 .data = @intFromEnum(SimpleValue.@"unreachable"),8208 .data = @intFromEnum(SimpleValue.@"unreachable"),
7527 });8209 });
7528 } else {8210 } else {
7529 // TODO: add the index to a free-list for reuse8211 // 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.
7530 }8213 }
7531}8214}
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...@@ -105,8 +105,6 @@ comptime_capture_scopes: std.AutoArrayHashMapUnmanaged(CaptureScope.Key, InternP
105105
106/// To be eliminated in a future commit by moving more data into InternPool.106/// To be eliminated in a future commit by moving more data into InternPool.
107/// Current uses that must be eliminated:107/// Current uses that must be eliminated:
108/// * Struct comptime_args
109/// * Struct optimized_order
110/// * comptime pointer mutation108/// * comptime pointer mutation
111/// This memory lives until the Module is destroyed.109/// This memory lives until the Module is destroyed.
112tmp_hack_arena: std.heap.ArenaAllocator,110tmp_hack_arena: std.heap.ArenaAllocator,
...@@ -678,14 +676,10 @@ pub const Decl = struct {...@@ -678,14 +676,10 @@ pub const Decl = struct {
678676
679 /// If the Decl owns its value and it is a struct, return it,677 /// If the Decl owns its value and it is a struct, return it,
680 /// otherwise null.678 /// otherwise null.
681 pub fn getOwnedStruct(decl: Decl, mod: *Module) ?*Struct {679 pub fn getOwnedStruct(decl: Decl, mod: *Module) ?InternPool.Key.StructType {
682 return mod.structPtrUnwrap(decl.getOwnedStructIndex(mod));680 if (!decl.owns_tv) return null;
683 }681 if (decl.val.ip_index == .none) return null;
684682 return mod.typeToStruct(decl.val.toType());
685 pub fn getOwnedStructIndex(decl: Decl, mod: *Module) Struct.OptionalIndex {
686 if (!decl.owns_tv) return .none;
687 if (decl.val.ip_index == .none) return .none;
688 return mod.intern_pool.indexToStructType(decl.val.toIntern());
689 }683 }
690684
691 /// If the Decl owns its value and it is a union, return it,685 /// If the Decl owns its value and it is a union, return it,
...@@ -795,9 +789,10 @@ pub const Decl = struct {...@@ -795,9 +789,10 @@ pub const Decl = struct {
795 return decl.getExternDecl(mod) != .none;789 return decl.getExternDecl(mod) != .none;
796 }790 }
797791
798 pub fn getAlignment(decl: Decl, mod: *Module) u32 {792 pub fn getAlignment(decl: Decl, mod: *Module) Alignment {
799 assert(decl.has_tv);793 assert(decl.has_tv);
800 return @as(u32, @intCast(decl.alignment.toByteUnitsOptional() orelse decl.ty.abiAlignment(mod)));794 if (decl.alignment != .none) return decl.alignment;
795 return decl.ty.abiAlignment(mod);
801 }796 }
802};797};
803798
...@@ -806,218 +801,6 @@ pub const EmitH = struct {...@@ -806,218 +801,6 @@ pub const EmitH = struct {
806 fwd_decl: ArrayListUnmanaged(u8) = .{},801 fwd_decl: ArrayListUnmanaged(u8) = .{},
807};802};
808803
809pub const PropertyBoolean = enum { no, yes, unknown, wip };
810
811/// Represents the data that a struct declaration provides.
812pub const Struct = struct {
813 /// Set of field names in declaration order.
814 fields: Fields,
815 /// Represents the declarations inside this struct.
816 namespace: Namespace.Index,
817 /// The Decl that corresponds to the struct itself.
818 owner_decl: Decl.Index,
819 /// Index of the struct_decl ZIR instruction.
820 zir_index: Zir.Inst.Index,
821 /// Indexes into `fields` sorted to be most memory efficient.
822 optimized_order: ?[*]u32 = null,
823 layout: std.builtin.Type.ContainerLayout,
824 /// If the layout is not packed, this is the noreturn type.
825 /// If the layout is packed, this is the backing integer type of the packed struct.
826 /// Whether zig chooses this type or the user specifies it, it is stored here.
827 /// This will be set to the noreturn type until status is `have_layout`.
828 backing_int_ty: Type = Type.noreturn,
829 status: enum {
830 none,
831 field_types_wip,
832 have_field_types,
833 layout_wip,
834 have_layout,
835 fully_resolved_wip,
836 // The types and all its fields have had their layout resolved. Even through pointer,
837 // which `have_layout` does not ensure.
838 fully_resolved,
839 },
840 /// If true, has more than one possible value. However it may still be non-runtime type
841 /// if it is a comptime-only type.
842 /// If false, resolving the fields is necessary to determine whether the type has only
843 /// one possible value.
844 known_non_opv: bool,
845 requires_comptime: PropertyBoolean = .unknown,
846 have_field_inits: bool = false,
847 is_tuple: bool,
848 assumed_runtime_bits: bool = false,
849
850 pub const Index = enum(u32) {
851 _,
852
853 pub fn toOptional(i: Index) OptionalIndex {
854 return @as(OptionalIndex, @enumFromInt(@intFromEnum(i)));
855 }
856 };
857
858 pub const OptionalIndex = enum(u32) {
859 none = std.math.maxInt(u32),
860 _,
861
862 pub fn init(oi: ?Index) OptionalIndex {
863 return @as(OptionalIndex, @enumFromInt(@intFromEnum(oi orelse return .none)));
864 }
865
866 pub fn unwrap(oi: OptionalIndex) ?Index {
867 if (oi == .none) return null;
868 return @as(Index, @enumFromInt(@intFromEnum(oi)));
869 }
870 };
871
872 pub const Fields = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, Field);
873
874 /// The `Type` and `Value` memory is owned by the arena of the Struct's owner_decl.
875 pub const Field = struct {
876 /// Uses `noreturn` to indicate `anytype`.
877 /// undefined until `status` is >= `have_field_types`.
878 ty: Type,
879 /// Uses `none` to indicate no default.
880 default_val: InternPool.Index,
881 /// Zero means to use the ABI alignment of the type.
882 abi_align: Alignment,
883 /// undefined until `status` is `have_layout`.
884 offset: u32,
885 /// If true then `default_val` is the comptime field value.
886 is_comptime: bool,
887
888 /// Returns the field alignment. If the struct is packed, returns 0.
889 /// Keep implementation in sync with `Sema.structFieldAlignment`.
890 pub fn alignment(
891 field: Field,
892 mod: *Module,
893 layout: std.builtin.Type.ContainerLayout,
894 ) u32 {
895 if (field.abi_align.toByteUnitsOptional()) |abi_align| {
896 assert(layout != .Packed);
897 return @as(u32, @intCast(abi_align));
898 }
899
900 const target = mod.getTarget();
901
902 switch (layout) {
903 .Packed => return 0,
904 .Auto => {
905 if (target.ofmt == .c) {
906 return alignmentExtern(field, mod);
907 } else {
908 return field.ty.abiAlignment(mod);
909 }
910 },
911 .Extern => return alignmentExtern(field, mod),
912 }
913 }
914
915 pub fn alignmentExtern(field: Field, mod: *Module) u32 {
916 // This logic is duplicated in Type.abiAlignmentAdvanced.
917 const ty_abi_align = field.ty.abiAlignment(mod);
918
919 if (field.ty.isAbiInt(mod) and field.ty.intInfo(mod).bits >= 128) {
920 // The C ABI requires 128 bit integer fields of structs
921 // to be 16-bytes aligned.
922 return @max(ty_abi_align, 16);
923 }
924
925 return ty_abi_align;
926 }
927 };
928
929 /// Used in `optimized_order` to indicate field that is not present in the
930 /// runtime version of the struct.
931 pub const omitted_field = std.math.maxInt(u32);
932
933 pub fn getFullyQualifiedName(s: *Struct, mod: *Module) !InternPool.NullTerminatedString {
934 return mod.declPtr(s.owner_decl).getFullyQualifiedName(mod);
935 }
936
937 pub fn srcLoc(s: Struct, mod: *Module) SrcLoc {
938 return mod.declPtr(s.owner_decl).srcLoc(mod);
939 }
940
941 pub fn haveFieldTypes(s: Struct) bool {
942 return switch (s.status) {
943 .none,
944 .field_types_wip,
945 => false,
946 .have_field_types,
947 .layout_wip,
948 .have_layout,
949 .fully_resolved_wip,
950 .fully_resolved,
951 => true,
952 };
953 }
954
955 pub fn haveLayout(s: Struct) bool {
956 return switch (s.status) {
957 .none,
958 .field_types_wip,
959 .have_field_types,
960 .layout_wip,
961 => false,
962 .have_layout,
963 .fully_resolved_wip,
964 .fully_resolved,
965 => true,
966 };
967 }
968
969 pub fn packedFieldBitOffset(s: Struct, mod: *Module, index: usize) u16 {
970 assert(s.layout == .Packed);
971 assert(s.haveLayout());
972 var bit_sum: u64 = 0;
973 for (s.fields.values(), 0..) |field, i| {
974 if (i == index) {
975 return @as(u16, @intCast(bit_sum));
976 }
977 bit_sum += field.ty.bitSize(mod);
978 }
979 unreachable; // index out of bounds
980 }
981
982 pub const RuntimeFieldIterator = struct {
983 module: *Module,
984 struct_obj: *const Struct,
985 index: u32 = 0,
986
987 pub const FieldAndIndex = struct {
988 field: Field,
989 index: u32,
990 };
991
992 pub fn next(it: *RuntimeFieldIterator) ?FieldAndIndex {
993 const mod = it.module;
994 while (true) {
995 var i = it.index;
996 it.index += 1;
997 if (it.struct_obj.fields.count() <= i)
998 return null;
999
1000 if (it.struct_obj.optimized_order) |some| {
1001 i = some[i];
1002 if (i == Module.Struct.omitted_field) return null;
1003 }
1004 const field = it.struct_obj.fields.values()[i];
1005
1006 if (!field.is_comptime and field.ty.hasRuntimeBits(mod)) {
1007 return FieldAndIndex{ .index = i, .field = field };
1008 }
1009 }
1010 }
1011 };
1012
1013 pub fn runtimeFieldIterator(s: *const Struct, module: *Module) RuntimeFieldIterator {
1014 return .{
1015 .struct_obj = s,
1016 .module = module,
1017 };
1018 }
1019};
1020
1021pub const DeclAdapter = struct {804pub const DeclAdapter = struct {
1022 mod: *Module,805 mod: *Module,
1023806
...@@ -2893,20 +2676,10 @@ pub fn namespacePtr(mod: *Module, index: Namespace.Index) *Namespace {...@@ -2893,20 +2676,10 @@ pub fn namespacePtr(mod: *Module, index: Namespace.Index) *Namespace {
2893 return mod.intern_pool.namespacePtr(index);2676 return mod.intern_pool.namespacePtr(index);
2894}2677}
28952678
2896pub fn structPtr(mod: *Module, index: Struct.Index) *Struct {
2897 return mod.intern_pool.structPtr(index);
2898}
2899
2900pub fn namespacePtrUnwrap(mod: *Module, index: Namespace.OptionalIndex) ?*Namespace {2679pub fn namespacePtrUnwrap(mod: *Module, index: Namespace.OptionalIndex) ?*Namespace {
2901 return mod.namespacePtr(index.unwrap() orelse return null);2680 return mod.namespacePtr(index.unwrap() orelse return null);
2902}2681}
29032682
2904/// This one accepts an index from the InternPool and asserts that it is not
2905/// the anonymous empty struct type.
2906pub fn structPtrUnwrap(mod: *Module, index: Struct.OptionalIndex) ?*Struct {
2907 return mod.structPtr(index.unwrap() orelse return null);
2908}
2909
2910/// Returns true if and only if the Decl is the top level struct associated with a File.2683/// Returns true if and only if the Decl is the top level struct associated with a File.
2911pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool {2684pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool {
2912 const decl = mod.declPtr(decl_index);2685 const decl = mod.declPtr(decl_index);
...@@ -3351,11 +3124,11 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void {...@@ -3351,11 +3124,11 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void {
33513124
3352 if (!decl.owns_tv) continue;3125 if (!decl.owns_tv) continue;
33533126
3354 if (decl.getOwnedStruct(mod)) |struct_obj| {3127 if (decl.getOwnedStruct(mod)) |struct_type| {
3355 struct_obj.zir_index = inst_map.get(struct_obj.zir_index) orelse {3128 struct_type.setZirIndex(ip, inst_map.get(struct_type.zir_index) orelse {
3356 try file.deleted_decls.append(gpa, decl_index);3129 try file.deleted_decls.append(gpa, decl_index);
3357 continue;3130 continue;
3358 };3131 });
3359 }3132 }
33603133
3361 if (decl.getOwnedUnion(mod)) |union_type| {3134 if (decl.getOwnedUnion(mod)) |union_type| {
...@@ -3870,36 +3643,16 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {...@@ -3870,36 +3643,16 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
3870 const new_decl = mod.declPtr(new_decl_index);3643 const new_decl = mod.declPtr(new_decl_index);
3871 errdefer @panic("TODO error handling");3644 errdefer @panic("TODO error handling");
38723645
3873 const struct_index = try mod.createStruct(.{
3874 .owner_decl = new_decl_index,
3875 .fields = .{},
3876 .zir_index = undefined, // set below
3877 .layout = .Auto,
3878 .status = .none,
3879 .known_non_opv = undefined,
3880 .is_tuple = undefined, // set below
3881 .namespace = new_namespace_index,
3882 });
3883 errdefer mod.destroyStruct(struct_index);
3884
3885 const struct_ty = try mod.intern_pool.get(gpa, .{ .struct_type = .{
3886 .index = struct_index.toOptional(),
3887 .namespace = new_namespace_index.toOptional(),
3888 } });
3889 // TODO: figure out InternPool removals for incremental compilation
3890 //errdefer mod.intern_pool.remove(struct_ty);
3891
3892 new_namespace.ty = struct_ty.toType();
3893 file.root_decl = new_decl_index.toOptional();3646 file.root_decl = new_decl_index.toOptional();
38943647
3895 new_decl.name = try file.fullyQualifiedName(mod);3648 new_decl.name = try file.fullyQualifiedName(mod);
3649 new_decl.name_fully_qualified = true;
3896 new_decl.src_line = 0;3650 new_decl.src_line = 0;
3897 new_decl.is_pub = true;3651 new_decl.is_pub = true;
3898 new_decl.is_exported = false;3652 new_decl.is_exported = false;
3899 new_decl.has_align = false;3653 new_decl.has_align = false;
3900 new_decl.has_linksection_or_addrspace = false;3654 new_decl.has_linksection_or_addrspace = false;
3901 new_decl.ty = Type.type;3655 new_decl.ty = Type.type;
3902 new_decl.val = struct_ty.toValue();
3903 new_decl.alignment = .none;3656 new_decl.alignment = .none;
3904 new_decl.@"linksection" = .none;3657 new_decl.@"linksection" = .none;
3905 new_decl.has_tv = true;3658 new_decl.has_tv = true;
...@@ -3907,75 +3660,76 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {...@@ -3907,75 +3660,76 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
3907 new_decl.alive = true; // This Decl corresponds to a File and is therefore always alive.3660 new_decl.alive = true; // This Decl corresponds to a File and is therefore always alive.
3908 new_decl.analysis = .in_progress;3661 new_decl.analysis = .in_progress;
3909 new_decl.generation = mod.generation;3662 new_decl.generation = mod.generation;
3910 new_decl.name_fully_qualified = true;
39113663
3912 if (file.status == .success_zir) {3664 if (file.status != .success_zir) {
3913 assert(file.zir_loaded);3665 new_decl.analysis = .file_failure;
3914 const main_struct_inst = Zir.main_struct_inst;3666 return;
3915 const struct_obj = mod.structPtr(struct_index);3667 }
3916 struct_obj.zir_index = main_struct_inst;3668 assert(file.zir_loaded);
3917 const extended = file.zir.instructions.items(.data)[main_struct_inst].extended;
3918 const small = @as(Zir.Inst.StructDecl.Small, @bitCast(extended.small));
3919 struct_obj.is_tuple = small.is_tuple;
3920
3921 var sema_arena = std.heap.ArenaAllocator.init(gpa);
3922 defer sema_arena.deinit();
3923 const sema_arena_allocator = sema_arena.allocator();
3924
3925 var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);
3926 defer comptime_mutable_decls.deinit();
3927
3928 var sema: Sema = .{
3929 .mod = mod,
3930 .gpa = gpa,
3931 .arena = sema_arena_allocator,
3932 .code = file.zir,
3933 .owner_decl = new_decl,
3934 .owner_decl_index = new_decl_index,
3935 .func_index = .none,
3936 .func_is_naked = false,
3937 .fn_ret_ty = Type.void,
3938 .fn_ret_ty_ies = null,
3939 .owner_func_index = .none,
3940 .comptime_mutable_decls = &comptime_mutable_decls,
3941 };
3942 defer sema.deinit();
39433669
3944 if (sema.analyzeStructDecl(new_decl, main_struct_inst, struct_index)) |_| {3670 var sema_arena = std.heap.ArenaAllocator.init(gpa);
3945 for (comptime_mutable_decls.items) |decl_index| {3671 defer sema_arena.deinit();
3946 const decl = mod.declPtr(decl_index);3672 const sema_arena_allocator = sema_arena.allocator();
3947 _ = try decl.internValue(mod);
3948 }
3949 new_decl.analysis = .complete;
3950 } else |err| switch (err) {
3951 error.OutOfMemory => return error.OutOfMemory,
3952 error.AnalysisFail => {},
3953 }
39543673
3955 if (mod.comp.whole_cache_manifest) |whole_cache_manifest| {3674 var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);
3956 const source = file.getSource(gpa) catch |err| {3675 defer comptime_mutable_decls.deinit();
3957 try reportRetryableFileError(mod, file, "unable to load source: {s}", .{@errorName(err)});
3958 return error.AnalysisFail;
3959 };
39603676
3961 const resolved_path = std.fs.path.resolve(3677 var sema: Sema = .{
3962 gpa,3678 .mod = mod,
3963 if (file.pkg.root_src_directory.path) |pkg_path|3679 .gpa = gpa,
3964 &[_][]const u8{ pkg_path, file.sub_file_path }3680 .arena = sema_arena_allocator,
3965 else3681 .code = file.zir,
3966 &[_][]const u8{file.sub_file_path},3682 .owner_decl = new_decl,
3967 ) catch |err| {3683 .owner_decl_index = new_decl_index,
3968 try reportRetryableFileError(mod, file, "unable to resolve path: {s}", .{@errorName(err)});3684 .func_index = .none,
3969 return error.AnalysisFail;3685 .func_is_naked = false,
3970 };3686 .fn_ret_ty = Type.void,
3971 errdefer gpa.free(resolved_path);3687 .fn_ret_ty_ies = null,
3688 .owner_func_index = .none,
3689 .comptime_mutable_decls = &comptime_mutable_decls,
3690 };
3691 defer sema.deinit();
39723692
3973 mod.comp.whole_cache_manifest_mutex.lock();3693 const main_struct_inst = Zir.main_struct_inst;
3974 defer mod.comp.whole_cache_manifest_mutex.unlock();3694 const struct_ty = sema.getStructType(
3975 try whole_cache_manifest.addFilePostContents(resolved_path, source.bytes, source.stat);3695 new_decl_index,
3976 }3696 new_namespace_index,
3977 } else {3697 main_struct_inst,
3978 new_decl.analysis = .file_failure;3698 ) catch |err| switch (err) {
3699 error.OutOfMemory => return error.OutOfMemory,
3700 };
3701 // TODO: figure out InternPool removals for incremental compilation
3702 //errdefer ip.remove(struct_ty);
3703 for (comptime_mutable_decls.items) |decl_index| {
3704 const decl = mod.declPtr(decl_index);
3705 _ = try decl.internValue(mod);
3706 }
3707
3708 new_namespace.ty = struct_ty.toType();
3709 new_decl.val = struct_ty.toValue();
3710 new_decl.analysis = .complete;
3711
3712 if (mod.comp.whole_cache_manifest) |whole_cache_manifest| {
3713 const source = file.getSource(gpa) catch |err| {
3714 try reportRetryableFileError(mod, file, "unable to load source: {s}", .{@errorName(err)});
3715 return error.AnalysisFail;
3716 };
3717
3718 const resolved_path = std.fs.path.resolve(
3719 gpa,
3720 if (file.pkg.root_src_directory.path) |pkg_path|
3721 &[_][]const u8{ pkg_path, file.sub_file_path }
3722 else
3723 &[_][]const u8{file.sub_file_path},
3724 ) catch |err| {
3725 try reportRetryableFileError(mod, file, "unable to resolve path: {s}", .{@errorName(err)});
3726 return error.AnalysisFail;
3727 };
3728 errdefer gpa.free(resolved_path);
3729
3730 mod.comp.whole_cache_manifest_mutex.lock();
3731 defer mod.comp.whole_cache_manifest_mutex.unlock();
3732 try whole_cache_manifest.addFilePostContents(resolved_path, source.bytes, source.stat);
3979 }3733 }
3980}3734}
39813735
...@@ -4055,18 +3809,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -4055,18 +3809,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
4055 };3809 };
4056 defer sema.deinit();3810 defer sema.deinit();
40573811
4058 if (mod.declIsRoot(decl_index)) {3812 assert(!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 }
40703813
4071 var block_scope: Sema.Block = .{3814 var block_scope: Sema.Block = .{
4072 .parent = null,3815 .parent = null,
...@@ -5241,14 +4984,6 @@ pub fn destroyNamespace(mod: *Module, index: Namespace.Index) void {...@@ -5241,14 +4984,6 @@ pub fn destroyNamespace(mod: *Module, index: Namespace.Index) void {
5241 return mod.intern_pool.destroyNamespace(mod.gpa, index);4984 return mod.intern_pool.destroyNamespace(mod.gpa, index);
5242}4985}
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
5252pub fn allocateNewDecl(4987pub fn allocateNewDecl(
5253 mod: *Module,4988 mod: *Module,
5254 namespace: Namespace.Index,4989 namespace: Namespace.Index,
...@@ -6202,7 +5937,6 @@ pub fn optionalType(mod: *Module, child_type: InternPool.Index) Allocator.Error!...@@ -6202,7 +5937,6 @@ pub fn optionalType(mod: *Module, child_type: InternPool.Index) Allocator.Error!
62025937
6203pub fn ptrType(mod: *Module, info: InternPool.Key.PtrType) Allocator.Error!Type {5938pub fn ptrType(mod: *Module, info: InternPool.Key.PtrType) Allocator.Error!Type {
6204 var canon_info = info;5939 var canon_info = info;
6205 const have_elem_layout = info.child.toType().layoutIsResolved(mod);
62065940
6207 if (info.flags.size == .C) canon_info.flags.is_allowzero = true;5941 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...@@ -6210,17 +5944,17 @@ pub fn ptrType(mod: *Module, info: InternPool.Key.PtrType) Allocator.Error!Type
6210 // type, we change it to 0 here. If this causes an assertion trip because the5944 // type, we change it to 0 here. If this causes an assertion trip because the
6211 // pointee type needs to be resolved more, that needs to be done before calling5945 // pointee type needs to be resolved more, that needs to be done before calling
6212 // this ptr() function.5946 // this ptr() function.
6213 if (info.flags.alignment.toByteUnitsOptional()) |info_align| {5947 if (info.flags.alignment != .none and
6214 if (have_elem_layout and info_align == info.child.toType().abiAlignment(mod)) {5948 info.flags.alignment == info.child.toType().abiAlignment(mod))
6215 canon_info.flags.alignment = .none;5949 {
6216 }5950 canon_info.flags.alignment = .none;
6217 }5951 }
62185952
6219 switch (info.flags.vector_index) {5953 switch (info.flags.vector_index) {
6220 // Canonicalize host_size. If it matches the bit size of the pointee type,5954 // Canonicalize host_size. If it matches the bit size of the pointee type,
6221 // we change it to 0 here. If this causes an assertion trip, the pointee type5955 // we change it to 0 here. If this causes an assertion trip, the pointee type
6222 // needs to be resolved before calling this ptr() function.5956 // 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) {
6224 const elem_bit_size = info.child.toType().bitSize(mod);5958 const elem_bit_size = info.child.toType().bitSize(mod);
6225 assert(info.packed_offset.bit_offset + elem_bit_size <= info.packed_offset.host_size * 8);5959 assert(info.packed_offset.bit_offset + elem_bit_size <= info.packed_offset.host_size * 8);
6226 if (info.packed_offset.host_size * 8 == elem_bit_size) {5960 if (info.packed_offset.host_size * 8 == elem_bit_size) {
...@@ -6483,7 +6217,7 @@ pub fn intBitsForValue(mod: *Module, val: Value, sign: bool) u16 {...@@ -6483,7 +6217,7 @@ pub fn intBitsForValue(mod: *Module, val: Value, sign: bool) u16 {
6483 return @as(u16, @intCast(big.bitCountTwosComp()));6217 return @as(u16, @intCast(big.bitCountTwosComp()));
6484 },6218 },
6485 .lazy_align => |lazy_ty| {6219 .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);
6487 },6221 },
6488 .lazy_size => |lazy_ty| {6222 .lazy_size => |lazy_ty| {
6489 return Type.smallestUnsignedBits(lazy_ty.toType().abiSize(mod)) + @intFromBool(sign);6223 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...@@ -6639,20 +6373,30 @@ pub fn namespaceDeclIndex(mod: *Module, namespace_index: Namespace.Index) Decl.I
6639/// * `@TypeOf(.{})`6373/// * `@TypeOf(.{})`
6640/// * A struct which has no fields (`struct {}`).6374/// * A struct which has no fields (`struct {}`).
6641/// * Not a struct.6375/// * Not a struct.
6642pub fn typeToStruct(mod: *Module, ty: Type) ?*Struct {6376pub fn typeToStruct(mod: *Module, ty: Type) ?InternPool.Key.StructType {
6643 if (ty.ip_index == .none) return null;6377 if (ty.ip_index == .none) return null;
6644 const struct_index = mod.intern_pool.indexToStructType(ty.toIntern()).unwrap() orelse return null;6378 return switch (mod.intern_pool.indexToKey(ty.ip_index)) {
6645 return mod.structPtr(struct_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 };
6646}6390}
66476391
6648/// This asserts that the union's enum tag type has been resolved.6392/// This asserts that the union's enum tag type has been resolved.
6649pub fn typeToUnion(mod: *Module, ty: Type) ?InternPool.UnionType {6393pub fn typeToUnion(mod: *Module, ty: Type) ?InternPool.UnionType {
6650 if (ty.ip_index == .none) return null;6394 if (ty.ip_index == .none) return null;
6651 const ip = &mod.intern_pool;6395 const ip = &mod.intern_pool;
6652 switch (ip.indexToKey(ty.ip_index)) {6396 return switch (ip.indexToKey(ty.ip_index)) {
6653 .union_type => |k| return ip.loadUnionType(k),6397 .union_type => |k| ip.loadUnionType(k),
6654 else => return null,6398 else => null,
6655 }6399 };
6656}6400}
66576401
6658pub fn typeToFunc(mod: *Module, ty: Type) ?InternPool.Key.FuncType {6402pub 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]...@@ -6741,13 +6485,13 @@ pub fn getParamName(mod: *Module, func_index: InternPool.Index, index: u32) [:0]
67416485
6742pub const UnionLayout = struct {6486pub const UnionLayout = struct {
6743 abi_size: u64,6487 abi_size: u64,
6744 abi_align: u32,6488 abi_align: Alignment,
6745 most_aligned_field: u32,6489 most_aligned_field: u32,
6746 most_aligned_field_size: u64,6490 most_aligned_field_size: u64,
6747 biggest_field: u32,6491 biggest_field: u32,
6748 payload_size: u64,6492 payload_size: u64,
6749 payload_align: u32,6493 payload_align: Alignment,
6750 tag_align: u32,6494 tag_align: Alignment,
6751 tag_size: u64,6495 tag_size: u64,
6752 padding: u32,6496 padding: u32,
6753};6497};
...@@ -6759,35 +6503,37 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout {...@@ -6759,35 +6503,37 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout {
6759 var most_aligned_field_size: u64 = undefined;6503 var most_aligned_field_size: u64 = undefined;
6760 var biggest_field: u32 = undefined;6504 var biggest_field: u32 = undefined;
6761 var payload_size: u64 = 0;6505 var payload_size: u64 = 0;
6762 var payload_align: u32 = 0;6506 var payload_align: Alignment = .@"1";
6763 for (u.field_types.get(ip), 0..) |field_ty, i| {6507 for (u.field_types.get(ip), 0..) |field_ty, i| {
6764 if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;6508 if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
67656509
6766 const field_align = u.fieldAlign(ip, @intCast(i)).toByteUnitsOptional() orelse6510 const explicit_align = u.fieldAlign(ip, @intCast(i));
6511 const field_align = if (explicit_align != .none)
6512 explicit_align
6513 else
6767 field_ty.toType().abiAlignment(mod);6514 field_ty.toType().abiAlignment(mod);
6768 const field_size = field_ty.toType().abiSize(mod);6515 const field_size = field_ty.toType().abiSize(mod);
6769 if (field_size > payload_size) {6516 if (field_size > payload_size) {
6770 payload_size = field_size;6517 payload_size = field_size;
6771 biggest_field = @intCast(i);6518 biggest_field = @intCast(i);
6772 }6519 }
6773 if (field_align > payload_align) {6520 if (field_align.compare(.gte, payload_align)) {
6774 payload_align = @intCast(field_align);6521 payload_align = field_align;
6775 most_aligned_field = @intCast(i);6522 most_aligned_field = @intCast(i);
6776 most_aligned_field_size = field_size;6523 most_aligned_field_size = field_size;
6777 }6524 }
6778 }6525 }
6779 payload_align = @max(payload_align, 1);
6780 const have_tag = u.flagsPtr(ip).runtime_tag.hasTag();6526 const have_tag = u.flagsPtr(ip).runtime_tag.hasTag();
6781 if (!have_tag or !u.enum_tag_ty.toType().hasRuntimeBits(mod)) {6527 if (!have_tag or !u.enum_tag_ty.toType().hasRuntimeBits(mod)) {
6782 return .{6528 return .{
6783 .abi_size = std.mem.alignForward(u64, payload_size, payload_align),6529 .abi_size = payload_align.forward(payload_size),
6784 .abi_align = payload_align,6530 .abi_align = payload_align,
6785 .most_aligned_field = most_aligned_field,6531 .most_aligned_field = most_aligned_field,
6786 .most_aligned_field_size = most_aligned_field_size,6532 .most_aligned_field_size = most_aligned_field_size,
6787 .biggest_field = biggest_field,6533 .biggest_field = biggest_field,
6788 .payload_size = payload_size,6534 .payload_size = payload_size,
6789 .payload_align = payload_align,6535 .payload_align = payload_align,
6790 .tag_align = 0,6536 .tag_align = .none,
6791 .tag_size = 0,6537 .tag_size = 0,
6792 .padding = 0,6538 .padding = 0,
6793 };6539 };
...@@ -6795,29 +6541,29 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout {...@@ -6795,29 +6541,29 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout {
6795 // Put the tag before or after the payload depending on which one's6541 // Put the tag before or after the payload depending on which one's
6796 // alignment is greater.6542 // alignment is greater.
6797 const tag_size = u.enum_tag_ty.toType().abiSize(mod);6543 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");
6799 var size: u64 = 0;6545 var size: u64 = 0;
6800 var padding: u32 = undefined;6546 var padding: u32 = undefined;
6801 if (tag_align >= payload_align) {6547 if (tag_align.compare(.gte, payload_align)) {
6802 // {Tag, Payload}6548 // {Tag, Payload}
6803 size += tag_size;6549 size += tag_size;
6804 size = std.mem.alignForward(u64, size, payload_align);6550 size = payload_align.forward(size);
6805 size += payload_size;6551 size += payload_size;
6806 const prev_size = size;6552 const prev_size = size;
6807 size = std.mem.alignForward(u64, size, tag_align);6553 size = tag_align.forward(size);
6808 padding = @as(u32, @intCast(size - prev_size));6554 padding = @intCast(size - prev_size);
6809 } else {6555 } else {
6810 // {Payload, Tag}6556 // {Payload, Tag}
6811 size += payload_size;6557 size += payload_size;
6812 size = std.mem.alignForward(u64, size, tag_align);6558 size = tag_align.forward(size);
6813 size += tag_size;6559 size += tag_size;
6814 const prev_size = size;6560 const prev_size = size;
6815 size = std.mem.alignForward(u64, size, payload_align);6561 size = payload_align.forward(size);
6816 padding = @as(u32, @intCast(size - prev_size));6562 padding = @intCast(size - prev_size);
6817 }6563 }
6818 return .{6564 return .{
6819 .abi_size = size,6565 .abi_size = size,
6820 .abi_align = @max(tag_align, payload_align),6566 .abi_align = tag_align.max(payload_align),
6821 .most_aligned_field = most_aligned_field,6567 .most_aligned_field = most_aligned_field,
6822 .most_aligned_field_size = most_aligned_field_size,6568 .most_aligned_field_size = most_aligned_field_size,
6823 .biggest_field = biggest_field,6569 .biggest_field = biggest_field,
...@@ -6834,17 +6580,16 @@ pub fn unionAbiSize(mod: *Module, u: InternPool.UnionType) u64 {...@@ -6834,17 +6580,16 @@ pub fn unionAbiSize(mod: *Module, u: InternPool.UnionType) u64 {
6834}6580}
68356581
6836/// Returns 0 if the union is represented with 0 bits at runtime.6582/// Returns 0 if the union is represented with 0 bits at runtime.
6837/// TODO: this returns alignment in byte units should should be a u646583pub fn unionAbiAlignment(mod: *Module, u: InternPool.UnionType) Alignment {
6838pub fn unionAbiAlignment(mod: *Module, u: InternPool.UnionType) u32 {
6839 const ip = &mod.intern_pool;6584 const ip = &mod.intern_pool;
6840 const have_tag = u.flagsPtr(ip).runtime_tag.hasTag();6585 const have_tag = u.flagsPtr(ip).runtime_tag.hasTag();
6841 var max_align: u32 = 0;6586 var max_align: Alignment = .none;
6842 if (have_tag) max_align = u.enum_tag_ty.toType().abiAlignment(mod);6587 if (have_tag) max_align = u.enum_tag_ty.toType().abiAlignment(mod);
6843 for (u.field_types.get(ip), 0..) |field_ty, field_index| {6588 for (u.field_types.get(ip), 0..) |field_ty, field_index| {
6844 if (!field_ty.toType().hasRuntimeBits(mod)) continue;6589 if (!field_ty.toType().hasRuntimeBits(mod)) continue;
68456590
6846 const field_align = mod.unionFieldNormalAlignment(u, @intCast(field_index));6591 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);
6848 }6593 }
6849 return max_align;6594 return max_align;
6850}6595}
...@@ -6852,10 +6597,10 @@ pub fn unionAbiAlignment(mod: *Module, u: InternPool.UnionType) u32 {...@@ -6852,10 +6597,10 @@ pub fn unionAbiAlignment(mod: *Module, u: InternPool.UnionType) u32 {
6852/// Returns the field alignment, assuming the union is not packed.6597/// Returns the field alignment, assuming the union is not packed.
6853/// Keep implementation in sync with `Sema.unionFieldAlignment`.6598/// Keep implementation in sync with `Sema.unionFieldAlignment`.
6854/// Prefer to call that function instead of this one during Sema.6599/// Prefer to call that function instead of this one during Sema.
6855/// TODO: this returns alignment in byte units should should be a u646600pub fn unionFieldNormalAlignment(mod: *Module, u: InternPool.UnionType, field_index: u32) Alignment {
6856pub fn unionFieldNormalAlignment(mod: *Module, u: InternPool.UnionType, field_index: u32) u32 {
6857 const ip = &mod.intern_pool;6601 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;
6859 const field_ty = u.field_types.get(ip)[field_index].toType();6604 const field_ty = u.field_types.get(ip)[field_index].toType();
6860 return field_ty.abiAlignment(mod);6605 return field_ty.abiAlignment(mod);
6861}6606}
...@@ -6866,3 +6611,64 @@ pub fn unionTagFieldIndex(mod: *Module, u: InternPool.UnionType, enum_tag: Value...@@ -6866,3 +6611,64 @@ pub fn unionTagFieldIndex(mod: *Module, u: InternPool.UnionType, enum_tag: Value
6866 const enum_type = ip.indexToKey(u.enum_tag_ty).enum_type;6611 const enum_type = ip.indexToKey(u.enum_tag_ty).enum_type;
6867 return enum_type.tagValueIndex(ip, enum_tag.toIntern());6612 return enum_type.tagValueIndex(ip, enum_tag.toIntern());
6868}6613}
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...@@ -2221,8 +2221,8 @@ fn failWithInvalidComptimeFieldStore(sema: *Sema, block: *Block, init_src: LazyS
2221 const msg = try sema.errMsg(block, init_src, "value stored in comptime field does not match the default value of the field", .{});2221 const msg = try sema.errMsg(block, init_src, "value stored in comptime field does not match the default value of the field", .{});
2222 errdefer msg.destroy(sema.gpa);2222 errdefer msg.destroy(sema.gpa);
22232223
2224 const struct_ty = mod.typeToStruct(container_ty) orelse break :msg msg;2224 const struct_type = mod.typeToStruct(container_ty) orelse break :msg msg;
2225 const default_value_src = mod.fieldSrcLoc(struct_ty.owner_decl, .{2225 const default_value_src = mod.fieldSrcLoc(struct_type.decl.unwrap().?, .{
2226 .index = field_index,2226 .index = field_index,
2227 .range = .value,2227 .range = .value,
2228 });2228 });
...@@ -2504,23 +2504,33 @@ fn analyzeAsAlign(...@@ -2504,23 +2504,33 @@ fn analyzeAsAlign(
2504 const alignment_big = try sema.analyzeAsInt(block, src, air_ref, align_ty, .{2504 const alignment_big = try sema.analyzeAsInt(block, src, air_ref, align_ty, .{
2505 .needed_comptime_reason = "alignment must be comptime-known",2505 .needed_comptime_reason = "alignment must be comptime-known",
2506 });2506 });
2507 const alignment: u32 = @intCast(alignment_big); // We coerce to u29 in the prev line.2507 return sema.validateAlign(block, src, alignment_big);
2508 try sema.validateAlign(block, src, alignment);
2509 return Alignment.fromNonzeroByteUnits(alignment);
2510}2508}
25112509
2512fn validateAlign(2510fn validateAlign(
2513 sema: *Sema,2511 sema: *Sema,
2514 block: *Block,2512 block: *Block,
2515 src: LazySrcLoc,2513 src: LazySrcLoc,
2516 alignment: u32,2514 alignment: u64,
2517) !void {2515) !Alignment {
2518 if (alignment == 0) return sema.fail(block, src, "alignment must be >= 1", .{});2516 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;
2519 if (!std.math.isPowerOfTwo(alignment)) {2528 if (!std.math.isPowerOfTwo(alignment)) {
2520 return sema.fail(block, src, "alignment value '{d}' is not a power of two", .{2529 return sema.fail(block, src, "alignment value '{d}' is not a power of two", .{
2521 alignment,2530 alignment,
2522 });2531 });
2523 }2532 }
2533 return Alignment.fromNonzeroByteUnits(alignment);
2524}2534}
25252535
2526pub fn resolveAlign(2536pub fn resolveAlign(
...@@ -2619,7 +2629,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -2619,7 +2629,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
2619 defer trash_block.instructions.deinit(sema.gpa);2629 defer trash_block.instructions.deinit(sema.gpa);
2620 const operand = try trash_block.addBitCast(pointee_ty, .void_value);2630 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(.{
2623 .child = pointee_ty.toIntern(),2633 .child = pointee_ty.toIntern(),
2624 .flags = .{2634 .flags = .{
2625 .alignment = ia1.alignment,2635 .alignment = ia1.alignment,
...@@ -2650,7 +2660,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -2650,7 +2660,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
2650 if (alignment != .none) {2660 if (alignment != .none) {
2651 try sema.resolveTypeLayout(pointee_ty);2661 try sema.resolveTypeLayout(pointee_ty);
2652 }2662 }
2653 const ptr_ty = try mod.ptrType(.{2663 const ptr_ty = try sema.ptrType(.{
2654 .child = pointee_ty.toIntern(),2664 .child = pointee_ty.toIntern(),
2655 .flags = .{2665 .flags = .{
2656 .alignment = alignment,2666 .alignment = alignment,
...@@ -2720,7 +2730,7 @@ fn coerceResultPtr(...@@ -2720,7 +2730,7 @@ fn coerceResultPtr(
2720 }2730 }
2721 }2731 }
27222732
2723 const ptr_ty = try mod.ptrType(.{2733 const ptr_ty = try sema.ptrType(.{
2724 .child = pointee_ty.toIntern(),2734 .child = pointee_ty.toIntern(),
2725 .flags = .{ .address_space = addr_space },2735 .flags = .{ .address_space = addr_space },
2726 });2736 });
...@@ -2749,7 +2759,7 @@ fn coerceResultPtr(...@@ -2749,7 +2759,7 @@ fn coerceResultPtr(
2749 // Array coerced to Vector where element size is not equal but coercible.2759 // Array coerced to Vector where element size is not equal but coercible.
2750 .aggregate_init => {2760 .aggregate_init => {
2751 const ty_pl = air_datas[trash_inst].ty_pl;2761 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(.{
2753 .child = (try sema.analyzeAsType(block, src, ty_pl.ty)).toIntern(),2763 .child = (try sema.analyzeAsType(block, src, ty_pl.ty)).toIntern(),
2754 .flags = .{ .address_space = addr_space },2764 .flags = .{ .address_space = addr_space },
2755 });2765 });
...@@ -2763,7 +2773,7 @@ fn coerceResultPtr(...@@ -2763,7 +2773,7 @@ fn coerceResultPtr(
2763 .bitcast => {2773 .bitcast => {
2764 const ty_op = air_datas[trash_inst].ty_op;2774 const ty_op = air_datas[trash_inst].ty_op;
2765 const operand_ty = sema.typeOf(ty_op.operand);2775 const operand_ty = sema.typeOf(ty_op.operand);
2766 const ptr_operand_ty = try mod.ptrType(.{2776 const ptr_operand_ty = try sema.ptrType(.{
2767 .child = operand_ty.toIntern(),2777 .child = operand_ty.toIntern(),
2768 .flags = .{ .address_space = addr_space },2778 .flags = .{ .address_space = addr_space },
2769 });2779 });
...@@ -2801,26 +2811,26 @@ fn coerceResultPtr(...@@ -2801,26 +2811,26 @@ fn coerceResultPtr(
2801 }2811 }
2802}2812}
28032813
2804pub fn analyzeStructDecl(2814pub fn getStructType(
2805 sema: *Sema,2815 sema: *Sema,
2806 new_decl: *Decl,2816 decl: Module.Decl.Index,
2807 inst: Zir.Inst.Index,2817 namespace: Module.Namespace.Index,
2808 struct_index: Module.Struct.Index,2818 zir_index: Zir.Inst.Index,
2809) SemaError!void {2819) !InternPool.Index {
2810 const mod = sema.mod;2820 const mod = sema.mod;
2811 const struct_obj = mod.structPtr(struct_index);2821 const gpa = sema.gpa;
2812 const extended = sema.code.instructions.items(.data)[inst].extended;2822 const ip = &mod.intern_pool;
2823 const extended = sema.code.instructions.items(.data)[zir_index].extended;
2813 assert(extended.opcode == .struct_decl);2824 assert(extended.opcode == .struct_decl);
2814 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);2825 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
2821 var extra_index: usize = extended.operand;2827 var extra_index: usize = extended.operand;
2822 extra_index += @intFromBool(small.has_src_node);2828 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;
2824 const decls_len = if (small.has_decls_len) blk: {2834 const decls_len = if (small.has_decls_len) blk: {
2825 const decls_len = sema.code.extra[extra_index];2835 const decls_len = sema.code.extra[extra_index];
2826 extra_index += 1;2836 extra_index += 1;
...@@ -2837,7 +2847,23 @@ pub fn analyzeStructDecl(...@@ -2837,7 +2847,23 @@ pub fn analyzeStructDecl(
2837 }2847 }
2838 }2848 }
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;
2841}2867}
28422868
2843fn zirStructDecl(2869fn zirStructDecl(
...@@ -2847,7 +2873,7 @@ fn zirStructDecl(...@@ -2847,7 +2873,7 @@ fn zirStructDecl(
2847 inst: Zir.Inst.Index,2873 inst: Zir.Inst.Index,
2848) CompileError!Air.Inst.Ref {2874) CompileError!Air.Inst.Ref {
2849 const mod = sema.mod;2875 const mod = sema.mod;
2850 const gpa = sema.gpa;2876 const ip = &mod.intern_pool;
2851 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);2877 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
2852 const src: LazySrcLoc = if (small.has_src_node) blk: {2878 const src: LazySrcLoc = if (small.has_src_node) blk: {
2853 const node_offset: i32 = @bitCast(sema.code.extra[extended.operand]);2879 const node_offset: i32 = @bitCast(sema.code.extra[extended.operand]);
...@@ -2874,37 +2900,21 @@ fn zirStructDecl(...@@ -2874,37 +2900,21 @@ fn zirStructDecl(
2874 const new_namespace = mod.namespacePtr(new_namespace_index);2900 const new_namespace = mod.namespacePtr(new_namespace_index);
2875 errdefer mod.destroyNamespace(new_namespace_index);2901 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
2889 const struct_ty = ty: {2903 const struct_ty = ty: {
2890 const ty = try mod.intern_pool.get(gpa, .{ .struct_type = .{2904 const ty = try sema.getStructType(new_decl_index, new_namespace_index, inst);
2891 .index = struct_index.toOptional(),
2892 .namespace = new_namespace_index.toOptional(),
2893 } });
2894 if (sema.builtin_type_target_index != .none) {2905 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);
2896 break :ty sema.builtin_type_target_index;2907 break :ty sema.builtin_type_target_index;
2897 }2908 }
2898 break :ty ty;2909 break :ty ty;
2899 };2910 };
2900 // TODO: figure out InternPool removals for incremental compilation2911 // TODO: figure out InternPool removals for incremental compilation
2901 //errdefer mod.intern_pool.remove(struct_ty);2912 //errdefer ip.remove(struct_ty);
29022913
2903 new_decl.ty = Type.type;2914 new_decl.ty = Type.type;
2904 new_decl.val = struct_ty.toValue();2915 new_decl.val = struct_ty.toValue();
2905 new_namespace.ty = struct_ty.toType();2916 new_namespace.ty = struct_ty.toType();
29062917
2907 try sema.analyzeStructDecl(new_decl, inst, struct_index);
2908 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);2918 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
2909 try mod.finalizeAnonDecl(new_decl_index);2919 try mod.finalizeAnonDecl(new_decl_index);
2910 return decl_val;2920 return decl_val;
...@@ -3196,7 +3206,7 @@ fn zirEnumDecl(...@@ -3196,7 +3206,7 @@ fn zirEnumDecl(
3196 extra_index += 1;3206 extra_index += 1;
31973207
3198 const field_name = try mod.intern_pool.getOrPutString(gpa, field_name_zir);3208 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| {
3200 const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy;3210 const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy;
3201 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy;3211 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy;
3202 const msg = msg: {3212 const msg = msg: {
...@@ -3227,7 +3237,7 @@ fn zirEnumDecl(...@@ -3227,7 +3237,7 @@ fn zirEnumDecl(
3227 };3237 };
3228 if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) break :overflow true;3238 if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) break :overflow true;
3229 last_tag_val = try mod.getCoerced(last_tag_val.?, int_tag_ty);3239 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| {
3231 const value_src = mod.fieldSrcLoc(new_decl_index, .{3241 const value_src = mod.fieldSrcLoc(new_decl_index, .{
3232 .index = field_i,3242 .index = field_i,
3233 .range = .value,3243 .range = .value,
...@@ -3249,7 +3259,7 @@ fn zirEnumDecl(...@@ -3249,7 +3259,7 @@ fn zirEnumDecl(
3249 else3259 else
3250 try mod.intValue(int_tag_ty, 0);3260 try mod.intValue(int_tag_ty, 0);
3251 if (overflow != null) break :overflow true;3261 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| {
3253 const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy;3263 const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy;
3254 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy;3264 const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy;
3255 const msg = msg: {3265 const msg = msg: {
...@@ -3498,7 +3508,7 @@ fn zirRetPtr(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {...@@ -3498,7 +3508,7 @@ fn zirRetPtr(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
3498 }3508 }
34993509
3500 const target = sema.mod.getTarget();3510 const target = sema.mod.getTarget();
3501 const ptr_type = try sema.mod.ptrType(.{3511 const ptr_type = try sema.ptrType(.{
3502 .child = sema.fn_ret_ty.toIntern(),3512 .child = sema.fn_ret_ty.toIntern(),
3503 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },3513 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
3504 });3514 });
...@@ -3507,6 +3517,7 @@ fn zirRetPtr(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {...@@ -3507,6 +3517,7 @@ fn zirRetPtr(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
3507 // We are inlining a function call; this should be emitted as an alloc, not a ret_ptr.3517 // We are inlining a function call; this should be emitted as an alloc, not a ret_ptr.
3508 // TODO when functions gain result location support, the inlining struct in3518 // TODO when functions gain result location support, the inlining struct in
3509 // Block should contain the return pointer, and we would pass that through here.3519 // Block should contain the return pointer, and we would pass that through here.
3520 try sema.queueFullTypeResolution(sema.fn_ret_ty);
3510 return block.addTy(.alloc, ptr_type);3521 return block.addTy(.alloc, ptr_type);
3511 }3522 }
35123523
...@@ -3701,7 +3712,7 @@ fn zirAllocExtended(...@@ -3701,7 +3712,7 @@ fn zirAllocExtended(
3701 }3712 }
3702 const target = sema.mod.getTarget();3713 const target = sema.mod.getTarget();
3703 try sema.resolveTypeLayout(var_ty);3714 try sema.resolveTypeLayout(var_ty);
3704 const ptr_type = try sema.mod.ptrType(.{3715 const ptr_type = try sema.ptrType(.{
3705 .child = var_ty.toIntern(),3716 .child = var_ty.toIntern(),
3706 .flags = .{3717 .flags = .{
3707 .alignment = alignment,3718 .alignment = alignment,
...@@ -3810,7 +3821,7 @@ fn makePtrConst(sema: *Sema, block: *Block, alloc: Air.Inst.Ref) CompileError!Ai...@@ -3810,7 +3821,7 @@ fn makePtrConst(sema: *Sema, block: *Block, alloc: Air.Inst.Ref) CompileError!Ai
38103821
3811 var ptr_info = alloc_ty.ptrInfo(mod);3822 var ptr_info = alloc_ty.ptrInfo(mod);
3812 ptr_info.flags.is_const = true;3823 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
3815 // Detect if a comptime value simply needs to have its type changed.3826 // Detect if a comptime value simply needs to have its type changed.
3816 if (try sema.resolveMaybeUndefVal(alloc)) |val| {3827 if (try sema.resolveMaybeUndefVal(alloc)) |val| {
...@@ -3852,7 +3863,7 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -3852,7 +3863,7 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
3852 return sema.analyzeComptimeAlloc(block, var_ty, .none);3863 return sema.analyzeComptimeAlloc(block, var_ty, .none);
3853 }3864 }
3854 const target = sema.mod.getTarget();3865 const target = sema.mod.getTarget();
3855 const ptr_type = try sema.mod.ptrType(.{3866 const ptr_type = try sema.ptrType(.{
3856 .child = var_ty.toIntern(),3867 .child = var_ty.toIntern(),
3857 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },3868 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
3858 });3869 });
...@@ -3872,7 +3883,7 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -3872,7 +3883,7 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
3872 }3883 }
3873 try sema.validateVarType(block, ty_src, var_ty, false);3884 try sema.validateVarType(block, ty_src, var_ty, false);
3874 const target = sema.mod.getTarget();3885 const target = sema.mod.getTarget();
3875 const ptr_type = try sema.mod.ptrType(.{3886 const ptr_type = try sema.ptrType(.{
3876 .child = var_ty.toIntern(),3887 .child = var_ty.toIntern(),
3877 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },3888 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
3878 });3889 });
...@@ -3938,7 +3949,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -3938,7 +3949,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
3938 const decl = mod.declPtr(decl_index);3949 const decl = mod.declPtr(decl_index);
3939 if (iac.is_const) _ = try decl.internValue(mod);3950 if (iac.is_const) _ = try decl.internValue(mod);
3940 const final_elem_ty = decl.ty;3951 const final_elem_ty = decl.ty;
3941 const final_ptr_ty = try mod.ptrType(.{3952 const final_ptr_ty = try sema.ptrType(.{
3942 .child = final_elem_ty.toIntern(),3953 .child = final_elem_ty.toIntern(),
3943 .flags = .{3954 .flags = .{
3944 .is_const = false,3955 .is_const = false,
...@@ -3971,7 +3982,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -3971,7 +3982,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
3971 const peer_inst_list = ia2.prongs.items(.stored_inst);3982 const peer_inst_list = ia2.prongs.items(.stored_inst);
3972 const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list, .none);3983 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(.{
3975 .child = final_elem_ty.toIntern(),3986 .child = final_elem_ty.toIntern(),
3976 .flags = .{3987 .flags = .{
3977 .alignment = ia1.alignment,3988 .alignment = ia1.alignment,
...@@ -4093,7 +4104,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -4093,7 +4104,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
4093 trash_block.is_comptime = false;4104 trash_block.is_comptime = false;
4094 defer trash_block.instructions.deinit(gpa);4105 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(.{
4097 .child = final_elem_ty.toIntern(),4108 .child = final_elem_ty.toIntern(),
4098 .flags = .{4109 .flags = .{
4099 .alignment = ia1.alignment,4110 .alignment = ia1.alignment,
...@@ -4688,12 +4699,13 @@ fn validateStructInit(...@@ -4688,12 +4699,13 @@ fn validateStructInit(
4688 // In this case the only thing we need to do is evaluate the implicit4699 // In this case the only thing we need to do is evaluate the implicit
4689 // store instructions for default field values, and report any missing fields.4700 // store instructions for default field values, and report any missing fields.
4690 // Avoid the cost of the extra machinery for detecting a comptime struct init value.4701 // 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);
4692 if (field_ptr != 0) continue;4704 if (field_ptr != 0) continue;
46934705
4694 const default_val = struct_ty.structFieldDefaultValue(i, mod);4706 const default_val = struct_ty.structFieldDefaultValue(i, mod);
4695 if (default_val.toIntern() == .unreachable_value) {4707 if (default_val.toIntern() == .unreachable_value) {
4696 if (struct_ty.isTuple(mod)) {4708 const field_name = struct_ty.structFieldName(i, mod).unwrap() orelse {
4697 const template = "missing tuple field with index {d}";4709 const template = "missing tuple field with index {d}";
4698 if (root_msg) |msg| {4710 if (root_msg) |msg| {
4699 try sema.errNote(block, init_src, msg, template, .{i});4711 try sema.errNote(block, init_src, msg, template, .{i});
...@@ -4701,8 +4713,7 @@ fn validateStructInit(...@@ -4701,8 +4713,7 @@ fn validateStructInit(
4701 root_msg = try sema.errMsg(block, init_src, template, .{i});4713 root_msg = try sema.errMsg(block, init_src, template, .{i});
4702 }4714 }
4703 continue;4715 continue;
4704 }4716 };
4705 const field_name = struct_ty.structFieldName(i, mod);
4706 const template = "missing struct field: {}";4717 const template = "missing struct field: {}";
4707 const args = .{field_name.fmt(ip)};4718 const args = .{field_name.fmt(ip)};
4708 if (root_msg) |msg| {4719 if (root_msg) |msg| {
...@@ -4723,10 +4734,11 @@ fn validateStructInit(...@@ -4723,10 +4734,11 @@ fn validateStructInit(
4723 }4734 }
47244735
4725 if (root_msg) |msg| {4736 if (root_msg) |msg| {
4726 if (mod.typeToStruct(struct_ty)) |struct_obj| {4737 if (mod.typeToStruct(struct_ty)) |struct_type| {
4727 const fqn = try struct_obj.getFullyQualifiedName(mod);4738 const decl = mod.declPtr(struct_type.decl.unwrap().?);
4739 const fqn = try decl.getFullyQualifiedName(mod);
4728 try mod.errNoteNonLazy(4740 try mod.errNoteNonLazy(
4729 struct_obj.srcLoc(mod),4741 decl.srcLoc(mod),
4730 msg,4742 msg,
4731 "struct '{}' declared here",4743 "struct '{}' declared here",
4732 .{fqn.fmt(ip)},4744 .{fqn.fmt(ip)},
...@@ -4751,7 +4763,8 @@ fn validateStructInit(...@@ -4751,7 +4763,8 @@ fn validateStructInit(
4751 // ends up being comptime-known.4763 // ends up being comptime-known.
4752 const field_values = try sema.arena.alloc(InternPool.Index, struct_ty.structFieldCount(mod));4764 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);
4755 if (field_ptr != 0) {4768 if (field_ptr != 0) {
4756 // Determine whether the value stored to this pointer is comptime-known.4769 // Determine whether the value stored to this pointer is comptime-known.
4757 const field_ty = struct_ty.structFieldType(i, mod);4770 const field_ty = struct_ty.structFieldType(i, mod);
...@@ -4830,7 +4843,7 @@ fn validateStructInit(...@@ -4830,7 +4843,7 @@ fn validateStructInit(
48304843
4831 const default_val = struct_ty.structFieldDefaultValue(i, mod);4844 const default_val = struct_ty.structFieldDefaultValue(i, mod);
4832 if (default_val.toIntern() == .unreachable_value) {4845 if (default_val.toIntern() == .unreachable_value) {
4833 if (struct_ty.isTuple(mod)) {4846 const field_name = struct_ty.structFieldName(i, mod).unwrap() orelse {
4834 const template = "missing tuple field with index {d}";4847 const template = "missing tuple field with index {d}";
4835 if (root_msg) |msg| {4848 if (root_msg) |msg| {
4836 try sema.errNote(block, init_src, msg, template, .{i});4849 try sema.errNote(block, init_src, msg, template, .{i});
...@@ -4838,8 +4851,7 @@ fn validateStructInit(...@@ -4838,8 +4851,7 @@ fn validateStructInit(
4838 root_msg = try sema.errMsg(block, init_src, template, .{i});4851 root_msg = try sema.errMsg(block, init_src, template, .{i});
4839 }4852 }
4840 continue;4853 continue;
4841 }4854 };
4842 const field_name = struct_ty.structFieldName(i, mod);
4843 const template = "missing struct field: {}";4855 const template = "missing struct field: {}";
4844 const args = .{field_name.fmt(ip)};4856 const args = .{field_name.fmt(ip)};
4845 if (root_msg) |msg| {4857 if (root_msg) |msg| {
...@@ -4853,10 +4865,11 @@ fn validateStructInit(...@@ -4853,10 +4865,11 @@ fn validateStructInit(
4853 }4865 }
48544866
4855 if (root_msg) |msg| {4867 if (root_msg) |msg| {
4856 if (mod.typeToStruct(struct_ty)) |struct_obj| {4868 if (mod.typeToStruct(struct_ty)) |struct_type| {
4857 const fqn = try struct_obj.getFullyQualifiedName(mod);4869 const decl = mod.declPtr(struct_type.decl.unwrap().?);
4870 const fqn = try decl.getFullyQualifiedName(mod);
4858 try mod.errNoteNonLazy(4871 try mod.errNoteNonLazy(
4859 struct_obj.srcLoc(mod),4872 decl.srcLoc(mod),
4860 msg,4873 msg,
4861 "struct '{}' declared here",4874 "struct '{}' declared here",
4862 .{fqn.fmt(ip)},4875 .{fqn.fmt(ip)},
...@@ -5255,14 +5268,14 @@ fn failWithBadMemberAccess(...@@ -5255,14 +5268,14 @@ fn failWithBadMemberAccess(
5255fn failWithBadStructFieldAccess(5268fn failWithBadStructFieldAccess(
5256 sema: *Sema,5269 sema: *Sema,
5257 block: *Block,5270 block: *Block,
5258 struct_obj: *Module.Struct,5271 struct_type: InternPool.Key.StructType,
5259 field_src: LazySrcLoc,5272 field_src: LazySrcLoc,
5260 field_name: InternPool.NullTerminatedString,5273 field_name: InternPool.NullTerminatedString,
5261) CompileError {5274) CompileError {
5262 const mod = sema.mod;5275 const mod = sema.mod;
5263 const gpa = sema.gpa;5276 const gpa = sema.gpa;
52645277 const decl = mod.declPtr(struct_type.decl.unwrap().?);
5265 const fqn = try struct_obj.getFullyQualifiedName(mod);5278 const fqn = try decl.getFullyQualifiedName(mod);
52665279
5267 const msg = msg: {5280 const msg = msg: {
5268 const msg = try sema.errMsg(5281 const msg = try sema.errMsg(
...@@ -5272,7 +5285,7 @@ fn failWithBadStructFieldAccess(...@@ -5272,7 +5285,7 @@ fn failWithBadStructFieldAccess(
5272 .{ field_name.fmt(&mod.intern_pool), fqn.fmt(&mod.intern_pool) },5285 .{ field_name.fmt(&mod.intern_pool), fqn.fmt(&mod.intern_pool) },
5273 );5286 );
5274 errdefer msg.destroy(gpa);5287 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", .{});
5276 break :msg msg;5289 break :msg msg;
5277 };5290 };
5278 return sema.failWithOwnedErrorMsg(block, msg);5291 return sema.failWithOwnedErrorMsg(block, msg);
...@@ -5787,9 +5800,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -5787,9 +5800,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
57875800
5788 try mod.semaFile(result.file);5801 try mod.semaFile(result.file);
5789 const file_root_decl_index = result.file.root_decl.unwrap().?;5802 const file_root_decl_index = result.file.root_decl.unwrap().?;
5790 const file_root_decl = mod.declPtr(file_root_decl_index);5803 return sema.analyzeDeclVal(parent_block, src, 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());
5793}5804}
57945805
5795fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {5806fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -8638,7 +8649,7 @@ fn analyzeOptionalPayloadPtr(...@@ -8638,7 +8649,7 @@ fn analyzeOptionalPayloadPtr(
8638 }8649 }
86398650
8640 const child_type = opt_type.optionalChild(mod);8651 const child_type = opt_type.optionalChild(mod);
8641 const child_pointer = try mod.ptrType(.{8652 const child_pointer = try sema.ptrType(.{
8642 .child = child_type.toIntern(),8653 .child = child_type.toIntern(),
8643 .flags = .{8654 .flags = .{
8644 .is_const = optional_ptr_ty.isConstPtr(mod),8655 .is_const = optional_ptr_ty.isConstPtr(mod),
...@@ -8707,7 +8718,7 @@ fn zirOptionalPayload(...@@ -8707,7 +8718,7 @@ fn zirOptionalPayload(
8707 // TODO https://github.com/ziglang/zig/issues/65978718 // TODO https://github.com/ziglang/zig/issues/6597
8708 if (true) break :t operand_ty;8719 if (true) break :t operand_ty;
8709 const ptr_info = operand_ty.ptrInfo(mod);8720 const ptr_info = operand_ty.ptrInfo(mod);
8710 break :t try mod.ptrType(.{8721 break :t try sema.ptrType(.{
8711 .child = ptr_info.child,8722 .child = ptr_info.child,
8712 .flags = .{8723 .flags = .{
8713 .alignment = ptr_info.flags.alignment,8724 .alignment = ptr_info.flags.alignment,
...@@ -8825,7 +8836,7 @@ fn analyzeErrUnionPayloadPtr(...@@ -8825,7 +8836,7 @@ fn analyzeErrUnionPayloadPtr(
88258836
8826 const err_union_ty = operand_ty.childType(mod);8837 const err_union_ty = operand_ty.childType(mod);
8827 const payload_ty = err_union_ty.errorUnionPayload(mod);8838 const payload_ty = err_union_ty.errorUnionPayload(mod);
8828 const operand_pointer_ty = try mod.ptrType(.{8839 const operand_pointer_ty = try sema.ptrType(.{
8829 .child = payload_ty.toIntern(),8840 .child = payload_ty.toIntern(),
8830 .flags = .{8841 .flags = .{
8831 .is_const = operand_ty.isConstPtr(mod),8842 .is_const = operand_ty.isConstPtr(mod),
...@@ -10680,7 +10691,7 @@ const SwitchProngAnalysis = struct {...@@ -10680,7 +10691,7 @@ const SwitchProngAnalysis = struct {
10680 const union_obj = mod.typeToUnion(operand_ty).?;10691 const union_obj = mod.typeToUnion(operand_ty).?;
10681 const field_ty = union_obj.field_types.get(ip)[field_index].toType();10692 const field_ty = union_obj.field_types.get(ip)[field_index].toType();
10682 if (capture_byref) {10693 if (capture_byref) {
10683 const ptr_field_ty = try mod.ptrType(.{10694 const ptr_field_ty = try sema.ptrType(.{
10684 .child = field_ty.toIntern(),10695 .child = field_ty.toIntern(),
10685 .flags = .{10696 .flags = .{
10686 .is_const = !operand_ptr_ty.ptrIsMutable(mod),10697 .is_const = !operand_ptr_ty.ptrIsMutable(mod),
...@@ -10786,7 +10797,7 @@ const SwitchProngAnalysis = struct {...@@ -10786,7 +10797,7 @@ const SwitchProngAnalysis = struct {
10786 // By-reference captures have some further restrictions which make them easier to emit10797 // By-reference captures have some further restrictions which make them easier to emit
10787 if (capture_byref) {10798 if (capture_byref) {
10788 const operand_ptr_info = operand_ptr_ty.ptrInfo(mod);10799 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(.{
10790 .child = capture_ty.toIntern(),10801 .child = capture_ty.toIntern(),
10791 .flags = .{10802 .flags = .{
10792 // TODO: alignment!10803 // TODO: alignment!
...@@ -10800,7 +10811,7 @@ const SwitchProngAnalysis = struct {...@@ -10800,7 +10811,7 @@ const SwitchProngAnalysis = struct {
10800 // pointer type is in-memory coercible to the capture pointer type.10811 // pointer type is in-memory coercible to the capture pointer type.
10801 if (!same_types) {10812 if (!same_types) {
10802 for (field_tys, 0..) |field_ty, i| {10813 for (field_tys, 0..) |field_ty, i| {
10803 const field_ptr_ty = try mod.ptrType(.{10814 const field_ptr_ty = try sema.ptrType(.{
10804 .child = field_ty.toIntern(),10815 .child = field_ty.toIntern(),
10805 .flags = .{10816 .flags = .{
10806 // TODO: alignment!10817 // TODO: alignment!
...@@ -12953,9 +12964,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -12953,9 +12964,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12953 }12964 }
12954 },12965 },
12955 .struct_type => |struct_type| {12966 .struct_type => |struct_type| {
12956 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :hf false;12967 break :hf struct_type.nameIndex(ip, field_name) != null;
12957 assert(struct_obj.haveFieldTypes());
12958 break :hf struct_obj.fields.contains(field_name);
12959 },12968 },
12960 .union_type => |union_type| {12969 .union_type => |union_type| {
12961 const union_obj = ip.loadUnionType(union_type);12970 const union_obj = ip.loadUnionType(union_type);
...@@ -13025,9 +13034,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -13025,9 +13034,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
13025 };13034 };
13026 try mod.semaFile(result.file);13035 try mod.semaFile(result.file);
13027 const file_root_decl_index = result.file.root_decl.unwrap().?;13036 const file_root_decl_index = result.file.root_decl.unwrap().?;
13028 const file_root_decl = mod.declPtr(file_root_decl_index);13037 return sema.analyzeDeclVal(block, operand_src, 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());
13031}13038}
1303213039
13033fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {13040fn 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...@@ -13766,12 +13773,12 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
13766 try sema.requireRuntimeBlock(block, src, runtime_src);13773 try sema.requireRuntimeBlock(block, src, runtime_src);
1376713774
13768 if (ptr_addrspace) |ptr_as| {13775 if (ptr_addrspace) |ptr_as| {
13769 const alloc_ty = try mod.ptrType(.{13776 const alloc_ty = try sema.ptrType(.{
13770 .child = result_ty.toIntern(),13777 .child = result_ty.toIntern(),
13771 .flags = .{ .address_space = ptr_as },13778 .flags = .{ .address_space = ptr_as },
13772 });13779 });
13773 const alloc = try block.addTy(.alloc, alloc_ty);13780 const alloc = try block.addTy(.alloc, alloc_ty);
13774 const elem_ptr_ty = try mod.ptrType(.{13781 const elem_ptr_ty = try sema.ptrType(.{
13775 .child = resolved_elem_ty.toIntern(),13782 .child = resolved_elem_ty.toIntern(),
13776 .flags = .{ .address_space = ptr_as },13783 .flags = .{ .address_space = ptr_as },
13777 });13784 });
...@@ -14031,12 +14038,12 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -14031,12 +14038,12 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
14031 try sema.requireRuntimeBlock(block, src, lhs_src);14038 try sema.requireRuntimeBlock(block, src, lhs_src);
1403214039
14033 if (ptr_addrspace) |ptr_as| {14040 if (ptr_addrspace) |ptr_as| {
14034 const alloc_ty = try mod.ptrType(.{14041 const alloc_ty = try sema.ptrType(.{
14035 .child = result_ty.toIntern(),14042 .child = result_ty.toIntern(),
14036 .flags = .{ .address_space = ptr_as },14043 .flags = .{ .address_space = ptr_as },
14037 });14044 });
14038 const alloc = try block.addTy(.alloc, alloc_ty);14045 const alloc = try block.addTy(.alloc, alloc_ty);
14039 const elem_ptr_ty = try mod.ptrType(.{14046 const elem_ptr_ty = try sema.ptrType(.{
14040 .child = lhs_info.elem_type.toIntern(),14047 .child = lhs_info.elem_type.toIntern(),
14041 .flags = .{ .address_space = ptr_as },14048 .flags = .{ .address_space = ptr_as },
14042 });14049 });
...@@ -15978,7 +15985,7 @@ fn analyzePtrArithmetic(...@@ -15978,7 +15985,7 @@ fn analyzePtrArithmetic(
15978 ));15985 ));
15979 assert(new_align != .none);15986 assert(new_align != .none);
1598015987
15981 break :t try mod.ptrType(.{15988 break :t try sema.ptrType(.{
15982 .child = ptr_info.child,15989 .child = ptr_info.child,
15983 .sentinel = ptr_info.sentinel,15990 .sentinel = ptr_info.sentinel,
15984 .flags = .{15991 .flags = .{
...@@ -16881,7 +16888,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -16881,7 +16888,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
16881 .none, // default alignment16888 .none, // default alignment
16882 );16889 );
16883 break :v try mod.intern(.{ .ptr = .{16890 break :v try mod.intern(.{ .ptr = .{
16884 .ty = (try mod.ptrType(.{16891 .ty = (try sema.ptrType(.{
16885 .child = param_info_ty.toIntern(),16892 .child = param_info_ty.toIntern(),
16886 .flags = .{16893 .flags = .{
16887 .size = .Slice,16894 .size = .Slice,
...@@ -16907,7 +16914,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -16907,7 +16914,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
16907 // calling_convention: CallingConvention,16914 // calling_convention: CallingConvention,
16908 (try mod.enumValueFieldIndex(callconv_ty, @intFromEnum(func_ty_info.cc))).toIntern(),16915 (try mod.enumValueFieldIndex(callconv_ty, @intFromEnum(func_ty_info.cc))).toIntern(),
16909 // alignment: comptime_int,16916 // 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(),
16911 // is_generic: bool,16918 // is_generic: bool,
16912 Value.makeBool(func_ty_info.is_generic).toIntern(),16919 Value.makeBool(func_ty_info.is_generic).toIntern(),
16913 // is_var_args: bool,16920 // is_var_args: bool,
...@@ -17200,7 +17207,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17200,7 +17207,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17200 };17207 };
1720117208
17202 // Build our ?[]const Error value17209 // Build our ?[]const Error value
17203 const slice_errors_ty = try mod.ptrType(.{17210 const slice_errors_ty = try sema.ptrType(.{
17204 .child = error_field_ty.toIntern(),17211 .child = error_field_ty.toIntern(),
17205 .flags = .{17212 .flags = .{
17206 .size = .Slice,17213 .size = .Slice,
...@@ -17349,7 +17356,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17349,7 +17356,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17349 .none, // default alignment17356 .none, // default alignment
17350 );17357 );
17351 break :v try mod.intern(.{ .ptr = .{17358 break :v try mod.intern(.{ .ptr = .{
17352 .ty = (try mod.ptrType(.{17359 .ty = (try sema.ptrType(.{
17353 .child = enum_field_ty.toIntern(),17360 .child = enum_field_ty.toIntern(),
17354 .flags = .{17361 .flags = .{
17355 .size = .Slice,17362 .size = .Slice,
...@@ -17461,7 +17468,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17461,7 +17468,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1746117468
17462 const alignment = switch (layout) {17469 const alignment = switch (layout) {
17463 .Auto, .Extern => try sema.unionFieldAlignment(union_obj, @intCast(i)),17470 .Auto, .Extern => try sema.unionFieldAlignment(union_obj, @intCast(i)),
17464 .Packed => 0,17471 .Packed => .none,
17465 };17472 };
1746617473
17467 const field_ty = union_obj.field_types.get(ip)[i];17474 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...@@ -17471,7 +17478,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17471 // type: type,17478 // type: type,
17472 field_ty,17479 field_ty,
17473 // alignment: comptime_int,17480 // alignment: comptime_int,
17474 (try mod.intValue(Type.comptime_int, alignment)).toIntern(),17481 (try mod.intValue(Type.comptime_int, alignment.toByteUnits(0))).toIntern(),
17475 };17482 };
17476 field_val.* = try mod.intern(.{ .aggregate = .{17483 field_val.* = try mod.intern(.{ .aggregate = .{
17477 .ty = union_field_ty.toIntern(),17484 .ty = union_field_ty.toIntern(),
...@@ -17493,7 +17500,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17493,7 +17500,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17493 .none, // default alignment17500 .none, // default alignment
17494 );17501 );
17495 break :v try mod.intern(.{ .ptr = .{17502 break :v try mod.intern(.{ .ptr = .{
17496 .ty = (try mod.ptrType(.{17503 .ty = (try sema.ptrType(.{
17497 .child = union_field_ty.toIntern(),17504 .child = union_field_ty.toIntern(),
17498 .flags = .{17505 .flags = .{
17499 .size = .Slice,17506 .size = .Slice,
...@@ -17578,7 +17585,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17578,7 +17585,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17578 };17585 };
1757917586
17580 try sema.resolveTypeLayout(ty); // Getting alignment requires type layout17587 try sema.resolveTypeLayout(ty); // Getting alignment requires type layout
17581 const layout = ty.containerLayout(mod);
1758217588
17583 var struct_field_vals: []InternPool.Index = &.{};17589 var struct_field_vals: []InternPool.Index = &.{};
17584 defer gpa.free(struct_field_vals);17590 defer gpa.free(struct_field_vals);
...@@ -17633,7 +17639,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17633,7 +17639,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17633 // is_comptime: bool,17639 // is_comptime: bool,
17634 Value.makeBool(is_comptime).toIntern(),17640 Value.makeBool(is_comptime).toIntern(),
17635 // alignment: comptime_int,17641 // 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(),
17637 };17643 };
17638 struct_field_val.* = try mod.intern(.{ .aggregate = .{17644 struct_field_val.* = try mod.intern(.{ .aggregate = .{
17639 .ty = struct_field_ty.toIntern(),17645 .ty = struct_field_ty.toIntern(),
...@@ -17645,16 +17651,17 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17645,16 +17651,17 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17645 .struct_type => |s| s,17651 .struct_type => |s| s,
17646 else => unreachable,17652 else => unreachable,
17647 };17653 };
17648 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :fv;17654 struct_field_vals = try gpa.alloc(InternPool.Index, struct_type.field_types.len);
17649 struct_field_vals = try gpa.alloc(InternPool.Index, struct_obj.fields.count());17655
1765017656 for (struct_field_vals, 0..) |*field_val, i| {
17651 for (
17652 struct_field_vals,
17653 struct_obj.fields.keys(),
17654 struct_obj.fields.values(),
17655 ) |*field_val, name_nts, field| {
17656 // TODO: write something like getCoercedInts to avoid needing to dupe17657 // 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);
17658 const name_val = v: {17665 const name_val = v: {
17659 var anon_decl = try block.startAnonDecl();17666 var anon_decl = try block.startAnonDecl();
17660 defer anon_decl.deinit();17667 defer anon_decl.deinit();
...@@ -17677,24 +17684,28 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17677,24 +17684,28 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17677 } });17684 } });
17678 };17685 };
1767917686
17680 const opt_default_val = if (field.default_val == .none)17687 const opt_default_val = if (field_init == .none) null else field_init.toValue();
17681 null17688 const default_val_ptr = try sema.optRefValue(block, field_ty, opt_default_val);
17682 else17689 const alignment = switch (struct_type.layout) {
17683 field.default_val.toValue();17690 .Packed => .none,
17684 const default_val_ptr = try sema.optRefValue(block, field.ty, opt_default_val);17691 else => try sema.structFieldAlignment(
17685 const alignment = field.alignment(mod, layout);17692 struct_type.fieldAlign(ip, i),
17693 field_ty,
17694 struct_type.layout,
17695 ),
17696 };
1768617697
17687 const struct_field_fields = .{17698 const struct_field_fields = .{
17688 // name: []const u8,17699 // name: []const u8,
17689 name_val,17700 name_val,
17690 // type: type,17701 // type: type,
17691 field.ty.toIntern(),17702 field_ty.toIntern(),
17692 // default_value: ?*const anyopaque,17703 // default_value: ?*const anyopaque,
17693 default_val_ptr.toIntern(),17704 default_val_ptr.toIntern(),
17694 // is_comptime: bool,17705 // is_comptime: bool,
17695 Value.makeBool(field.is_comptime).toIntern(),17706 Value.makeBool(field_is_comptime).toIntern(),
17696 // alignment: comptime_int,17707 // alignment: comptime_int,
17697 (try mod.intValue(Type.comptime_int, alignment)).toIntern(),17708 (try mod.intValue(Type.comptime_int, alignment.toByteUnits(0))).toIntern(),
17698 };17709 };
17699 field_val.* = try mod.intern(.{ .aggregate = .{17710 field_val.* = try mod.intern(.{ .aggregate = .{
17700 .ty = struct_field_ty.toIntern(),17711 .ty = struct_field_ty.toIntern(),
...@@ -17717,7 +17728,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17717,7 +17728,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17717 .none, // default alignment17728 .none, // default alignment
17718 );17729 );
17719 break :v try mod.intern(.{ .ptr = .{17730 break :v try mod.intern(.{ .ptr = .{
17720 .ty = (try mod.ptrType(.{17731 .ty = (try sema.ptrType(.{
17721 .child = struct_field_ty.toIntern(),17732 .child = struct_field_ty.toIntern(),
17722 .flags = .{17733 .flags = .{
17723 .size = .Slice,17734 .size = .Slice,
...@@ -17733,11 +17744,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17733,11 +17744,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1773317744
17734 const backing_integer_val = try mod.intern(.{ .opt = .{17745 const backing_integer_val = try mod.intern(.{ .opt = .{
17735 .ty = (try mod.optionalType(.type_type)).toIntern(),17746 .ty = (try mod.optionalType(.type_type)).toIntern(),
17736 .val = if (layout == .Packed) val: {17747 .val = if (mod.typeToPackedStruct(ty)) |packed_struct| val: {
17737 const struct_obj = mod.typeToStruct(ty).?;17748 assert(packed_struct.backingIntType(ip).toType().isInt(mod));
17738 assert(struct_obj.haveLayout());17749 break :val packed_struct.backingIntType(ip).*;
17739 assert(struct_obj.backing_int_ty.isInt(mod));
17740 break :val struct_obj.backing_int_ty.toIntern();
17741 } else .none,17750 } else .none,
17742 } });17751 } });
1774317752
...@@ -17754,6 +17763,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17754,6 +17763,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17754 break :t decl.val.toType();17763 break :t decl.val.toType();
17755 };17764 };
1775617765
17766 const layout = ty.containerLayout(mod);
17767
17757 const field_values = [_]InternPool.Index{17768 const field_values = [_]InternPool.Index{
17758 // layout: ContainerLayout,17769 // layout: ContainerLayout,
17759 (try mod.enumValueFieldIndex(container_layout_ty, @intFromEnum(layout))).toIntern(),17770 (try mod.enumValueFieldIndex(container_layout_ty, @intFromEnum(layout))).toIntern(),
...@@ -17863,7 +17874,7 @@ fn typeInfoDecls(...@@ -17863,7 +17874,7 @@ fn typeInfoDecls(
17863 .none, // default alignment17874 .none, // default alignment
17864 );17875 );
17865 return try mod.intern(.{ .ptr = .{17876 return try mod.intern(.{ .ptr = .{
17866 .ty = (try mod.ptrType(.{17877 .ty = (try sema.ptrType(.{
17867 .child = declaration_ty.toIntern(),17878 .child = declaration_ty.toIntern(),
17868 .flags = .{17879 .flags = .{
17869 .size = .Slice,17880 .size = .Slice,
...@@ -18433,7 +18444,7 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr...@@ -18433,7 +18444,7 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr
1843318444
18434 const operand_ty = sema.typeOf(operand);18445 const operand_ty = sema.typeOf(operand);
18435 const ptr_info = operand_ty.ptrInfo(mod);18446 const ptr_info = operand_ty.ptrInfo(mod);
18436 const res_ty = try mod.ptrType(.{18447 const res_ty = try sema.ptrType(.{
18437 .child = err_union_ty.errorUnionPayload(mod).toIntern(),18448 .child = err_union_ty.errorUnionPayload(mod).toIntern(),
18438 .flags = .{18449 .flags = .{
18439 .is_const = ptr_info.flags.is_const,18450 .is_const = ptr_info.flags.is_const,
...@@ -18924,9 +18935,8 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -18924,9 +18935,8 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
18924 },18935 },
18925 else => {},18936 else => {},
18926 }18937 }
18927 const abi_align: u32 = @intCast((try val.getUnsignedIntAdvanced(mod, sema)).?);18938 const align_bytes = (try val.getUnsignedIntAdvanced(mod, sema)).?;
18928 try sema.validateAlign(block, align_src, abi_align);18939 break :blk try sema.validateAlignAllowZero(block, align_src, align_bytes);
18929 break :blk Alignment.fromByteUnits(abi_align);
18930 } else .none;18940 } else .none;
1893118941
18932 const address_space: std.builtin.AddressSpace = if (inst_data.flags.has_addrspace) blk: {18942 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...@@ -18988,7 +18998,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
18988 }18998 }
18989 }18999 }
1899019000
18991 const ty = try mod.ptrType(.{19001 const ty = try sema.ptrType(.{
18992 .child = elem_ty.toIntern(),19002 .child = elem_ty.toIntern(),
18993 .sentinel = sentinel,19003 .sentinel = sentinel,
18994 .flags = .{19004 .flags = .{
...@@ -19226,7 +19236,7 @@ fn zirStructInit(...@@ -19226,7 +19236,7 @@ fn zirStructInit(
1922619236
19227 if (is_ref) {19237 if (is_ref) {
19228 const target = mod.getTarget();19238 const target = mod.getTarget();
19229 const alloc_ty = try mod.ptrType(.{19239 const alloc_ty = try sema.ptrType(.{
19230 .child = resolved_ty.toIntern(),19240 .child = resolved_ty.toIntern(),
19231 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },19241 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
19232 });19242 });
...@@ -19291,12 +19301,12 @@ fn finishStructInit(...@@ -19291,12 +19301,12 @@ fn finishStructInit(
19291 }19301 }
19292 },19302 },
19293 .struct_type => |struct_type| {19303 .struct_type => |struct_type| {
19294 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;19304 for (0..struct_type.field_types.len) |i| {
19295 for (struct_obj.fields.values(), 0..) |field, i| {
19296 if (field_inits[i] != .none) continue;19305 if (field_inits[i] != .none) continue;
1929719306
19298 if (field.default_val == .none) {19307 const field_init = struct_type.fieldInit(ip, i);
19299 const field_name = struct_obj.fields.keys()[i];19308 if (field_init == .none) {
19309 const field_name = struct_type.field_names.get(ip)[i];
19300 const template = "missing struct field: {}";19310 const template = "missing struct field: {}";
19301 const args = .{field_name.fmt(ip)};19311 const args = .{field_name.fmt(ip)};
19302 if (root_msg) |msg| {19312 if (root_msg) |msg| {
...@@ -19305,7 +19315,7 @@ fn finishStructInit(...@@ -19305,7 +19315,7 @@ fn finishStructInit(
19305 root_msg = try sema.errMsg(block, init_src, template, args);19315 root_msg = try sema.errMsg(block, init_src, template, args);
19306 }19316 }
19307 } else {19317 } else {
19308 field_inits[i] = Air.internedToRef(field.default_val);19318 field_inits[i] = Air.internedToRef(field_init);
19309 }19319 }
19310 }19320 }
19311 },19321 },
...@@ -19313,10 +19323,11 @@ fn finishStructInit(...@@ -19313,10 +19323,11 @@ fn finishStructInit(
19313 }19323 }
1931419324
19315 if (root_msg) |msg| {19325 if (root_msg) |msg| {
19316 if (mod.typeToStruct(struct_ty)) |struct_obj| {19326 if (mod.typeToStruct(struct_ty)) |struct_type| {
19317 const fqn = try struct_obj.getFullyQualifiedName(mod);19327 const decl = mod.declPtr(struct_type.decl.unwrap().?);
19328 const fqn = try decl.getFullyQualifiedName(mod);
19318 try mod.errNoteNonLazy(19329 try mod.errNoteNonLazy(
19319 struct_obj.srcLoc(mod),19330 decl.srcLoc(mod),
19320 msg,19331 msg,
19321 "struct '{}' declared here",19332 "struct '{}' declared here",
19322 .{fqn.fmt(ip)},19333 .{fqn.fmt(ip)},
...@@ -19349,7 +19360,7 @@ fn finishStructInit(...@@ -19349,7 +19360,7 @@ fn finishStructInit(
19349 if (is_ref) {19360 if (is_ref) {
19350 try sema.resolveStructLayout(struct_ty);19361 try sema.resolveStructLayout(struct_ty);
19351 const target = sema.mod.getTarget();19362 const target = sema.mod.getTarget();
19352 const alloc_ty = try mod.ptrType(.{19363 const alloc_ty = try sema.ptrType(.{
19353 .child = struct_ty.toIntern(),19364 .child = struct_ty.toIntern(),
19354 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },19365 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
19355 });19366 });
...@@ -19502,7 +19513,7 @@ fn structInitAnon(...@@ -19502,7 +19513,7 @@ fn structInitAnon(
1950219513
19503 if (is_ref) {19514 if (is_ref) {
19504 const target = mod.getTarget();19515 const target = mod.getTarget();
19505 const alloc_ty = try mod.ptrType(.{19516 const alloc_ty = try sema.ptrType(.{
19506 .child = tuple_ty,19517 .child = tuple_ty,
19507 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },19518 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
19508 });19519 });
...@@ -19516,7 +19527,7 @@ fn structInitAnon(...@@ -19516,7 +19527,7 @@ fn structInitAnon(
19516 };19527 };
19517 extra_index = item.end;19528 extra_index = item.end;
1951819529
19519 const field_ptr_ty = try mod.ptrType(.{19530 const field_ptr_ty = try sema.ptrType(.{
19520 .child = field_ty,19531 .child = field_ty,
19521 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },19532 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
19522 });19533 });
...@@ -19640,7 +19651,7 @@ fn zirArrayInit(...@@ -19640,7 +19651,7 @@ fn zirArrayInit(
1964019651
19641 if (is_ref) {19652 if (is_ref) {
19642 const target = mod.getTarget();19653 const target = mod.getTarget();
19643 const alloc_ty = try mod.ptrType(.{19654 const alloc_ty = try sema.ptrType(.{
19644 .child = array_ty.toIntern(),19655 .child = array_ty.toIntern(),
19645 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },19656 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
19646 });19657 });
...@@ -19648,7 +19659,7 @@ fn zirArrayInit(...@@ -19648,7 +19659,7 @@ fn zirArrayInit(
1964819659
19649 if (array_ty.isTuple(mod)) {19660 if (array_ty.isTuple(mod)) {
19650 for (resolved_args, 0..) |arg, i| {19661 for (resolved_args, 0..) |arg, i| {
19651 const elem_ptr_ty = try mod.ptrType(.{19662 const elem_ptr_ty = try sema.ptrType(.{
19652 .child = array_ty.structFieldType(i, mod).toIntern(),19663 .child = array_ty.structFieldType(i, mod).toIntern(),
19653 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },19664 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
19654 });19665 });
...@@ -19661,7 +19672,7 @@ fn zirArrayInit(...@@ -19661,7 +19672,7 @@ fn zirArrayInit(
19661 return sema.makePtrConst(block, alloc);19672 return sema.makePtrConst(block, alloc);
19662 }19673 }
1966319674
19664 const elem_ptr_ty = try mod.ptrType(.{19675 const elem_ptr_ty = try sema.ptrType(.{
19665 .child = array_ty.elemType2(mod).toIntern(),19676 .child = array_ty.elemType2(mod).toIntern(),
19666 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },19677 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
19667 });19678 });
...@@ -19749,14 +19760,14 @@ fn arrayInitAnon(...@@ -19749,14 +19760,14 @@ fn arrayInitAnon(
1974919760
19750 if (is_ref) {19761 if (is_ref) {
19751 const target = sema.mod.getTarget();19762 const target = sema.mod.getTarget();
19752 const alloc_ty = try mod.ptrType(.{19763 const alloc_ty = try sema.ptrType(.{
19753 .child = tuple_ty,19764 .child = tuple_ty,
19754 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },19765 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
19755 });19766 });
19756 const alloc = try block.addTy(.alloc, alloc_ty);19767 const alloc = try block.addTy(.alloc, alloc_ty);
19757 for (operands, 0..) |operand, i_usize| {19768 for (operands, 0..) |operand, i_usize| {
19758 const i: u32 = @intCast(i_usize);19769 const i: u32 = @intCast(i_usize);
19759 const field_ptr_ty = try mod.ptrType(.{19770 const field_ptr_ty = try sema.ptrType(.{
19760 .child = types[i],19771 .child = types[i],
19761 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },19772 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
19762 });19773 });
...@@ -19848,10 +19859,10 @@ fn fieldType(...@@ -19848,10 +19859,10 @@ fn fieldType(
19848 return Air.internedToRef(anon_struct.types.get(ip)[field_index]);19859 return Air.internedToRef(anon_struct.types.get(ip)[field_index]);
19849 },19860 },
19850 .struct_type => |struct_type| {19861 .struct_type => |struct_type| {
19851 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;19862 const field_index = struct_type.nameIndex(ip, field_name) orelse
19852 const field = struct_obj.fields.get(field_name) orelse19863 return sema.failWithBadStructFieldAccess(block, struct_type, field_src, field_name);
19853 return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);19864 const field_ty = struct_type.field_types.get(ip)[field_index];
19854 return Air.internedToRef(field.ty.toIntern());19865 return Air.internedToRef(field_ty);
19855 },19866 },
19856 else => unreachable,19867 else => unreachable,
19857 },19868 },
...@@ -20167,14 +20178,14 @@ fn zirReify(...@@ -20167,14 +20178,14 @@ fn zirReify(
20167 .AnyFrame => return sema.failWithUseOfAsync(block, src),20178 .AnyFrame => return sema.failWithUseOfAsync(block, src),
20168 .EnumLiteral => return .enum_literal_type,20179 .EnumLiteral => return .enum_literal_type,
20169 .Int => {20180 .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;
20171 const signedness_val = try union_val.val.toValue().fieldValue(20182 const signedness_val = try union_val.val.toValue().fieldValue(
20172 mod,20183 mod,
20173 fields.getIndex(try ip.getOrPutString(gpa, "signedness")).?,20184 struct_type.nameIndex(ip, try ip.getOrPutString(gpa, "signedness")).?,
20174 );20185 );
20175 const bits_val = try union_val.val.toValue().fieldValue(20186 const bits_val = try union_val.val.toValue().fieldValue(
20176 mod,20187 mod,
20177 fields.getIndex(try ip.getOrPutString(gpa, "bits")).?,20188 struct_type.nameIndex(ip, try ip.getOrPutString(gpa, "bits")).?,
20178 );20189 );
2017920190
20180 const signedness = mod.toEnum(std.builtin.Signedness, signedness_val);20191 const signedness = mod.toEnum(std.builtin.Signedness, signedness_val);
...@@ -20183,11 +20194,13 @@ fn zirReify(...@@ -20183,11 +20194,13 @@ fn zirReify(
20183 return Air.internedToRef(ty.toIntern());20194 return Air.internedToRef(ty.toIntern());
20184 },20195 },
20185 .Vector => {20196 .Vector => {
20186 const fields = ip.typeOf(union_val.val).toType().structFields(mod);20197 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20187 const len_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(20198 const len_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20199 ip,
20188 try ip.getOrPutString(gpa, "len"),20200 try ip.getOrPutString(gpa, "len"),
20189 ).?);20201 ).?);
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,
20191 try ip.getOrPutString(gpa, "child"),20204 try ip.getOrPutString(gpa, "child"),
20192 ).?);20205 ).?);
2019320206
...@@ -20203,8 +20216,9 @@ fn zirReify(...@@ -20203,8 +20216,9 @@ fn zirReify(
20203 return Air.internedToRef(ty.toIntern());20216 return Air.internedToRef(ty.toIntern());
20204 },20217 },
20205 .Float => {20218 .Float => {
20206 const fields = ip.typeOf(union_val.val).toType().structFields(mod);20219 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20207 const bits_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(20220 const bits_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20221 ip,
20208 try ip.getOrPutString(gpa, "bits"),20222 try ip.getOrPutString(gpa, "bits"),
20209 ).?);20223 ).?);
2021020224
...@@ -20220,29 +20234,37 @@ fn zirReify(...@@ -20220,29 +20234,37 @@ fn zirReify(
20220 return Air.internedToRef(ty.toIntern());20234 return Air.internedToRef(ty.toIntern());
20221 },20235 },
20222 .Pointer => {20236 .Pointer => {
20223 const fields = ip.typeOf(union_val.val).toType().structFields(mod);20237 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20224 const size_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(20238 const size_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20239 ip,
20225 try ip.getOrPutString(gpa, "size"),20240 try ip.getOrPutString(gpa, "size"),
20226 ).?);20241 ).?);
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,
20228 try ip.getOrPutString(gpa, "is_const"),20244 try ip.getOrPutString(gpa, "is_const"),
20229 ).?);20245 ).?);
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,
20231 try ip.getOrPutString(gpa, "is_volatile"),20248 try ip.getOrPutString(gpa, "is_volatile"),
20232 ).?);20249 ).?);
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,
20234 try ip.getOrPutString(gpa, "alignment"),20252 try ip.getOrPutString(gpa, "alignment"),
20235 ).?);20253 ).?);
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,
20237 try ip.getOrPutString(gpa, "address_space"),20256 try ip.getOrPutString(gpa, "address_space"),
20238 ).?);20257 ).?);
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,
20240 try ip.getOrPutString(gpa, "child"),20260 try ip.getOrPutString(gpa, "child"),
20241 ).?);20261 ).?);
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,
20243 try ip.getOrPutString(gpa, "is_allowzero"),20264 try ip.getOrPutString(gpa, "is_allowzero"),
20244 ).?);20265 ).?);
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,
20246 try ip.getOrPutString(gpa, "sentinel"),20268 try ip.getOrPutString(gpa, "sentinel"),
20247 ).?);20269 ).?);
2024820270
...@@ -20307,7 +20329,7 @@ fn zirReify(...@@ -20307,7 +20329,7 @@ fn zirReify(
20307 }20329 }
20308 }20330 }
2030920331
20310 const ty = try mod.ptrType(.{20332 const ty = try sema.ptrType(.{
20311 .child = elem_ty.toIntern(),20333 .child = elem_ty.toIntern(),
20312 .sentinel = actual_sentinel,20334 .sentinel = actual_sentinel,
20313 .flags = .{20335 .flags = .{
...@@ -20322,14 +20344,17 @@ fn zirReify(...@@ -20322,14 +20344,17 @@ fn zirReify(
20322 return Air.internedToRef(ty.toIntern());20344 return Air.internedToRef(ty.toIntern());
20323 },20345 },
20324 .Array => {20346 .Array => {
20325 const fields = ip.typeOf(union_val.val).toType().structFields(mod);20347 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20326 const len_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(20348 const len_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20349 ip,
20327 try ip.getOrPutString(gpa, "len"),20350 try ip.getOrPutString(gpa, "len"),
20328 ).?);20351 ).?);
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,
20330 try ip.getOrPutString(gpa, "child"),20354 try ip.getOrPutString(gpa, "child"),
20331 ).?);20355 ).?);
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,
20333 try ip.getOrPutString(gpa, "sentinel"),20358 try ip.getOrPutString(gpa, "sentinel"),
20334 ).?);20359 ).?);
2033520360
...@@ -20348,8 +20373,9 @@ fn zirReify(...@@ -20348,8 +20373,9 @@ fn zirReify(
20348 return Air.internedToRef(ty.toIntern());20373 return Air.internedToRef(ty.toIntern());
20349 },20374 },
20350 .Optional => {20375 .Optional => {
20351 const fields = ip.typeOf(union_val.val).toType().structFields(mod);20376 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20352 const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(20377 const child_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20378 ip,
20353 try ip.getOrPutString(gpa, "child"),20379 try ip.getOrPutString(gpa, "child"),
20354 ).?);20380 ).?);
2035520381
...@@ -20359,11 +20385,13 @@ fn zirReify(...@@ -20359,11 +20385,13 @@ fn zirReify(
20359 return Air.internedToRef(ty.toIntern());20385 return Air.internedToRef(ty.toIntern());
20360 },20386 },
20361 .ErrorUnion => {20387 .ErrorUnion => {
20362 const fields = ip.typeOf(union_val.val).toType().structFields(mod);20388 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20363 const error_set_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(20389 const error_set_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20390 ip,
20364 try ip.getOrPutString(gpa, "error_set"),20391 try ip.getOrPutString(gpa, "error_set"),
20365 ).?);20392 ).?);
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,
20367 try ip.getOrPutString(gpa, "payload"),20395 try ip.getOrPutString(gpa, "payload"),
20368 ).?);20396 ).?);
2036920397
...@@ -20386,8 +20414,9 @@ fn zirReify(...@@ -20386,8 +20414,9 @@ fn zirReify(
20386 try names.ensureUnusedCapacity(sema.arena, len);20414 try names.ensureUnusedCapacity(sema.arena, len);
20387 for (0..len) |i| {20415 for (0..len) |i| {
20388 const elem_val = try payload_val.elemValue(mod, i);20416 const elem_val = try payload_val.elemValue(mod, i);
20389 const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod);20417 const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type;
20390 const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex(20418 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
20419 ip,
20391 try ip.getOrPutString(gpa, "name"),20420 try ip.getOrPutString(gpa, "name"),
20392 ).?);20421 ).?);
2039320422
...@@ -20405,20 +20434,25 @@ fn zirReify(...@@ -20405,20 +20434,25 @@ fn zirReify(
20405 return Air.internedToRef(ty.toIntern());20434 return Air.internedToRef(ty.toIntern());
20406 },20435 },
20407 .Struct => {20436 .Struct => {
20408 const fields = ip.typeOf(union_val.val).toType().structFields(mod);20437 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20409 const layout_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(20438 const layout_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20439 ip,
20410 try ip.getOrPutString(gpa, "layout"),20440 try ip.getOrPutString(gpa, "layout"),
20411 ).?);20441 ).?);
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,
20413 try ip.getOrPutString(gpa, "backing_integer"),20444 try ip.getOrPutString(gpa, "backing_integer"),
20414 ).?);20445 ).?);
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,
20416 try ip.getOrPutString(gpa, "fields"),20448 try ip.getOrPutString(gpa, "fields"),
20417 ).?);20449 ).?);
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,
20419 try ip.getOrPutString(gpa, "decls"),20452 try ip.getOrPutString(gpa, "decls"),
20420 ).?);20453 ).?);
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,
20422 try ip.getOrPutString(gpa, "is_tuple"),20456 try ip.getOrPutString(gpa, "is_tuple"),
20423 ).?);20457 ).?);
2042420458
...@@ -20436,17 +20470,21 @@ fn zirReify(...@@ -20436,17 +20470,21 @@ fn zirReify(
20436 return try sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_val, name_strategy, is_tuple_val.toBool());20470 return try sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_val, name_strategy, is_tuple_val.toBool());
20437 },20471 },
20438 .Enum => {20472 .Enum => {
20439 const fields = ip.typeOf(union_val.val).toType().structFields(mod);20473 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20440 const tag_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(20474 const tag_type_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20475 ip,
20441 try ip.getOrPutString(gpa, "tag_type"),20476 try ip.getOrPutString(gpa, "tag_type"),
20442 ).?);20477 ).?);
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,
20444 try ip.getOrPutString(gpa, "fields"),20480 try ip.getOrPutString(gpa, "fields"),
20445 ).?);20481 ).?);
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,
20447 try ip.getOrPutString(gpa, "decls"),20484 try ip.getOrPutString(gpa, "decls"),
20448 ).?);20485 ).?);
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,
20450 try ip.getOrPutString(gpa, "is_exhaustive"),20488 try ip.getOrPutString(gpa, "is_exhaustive"),
20451 ).?);20489 ).?);
2045220490
...@@ -20496,11 +20534,13 @@ fn zirReify(...@@ -20496,11 +20534,13 @@ fn zirReify(
2049620534
20497 for (0..fields_len) |field_i| {20535 for (0..fields_len) |field_i| {
20498 const elem_val = try fields_val.elemValue(mod, field_i);20536 const elem_val = try fields_val.elemValue(mod, field_i);
20499 const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod);20537 const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type;
20500 const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex(20538 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
20539 ip,
20501 try ip.getOrPutString(gpa, "name"),20540 try ip.getOrPutString(gpa, "name"),
20502 ).?);20541 ).?);
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,
20504 try ip.getOrPutString(gpa, "value"),20544 try ip.getOrPutString(gpa, "value"),
20505 ).?);20545 ).?);
2050620546
...@@ -20515,7 +20555,7 @@ fn zirReify(...@@ -20515,7 +20555,7 @@ fn zirReify(
20515 });20555 });
20516 }20556 }
2051720557
20518 if (try incomplete_enum.addFieldName(ip, gpa, field_name)) |other_index| {20558 if (incomplete_enum.addFieldName(ip, field_name)) |other_index| {
20519 const msg = msg: {20559 const msg = msg: {
20520 const msg = try sema.errMsg(block, src, "duplicate enum field '{}'", .{20560 const msg = try sema.errMsg(block, src, "duplicate enum field '{}'", .{
20521 field_name.fmt(ip),20561 field_name.fmt(ip),
...@@ -20528,7 +20568,7 @@ fn zirReify(...@@ -20528,7 +20568,7 @@ fn zirReify(
20528 return sema.failWithOwnedErrorMsg(block, msg);20568 return sema.failWithOwnedErrorMsg(block, msg);
20529 }20569 }
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| {
20532 const msg = msg: {20572 const msg = msg: {
20533 const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{value_val.fmtValue(Type.comptime_int, mod)});20573 const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{value_val.fmtValue(Type.comptime_int, mod)});
20534 errdefer msg.destroy(gpa);20574 errdefer msg.destroy(gpa);
...@@ -20545,8 +20585,9 @@ fn zirReify(...@@ -20545,8 +20585,9 @@ fn zirReify(
20545 return decl_val;20585 return decl_val;
20546 },20586 },
20547 .Opaque => {20587 .Opaque => {
20548 const fields = ip.typeOf(union_val.val).toType().structFields(mod);20588 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20549 const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(20589 const decls_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20590 ip,
20550 try ip.getOrPutString(gpa, "decls"),20591 try ip.getOrPutString(gpa, "decls"),
20551 ).?);20592 ).?);
2055220593
...@@ -20594,17 +20635,21 @@ fn zirReify(...@@ -20594,17 +20635,21 @@ fn zirReify(
20594 return decl_val;20635 return decl_val;
20595 },20636 },
20596 .Union => {20637 .Union => {
20597 const fields = ip.typeOf(union_val.val).toType().structFields(mod);20638 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20598 const layout_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(20639 const layout_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20640 ip,
20599 try ip.getOrPutString(gpa, "layout"),20641 try ip.getOrPutString(gpa, "layout"),
20600 ).?);20642 ).?);
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,
20602 try ip.getOrPutString(gpa, "tag_type"),20645 try ip.getOrPutString(gpa, "tag_type"),
20603 ).?);20646 ).?);
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,
20605 try ip.getOrPutString(gpa, "fields"),20649 try ip.getOrPutString(gpa, "fields"),
20606 ).?);20650 ).?);
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,
20608 try ip.getOrPutString(gpa, "decls"),20653 try ip.getOrPutString(gpa, "decls"),
20609 ).?);20654 ).?);
2061020655
...@@ -20644,14 +20689,17 @@ fn zirReify(...@@ -20644,14 +20689,17 @@ fn zirReify(
2064420689
20645 for (0..fields_len) |i| {20690 for (0..fields_len) |i| {
20646 const elem_val = try fields_val.elemValue(mod, i);20691 const elem_val = try fields_val.elemValue(mod, i);
20647 const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod);20692 const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type;
20648 const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex(20693 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
20694 ip,
20649 try ip.getOrPutString(gpa, "name"),20695 try ip.getOrPutString(gpa, "name"),
20650 ).?);20696 ).?);
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,
20652 try ip.getOrPutString(gpa, "type"),20699 try ip.getOrPutString(gpa, "type"),
20653 ).?);20700 ).?);
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,
20655 try ip.getOrPutString(gpa, "alignment"),20703 try ip.getOrPutString(gpa, "alignment"),
20656 ).?);20704 ).?);
2065720705
...@@ -20812,23 +20860,29 @@ fn zirReify(...@@ -20812,23 +20860,29 @@ fn zirReify(
20812 return decl_val;20860 return decl_val;
20813 },20861 },
20814 .Fn => {20862 .Fn => {
20815 const fields = ip.typeOf(union_val.val).toType().structFields(mod);20863 const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
20816 const calling_convention_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(20864 const calling_convention_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex(
20865 ip,
20817 try ip.getOrPutString(gpa, "calling_convention"),20866 try ip.getOrPutString(gpa, "calling_convention"),
20818 ).?);20867 ).?);
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,
20820 try ip.getOrPutString(gpa, "alignment"),20870 try ip.getOrPutString(gpa, "alignment"),
20821 ).?);20871 ).?);
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,
20823 try ip.getOrPutString(gpa, "is_generic"),20874 try ip.getOrPutString(gpa, "is_generic"),
20824 ).?);20875 ).?);
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,
20826 try ip.getOrPutString(gpa, "is_var_args"),20878 try ip.getOrPutString(gpa, "is_var_args"),
20827 ).?);20879 ).?);
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,
20829 try ip.getOrPutString(gpa, "return_type"),20882 try ip.getOrPutString(gpa, "return_type"),
20830 ).?);20883 ).?);
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,
20832 try ip.getOrPutString(gpa, "params"),20886 try ip.getOrPutString(gpa, "params"),
20833 ).?);20887 ).?);
2083420888
...@@ -20844,15 +20898,9 @@ fn zirReify(...@@ -20844,15 +20898,9 @@ fn zirReify(
20844 }20898 }
2084520899
20846 const alignment = alignment: {20900 const alignment = alignment: {
20847 if (!try sema.intFitsInType(alignment_val, Type.u32, null)) {20901 const alignment = try sema.validateAlignAllowZero(block, src, alignment_val.toUnsignedInt(mod));
20848 return sema.fail(block, src, "alignment must fit in 'u32'", .{});20902 const default = target_util.defaultFunctionAlignment(target);
20849 }20903 break :alignment if (alignment == default) .none else alignment;
20850 const alignment: u29 = @intCast(alignment_val.toUnsignedInt(mod));
20851 if (alignment == target_util.defaultFunctionAlignment(target)) {
20852 break :alignment .none;
20853 } else {
20854 break :alignment Alignment.fromByteUnits(alignment);
20855 }
20856 };20904 };
20857 const return_type = return_type_val.optionalValue(mod) orelse20905 const return_type = return_type_val.optionalValue(mod) orelse
20858 return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{});20906 return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{});
...@@ -20863,14 +20911,17 @@ fn zirReify(...@@ -20863,14 +20911,17 @@ fn zirReify(
20863 var noalias_bits: u32 = 0;20911 var noalias_bits: u32 = 0;
20864 for (param_types, 0..) |*param_type, i| {20912 for (param_types, 0..) |*param_type, i| {
20865 const elem_val = try params_val.elemValue(mod, i);20913 const elem_val = try params_val.elemValue(mod, i);
20866 const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod);20914 const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type;
20867 const param_is_generic_val = try elem_val.fieldValue(mod, elem_fields.getIndex(20915 const param_is_generic_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
20916 ip,
20868 try ip.getOrPutString(gpa, "is_generic"),20917 try ip.getOrPutString(gpa, "is_generic"),
20869 ).?);20918 ).?);
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,
20871 try ip.getOrPutString(gpa, "is_noalias"),20921 try ip.getOrPutString(gpa, "is_noalias"),
20872 ).?);20922 ).?);
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,
20874 try ip.getOrPutString(gpa, "type"),20925 try ip.getOrPutString(gpa, "type"),
20875 ).?);20926 ).?);
2087620927
...@@ -20931,6 +20982,8 @@ fn reifyStruct(...@@ -20931,6 +20982,8 @@ fn reifyStruct(
20931 .Auto => {},20982 .Auto => {},
20932 };20983 };
2093320984
20985 const fields_len: u32 = @intCast(try sema.usizeCast(block, src, fields_val.sliceLen(mod)));
20986
20934 // Because these three things each reference each other, `undefined`20987 // Because these three things each reference each other, `undefined`
20935 // placeholders are used before being set after the struct type gains an20988 // placeholders are used before being set after the struct type gains an
20936 // InternPool index.20989 // InternPool index.
...@@ -20946,58 +20999,52 @@ fn reifyStruct(...@@ -20946,58 +20999,52 @@ fn reifyStruct(
20946 mod.abortAnonDecl(new_decl_index);20999 mod.abortAnonDecl(new_decl_index);
20947 }21000 }
2094821001
20949 const new_namespace_index = try mod.createNamespace(.{21002 const ty = try ip.getStructType(gpa, .{
20950 .parent = block.namespace.toOptional(),21003 .decl = new_decl_index,
20951 .ty = undefined,21004 .namespace = .none,
20952 .file_scope = block.getFileScope(mod),
20953 });
20954 const new_namespace = mod.namespacePtr(new_namespace_index);
20955 errdefer mod.destroyNamespace(new_namespace_index);
20956
20957 const struct_index = try mod.createStruct(.{
20958 .owner_decl = new_decl_index,
20959 .fields = .{},
20960 .zir_index = inst,21005 .zir_index = inst,
20961 .layout = layout,21006 .layout = layout,
20962 .status = .have_field_types,
20963 .known_non_opv = false,21007 .known_non_opv = false,
21008 .fields_len = fields_len,
21009 .requires_comptime = .unknown,
20964 .is_tuple = is_tuple,21010 .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,
20966 });21018 });
20967 const struct_obj = mod.structPtr(struct_index);
20968 errdefer mod.destroyStruct(struct_index);
20969
20970 const struct_ty = try ip.get(gpa, .{ .struct_type = .{
20971 .index = struct_index.toOptional(),
20972 .namespace = new_namespace_index.toOptional(),
20973 } });
20974 // TODO: figure out InternPool removals for incremental compilation21019 // 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
20977 new_decl.ty = Type.type;21023 new_decl.ty = Type.type;
20978 new_decl.val = struct_ty.toValue();21024 new_decl.val = ty.toValue();
20979 new_namespace.ty = struct_ty.toType();
2098021025
20981 // Fields21026 // Fields
20982 const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod));21027 for (0..fields_len) |i| {
20983 try struct_obj.fields.ensureTotalCapacity(mod.tmp_hack_arena.allocator(), fields_len);
20984 var i: usize = 0;
20985 while (i < fields_len) : (i += 1) {
20986 const elem_val = try fields_val.elemValue(mod, i);21028 const elem_val = try fields_val.elemValue(mod, i);
20987 const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod);21029 const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type;
20988 const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex(21030 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21031 ip,
20989 try ip.getOrPutString(gpa, "name"),21032 try ip.getOrPutString(gpa, "name"),
20990 ).?);21033 ).?);
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,
20992 try ip.getOrPutString(gpa, "type"),21036 try ip.getOrPutString(gpa, "type"),
20993 ).?);21037 ).?);
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,
20995 try ip.getOrPutString(gpa, "default_value"),21040 try ip.getOrPutString(gpa, "default_value"),
20996 ).?);21041 ).?);
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,
20998 try ip.getOrPutString(gpa, "is_comptime"),21044 try ip.getOrPutString(gpa, "is_comptime"),
20999 ).?);21045 ).?);
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,
21001 try ip.getOrPutString(gpa, "alignment"),21048 try ip.getOrPutString(gpa, "alignment"),
21002 ).?);21049 ).?);
2100321050
...@@ -21009,6 +21056,8 @@ fn reifyStruct(...@@ -21009,6 +21056,8 @@ fn reifyStruct(
21009 if (layout == .Packed) {21056 if (layout == .Packed) {
21010 if (abi_align != 0) return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{});21057 if (abi_align != 0) return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{});
21011 if (is_comptime_val.toBool()) return sema.fail(block, src, "packed struct fields cannot be marked comptime", .{});21058 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);
21012 }21061 }
21013 if (layout == .Extern and is_comptime_val.toBool()) {21062 if (layout == .Extern and is_comptime_val.toBool()) {
21014 return sema.fail(block, src, "extern struct fields cannot be marked comptime", .{});21063 return sema.fail(block, src, "extern struct fields cannot be marked comptime", .{});
...@@ -21032,10 +21081,8 @@ fn reifyStruct(...@@ -21032,10 +21081,8 @@ fn reifyStruct(
21032 .{field_index},21081 .{field_index},
21033 );21082 );
21034 }21083 }
21035 }21084 } else if (struct_type.addFieldName(ip, field_name)) |prev_index| {
21036 const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);21085 _ = prev_index; // TODO: better source location
21037 if (gop.found_existing) {
21038 // TODO: better source location
21039 return sema.fail(block, src, "duplicate struct field {}", .{field_name.fmt(ip)});21086 return sema.fail(block, src, "duplicate struct field {}", .{field_name.fmt(ip)});
21040 }21087 }
2104121088
...@@ -21051,13 +21098,10 @@ fn reifyStruct(...@@ -21051,13 +21098,10 @@ fn reifyStruct(
21051 return sema.fail(block, src, "comptime field without default initialization value", .{});21098 return sema.fail(block, src, "comptime field without default initialization value", .{});
21052 }21099 }
2105321100
21054 gop.value_ptr.* = .{21101 struct_type.field_types.get(ip)[i] = field_ty.toIntern();
21055 .ty = field_ty,21102 struct_type.field_inits.get(ip)[i] = default_val;
21056 .abi_align = Alignment.fromByteUnits(abi_align),21103 if (is_comptime_val.toBool())
21057 .default_val = default_val,21104 struct_type.setFieldComptime(ip, i);
21058 .is_comptime = is_comptime_val.toBool(),
21059 .offset = undefined,
21060 };
2106121105
21062 if (field_ty.zigTypeTag(mod) == .Opaque) {21106 if (field_ty.zigTypeTag(mod) == .Opaque) {
21063 const msg = msg: {21107 const msg = msg: {
...@@ -21079,7 +21123,7 @@ fn reifyStruct(...@@ -21079,7 +21123,7 @@ fn reifyStruct(
21079 };21123 };
21080 return sema.failWithOwnedErrorMsg(block, msg);21124 return sema.failWithOwnedErrorMsg(block, msg);
21081 }21125 }
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)) {
21083 const msg = msg: {21127 const msg = msg: {
21084 const msg = try sema.errMsg(block, src, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});21128 const msg = try sema.errMsg(block, src, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
21085 errdefer msg.destroy(gpa);21129 errdefer msg.destroy(gpa);
...@@ -21091,7 +21135,7 @@ fn reifyStruct(...@@ -21091,7 +21135,7 @@ fn reifyStruct(
21091 break :msg msg;21135 break :msg msg;
21092 };21136 };
21093 return sema.failWithOwnedErrorMsg(block, msg);21137 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))) {
21095 const msg = msg: {21139 const msg = msg: {
21096 const msg = try sema.errMsg(block, src, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});21140 const msg = try sema.errMsg(block, src, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
21097 errdefer msg.destroy(gpa);21141 errdefer msg.destroy(gpa);
...@@ -21107,13 +21151,12 @@ fn reifyStruct(...@@ -21107,13 +21151,12 @@ fn reifyStruct(
21107 }21151 }
2110821152
21109 if (layout == .Packed) {21153 if (layout == .Packed) {
21110 struct_obj.status = .layout_wip;21154 for (0..struct_type.field_types.len) |index| {
2111121155 const field_ty = struct_type.field_types.get(ip)[index].toType();
21112 for (struct_obj.fields.values(), 0..) |field, index| {21156 sema.resolveTypeLayout(field_ty) catch |err| switch (err) {
21113 sema.resolveTypeLayout(field.ty) catch |err| switch (err) {
21114 error.AnalysisFail => {21157 error.AnalysisFail => {
21115 const msg = sema.err orelse return err;21158 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", .{});
21117 return err;21160 return err;
21118 },21161 },
21119 else => return err,21162 else => return err,
...@@ -21121,19 +21164,18 @@ fn reifyStruct(...@@ -21121,19 +21164,18 @@ fn reifyStruct(
21121 }21164 }
2112221165
21123 var fields_bit_sum: u64 = 0;21166 var fields_bit_sum: u64 = 0;
21124 for (struct_obj.fields.values()) |field| {21167 for (struct_type.field_types.get(ip)) |field_ty| {
21125 fields_bit_sum += field.ty.bitSize(mod);21168 fields_bit_sum += field_ty.toType().bitSize(mod);
21126 }21169 }
2112721170
21128 if (backing_int_val.optionalValue(mod)) |payload| {21171 if (backing_int_val.optionalValue(mod)) |backing_int_ty_val| {
21129 const backing_int_ty = payload.toType();21172 const backing_int_ty = backing_int_ty_val.toType();
21130 try sema.checkBackingIntType(block, src, backing_int_ty, fields_bit_sum);21173 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();
21132 } else {21175 } 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();
21134 }21178 }
21135
21136 struct_obj.status = .have_layout;
21137 }21179 }
2113821180
21139 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);21181 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!...@@ -21439,8 +21481,9 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
21439 const is_non_zero = try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize);21481 const is_non_zero = try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize);
21440 try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null);21482 try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null);
21441 }21483 }
21442 if (ptr_align > 1) {21484 if (ptr_align.compare(.gt, .@"1")) {
21443 const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, ptr_align - 1)).toIntern());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());
21444 const remainder = try block.addBinOp(.bit_and, operand_coerced, align_minus_1);21487 const remainder = try block.addBinOp(.bit_and, operand_coerced, align_minus_1);
21445 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);21488 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
21446 try sema.addSafetyCheck(block, src, is_aligned, .incorrect_alignment);21489 try sema.addSafetyCheck(block, src, is_aligned, .incorrect_alignment);
...@@ -21458,8 +21501,9 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -21458,8 +21501,9 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
21458 const is_non_zero = try block.addBinOp(.cmp_neq, elem_coerced, .zero_usize);21501 const is_non_zero = try block.addBinOp(.cmp_neq, elem_coerced, .zero_usize);
21459 try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null);21502 try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null);
21460 }21503 }
21461 if (ptr_align > 1) {21504 if (ptr_align.compare(.gt, .@"1")) {
21462 const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, ptr_align - 1)).toIntern());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());
21463 const remainder = try block.addBinOp(.bit_and, elem_coerced, align_minus_1);21507 const remainder = try block.addBinOp(.bit_and, elem_coerced, align_minus_1);
21464 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);21508 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
21465 try sema.addSafetyCheck(block, src, is_aligned, .incorrect_alignment);21509 try sema.addSafetyCheck(block, src, is_aligned, .incorrect_alignment);
...@@ -21476,12 +21520,19 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -21476,12 +21520,19 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
21476 return block.addAggregateInit(dest_ty, new_elems);21520 return block.addAggregateInit(dest_ty, new_elems);
21477}21521}
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 {
21480 const mod = sema.mod;21531 const mod = sema.mod;
21481 const addr = operand_val.toUnsignedInt(mod);21532 const addr = operand_val.toUnsignedInt(mod);
21482 if (!ptr_ty.isAllowzeroPtr(mod) and addr == 0)21533 if (!ptr_ty.isAllowzeroPtr(mod) and addr == 0)
21483 return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{ptr_ty.fmt(sema.mod)});21534 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))
21485 return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{ptr_ty.fmt(sema.mod)});21536 return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{ptr_ty.fmt(sema.mod)});
2148621537
21487 return switch (ptr_ty.zigTypeTag(mod)) {21538 return switch (ptr_ty.zigTypeTag(mod)) {
...@@ -21795,18 +21846,26 @@ fn ptrCastFull(...@@ -21795,18 +21846,26 @@ fn ptrCastFull(
21795 // TODO: vector index?21846 // TODO: vector index?
21796 }21847 }
2179721848
21798 const src_align = src_info.flags.alignment.toByteUnitsOptional() orelse src_info.child.toType().abiAlignment(mod);21849 const src_align = if (src_info.flags.alignment != .none)
21799 const dest_align = dest_info.flags.alignment.toByteUnitsOptional() orelse dest_info.child.toType().abiAlignment(mod);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
21800 if (!flags.align_cast) {21859 if (!flags.align_cast) {
21801 if (dest_align > src_align) {21860 if (dest_align.compare(.gt, src_align)) {
21802 return sema.failWithOwnedErrorMsg(block, msg: {21861 return sema.failWithOwnedErrorMsg(block, msg: {
21803 const msg = try sema.errMsg(block, src, "cast increases pointer alignment", .{});21862 const msg = try sema.errMsg(block, src, "cast increases pointer alignment", .{});
21804 errdefer msg.destroy(sema.gpa);21863 errdefer msg.destroy(sema.gpa);
21805 try sema.errNote(block, operand_src, msg, "'{}' has alignment '{d}'", .{21864 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),
21807 });21866 });
21808 try sema.errNote(block, src, msg, "'{}' has alignment '{d}'", .{21867 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),
21810 });21869 });
21811 try sema.errNote(block, src, msg, "use @alignCast to assert pointer alignment", .{});21870 try sema.errNote(block, src, msg, "use @alignCast to assert pointer alignment", .{});
21812 break :msg msg;21871 break :msg msg;
...@@ -21874,7 +21933,7 @@ fn ptrCastFull(...@@ -21874,7 +21933,7 @@ fn ptrCastFull(
21874 // Only convert to a many-pointer at first21933 // Only convert to a many-pointer at first
21875 var info = dest_info;21934 var info = dest_info;
21876 info.flags.size = .Many;21935 info.flags.size = .Many;
21877 const ty = try mod.ptrType(info);21936 const ty = try sema.ptrType(info);
21878 if (dest_ty.zigTypeTag(mod) == .Optional) {21937 if (dest_ty.zigTypeTag(mod) == .Optional) {
21879 break :blk try mod.optionalType(ty.toIntern());21938 break :blk try mod.optionalType(ty.toIntern());
21880 } else {21939 } else {
...@@ -21891,10 +21950,13 @@ fn ptrCastFull(...@@ -21891,10 +21950,13 @@ fn ptrCastFull(
21891 if (!dest_ty.ptrAllowsZero(mod) and ptr_val.isNull(mod)) {21950 if (!dest_ty.ptrAllowsZero(mod) and ptr_val.isNull(mod)) {
21892 return sema.fail(block, operand_src, "null pointer casted to type '{}'", .{dest_ty.fmt(mod)});21951 return sema.fail(block, operand_src, "null pointer casted to type '{}'", .{dest_ty.fmt(mod)});
21893 }21952 }
21894 if (dest_align > src_align) {21953 if (dest_align.compare(.gt, src_align)) {
21895 if (try ptr_val.getUnsignedIntAdvanced(mod, null)) |addr| {21954 if (try ptr_val.getUnsignedIntAdvanced(mod, null)) |addr| {
21896 if (addr % dest_align != 0) {21955 if (!dest_align.check(addr)) {
21897 return sema.fail(block, operand_src, "pointer address 0x{X} is not aligned to {d} bytes", .{ addr, dest_align });21956 return sema.fail(block, operand_src, "pointer address 0x{X} is not aligned to {d} bytes", .{
21957 addr,
21958 dest_align.toByteUnitsOptional().?,
21959 });
21898 }21960 }
21899 }21961 }
21900 }21962 }
...@@ -21928,8 +21990,12 @@ fn ptrCastFull(...@@ -21928,8 +21990,12 @@ fn ptrCastFull(
21928 try sema.addSafetyCheck(block, src, ok, .cast_to_null);21990 try sema.addSafetyCheck(block, src, ok, .cast_to_null);
21929 }21991 }
2193021992
21931 if (block.wantSafety() and dest_align > src_align and try sema.typeHasRuntimeBits(dest_info.child.toType())) {21993 if (block.wantSafety() and
21932 const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, dest_align - 1)).toIntern());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());
21933 const ptr_int = try block.addUnOp(.int_from_ptr, ptr);21999 const ptr_int = try block.addUnOp(.int_from_ptr, ptr);
21934 const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1);22000 const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1);
21935 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);22001 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
...@@ -21946,7 +22012,7 @@ fn ptrCastFull(...@@ -21946,7 +22012,7 @@ fn ptrCastFull(
21946 // We can't change address spaces with a bitcast, so this requires two instructions22012 // We can't change address spaces with a bitcast, so this requires two instructions
21947 var intermediate_info = src_info;22013 var intermediate_info = src_info;
21948 intermediate_info.flags.address_space = dest_info.flags.address_space;22014 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);
21950 const intermediate_ty = if (dest_ptr_ty.zigTypeTag(mod) == .Optional) blk: {22016 const intermediate_ty = if (dest_ptr_ty.zigTypeTag(mod) == .Optional) blk: {
21951 break :blk try mod.optionalType(intermediate_ptr_ty.toIntern());22017 break :blk try mod.optionalType(intermediate_ptr_ty.toIntern());
21952 } else intermediate_ptr_ty;22018 } else intermediate_ptr_ty;
...@@ -22002,7 +22068,7 @@ fn zirPtrCastNoDest(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst...@@ -22002,7 +22068,7 @@ fn zirPtrCastNoDest(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst
22002 var ptr_info = operand_ty.ptrInfo(mod);22068 var ptr_info = operand_ty.ptrInfo(mod);
22003 if (flags.const_cast) ptr_info.flags.is_const = false;22069 if (flags.const_cast) ptr_info.flags.is_const = false;
22004 if (flags.volatile_cast) ptr_info.flags.is_volatile = false;22070 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
22007 if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {22073 if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
22008 return Air.internedToRef((try mod.getCoerced(operand_val, dest_ty)).toIntern());22074 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...@@ -22285,6 +22351,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6
22285 });22351 });
2228622352
22287 const mod = sema.mod;22353 const mod = sema.mod;
22354 const ip = &mod.intern_pool;
22288 try sema.resolveTypeLayout(ty);22355 try sema.resolveTypeLayout(ty);
22289 switch (ty.zigTypeTag(mod)) {22356 switch (ty.zigTypeTag(mod)) {
22290 .Struct => {},22357 .Struct => {},
...@@ -22300,7 +22367,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6...@@ -22300,7 +22367,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6
22300 }22367 }
2230122368
22302 const field_index = if (ty.isTuple(mod)) blk: {22369 const field_index = if (ty.isTuple(mod)) blk: {
22303 if (mod.intern_pool.stringEqlSlice(field_name, "len")) {22370 if (ip.stringEqlSlice(field_name, "len")) {
22304 return sema.fail(block, src, "no offset available for 'len' field of tuple", .{});22371 return sema.fail(block, src, "no offset available for 'len' field of tuple", .{});
22305 }22372 }
22306 break :blk try sema.tupleFieldIndex(block, ty, field_name, rhs_src);22373 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...@@ -22313,12 +22380,13 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6
22313 switch (ty.containerLayout(mod)) {22380 switch (ty.containerLayout(mod)) {
22314 .Packed => {22381 .Packed => {
22315 var bit_sum: u64 = 0;22382 var bit_sum: u64 = 0;
22316 const fields = ty.structFields(mod);22383 const struct_type = ip.indexToKey(ty.toIntern()).struct_type;
22317 for (fields.values(), 0..) |field, i| {22384 for (0..struct_type.field_types.len) |i| {
22318 if (i == field_index) {22385 if (i == field_index) {
22319 return bit_sum;22386 return bit_sum;
22320 }22387 }
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);
22322 } else unreachable;22390 } else unreachable;
22323 },22391 },
22324 else => return ty.structFieldOffset(field_index, mod) * 8,22392 else => return ty.structFieldOffset(field_index, mod) * 8,
...@@ -22535,7 +22603,7 @@ fn checkAtomicPtrOperand(...@@ -22535,7 +22603,7 @@ fn checkAtomicPtrOperand(
22535 const ptr_data = switch (try ptr_ty.zigTypeTagOrPoison(mod)) {22603 const ptr_data = switch (try ptr_ty.zigTypeTagOrPoison(mod)) {
22536 .Pointer => ptr_ty.ptrInfo(mod),22604 .Pointer => ptr_ty.ptrInfo(mod),
22537 else => {22605 else => {
22538 const wanted_ptr_ty = try mod.ptrType(wanted_ptr_data);22606 const wanted_ptr_ty = try sema.ptrType(wanted_ptr_data);
22539 _ = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src);22607 _ = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src);
22540 unreachable;22608 unreachable;
22541 },22609 },
...@@ -22545,7 +22613,7 @@ fn checkAtomicPtrOperand(...@@ -22545,7 +22613,7 @@ fn checkAtomicPtrOperand(
22545 wanted_ptr_data.flags.is_allowzero = ptr_data.flags.is_allowzero;22613 wanted_ptr_data.flags.is_allowzero = ptr_data.flags.is_allowzero;
22546 wanted_ptr_data.flags.is_volatile = ptr_data.flags.is_volatile;22614 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);
22549 const casted_ptr = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src);22617 const casted_ptr = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src);
2255022618
22551 return casted_ptr;22619 return casted_ptr;
...@@ -23717,8 +23785,8 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -23717,8 +23785,8 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
23717 return sema.fail(block, src, "TODO handle packed structs/unions with @fieldParentPtr", .{});23785 return sema.fail(block, src, "TODO handle packed structs/unions with @fieldParentPtr", .{});
23718 } else {23786 } else {
23719 ptr_ty_data.flags.alignment = blk: {23787 ptr_ty_data.flags.alignment = blk: {
23720 if (mod.typeToStruct(parent_ty)) |struct_obj| {23788 if (mod.typeToStruct(parent_ty)) |struct_type| {
23721 break :blk struct_obj.fields.values()[field_index].abi_align;23789 break :blk struct_type.fieldAlign(ip, field_index);
23722 } else if (mod.typeToUnion(parent_ty)) |union_obj| {23790 } else if (mod.typeToUnion(parent_ty)) |union_obj| {
23723 break :blk union_obj.fieldAlign(ip, field_index);23791 break :blk union_obj.fieldAlign(ip, field_index);
23724 } else {23792 } else {
...@@ -23727,11 +23795,11 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -23727,11 +23795,11 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
23727 };23795 };
23728 }23796 }
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);
23731 const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, ptr_src);23799 const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, ptr_src);
2373223800
23733 ptr_ty_data.child = parent_ty.toIntern();23801 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
23736 if (try sema.resolveDefinedValue(block, src, casted_field_ptr)) |field_ptr_val| {23804 if (try sema.resolveDefinedValue(block, src, casted_field_ptr)) |field_ptr_val| {
23737 const field = switch (ip.indexToKey(field_ptr_val.toIntern())) {23805 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...@@ -24062,7 +24130,7 @@ fn upgradeToArrayPtr(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, len: u64) !A
24062 // Already an array pointer.24130 // Already an array pointer.
24063 return ptr;24131 return ptr;
24064 }24132 }
24065 const new_ty = try mod.ptrType(.{24133 const new_ty = try sema.ptrType(.{
24066 .child = (try mod.arrayType(.{24134 .child = (try mod.arrayType(.{
24067 .len = len,24135 .len = len,
24068 .sentinel = info.sentinel,24136 .sentinel = info.sentinel,
...@@ -24266,7 +24334,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void...@@ -24266,7 +24334,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
24266 assert(dest_manyptr_ty_key.flags.size == .One);24334 assert(dest_manyptr_ty_key.flags.size == .One);
24267 dest_manyptr_ty_key.child = dest_elem_ty.toIntern();24335 dest_manyptr_ty_key.child = dest_elem_ty.toIntern();
24268 dest_manyptr_ty_key.flags.size = .Many;24336 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);
24270 } else new_dest_ptr;24338 } else new_dest_ptr;
2427124339
24272 const new_src_ptr_ty = sema.typeOf(new_src_ptr);24340 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...@@ -24277,7 +24345,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
24277 assert(src_manyptr_ty_key.flags.size == .One);24345 assert(src_manyptr_ty_key.flags.size == .One);
24278 src_manyptr_ty_key.child = src_elem_ty.toIntern();24346 src_manyptr_ty_key.child = src_elem_ty.toIntern();
24279 src_manyptr_ty_key.flags.size = .Many;24347 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);
24281 } else new_src_ptr;24349 } else new_src_ptr;
2428224350
24283 // ok1: dest >= src + len24351 // ok1: dest >= src + len
...@@ -24528,13 +24596,9 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -24528,13 +24596,9 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
24528 if (val.isGenericPoison()) {24596 if (val.isGenericPoison()) {
24529 break :blk null;24597 break :blk null;
24530 }24598 }
24531 const alignment: u32 = @intCast(val.toUnsignedInt(mod));24599 const alignment = try sema.validateAlignAllowZero(block, align_src, val.toUnsignedInt(mod));
24532 try sema.validateAlign(block, align_src, alignment);24600 const default = target_util.defaultFunctionAlignment(target);
24533 if (alignment == target_util.defaultFunctionAlignment(target)) {24601 break :blk if (alignment == default) .none else alignment;
24534 break :blk .none;
24535 } else {
24536 break :blk Alignment.fromNonzeroByteUnits(alignment);
24537 }
24538 } else if (extra.data.bits.has_align_ref) blk: {24602 } else if (extra.data.bits.has_align_ref) blk: {
24539 const align_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);24603 const align_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
24540 extra_index += 1;24604 extra_index += 1;
...@@ -24546,13 +24610,9 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -24546,13 +24610,9 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
24546 },24610 },
24547 else => |e| return e,24611 else => |e| return e,
24548 };24612 };
24549 const alignment: u32 = @intCast(align_tv.val.toUnsignedInt(mod));24613 const alignment = try sema.validateAlignAllowZero(block, align_src, align_tv.val.toUnsignedInt(mod));
24550 try sema.validateAlign(block, align_src, alignment);24614 const default = target_util.defaultFunctionAlignment(target);
24551 if (alignment == target_util.defaultFunctionAlignment(target)) {24615 break :blk if (alignment == default) .none else alignment;
24552 break :blk .none;
24553 } else {
24554 break :blk Alignment.fromNonzeroByteUnits(alignment);
24555 }
24556 } else .none;24616 } else .none;
2455724617
24558 const @"addrspace": ?std.builtin.AddressSpace = if (extra.data.bits.has_addrspace_body) blk: {24618 const @"addrspace": ?std.builtin.AddressSpace = if (extra.data.bits.has_addrspace_body) blk: {
...@@ -25237,16 +25297,17 @@ fn explainWhyTypeIsComptimeInner(...@@ -25237,16 +25297,17 @@ fn explainWhyTypeIsComptimeInner(
25237 .Struct => {25297 .Struct => {
25238 if ((try type_set.getOrPut(sema.gpa, ty.toIntern())).found_existing) return;25298 if ((try type_set.getOrPut(sema.gpa, ty.toIntern())).found_existing) return;
2523925299
25240 if (mod.typeToStruct(ty)) |struct_obj| {25300 if (mod.typeToStruct(ty)) |struct_type| {
25241 for (struct_obj.fields.values(), 0..) |field, i| {25301 for (0..struct_type.field_types.len) |i| {
25242 const field_src_loc = mod.fieldSrcLoc(struct_obj.owner_decl, .{25302 const field_ty = struct_type.field_types.get(ip)[i].toType();
25303 const field_src_loc = mod.fieldSrcLoc(struct_type.decl.unwrap().?, .{
25243 .index = i,25304 .index = i,
25244 .range = .type,25305 .range = .type,
25245 });25306 });
2524625307
25247 if (try sema.typeRequiresComptime(field.ty)) {25308 if (try sema.typeRequiresComptime(field_ty)) {
25248 try mod.errNoteNonLazy(field_src_loc, msg, "struct requires comptime because of this field", .{});25309 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);
25250 }25311 }
25251 }25312 }
25252 }25313 }
...@@ -25515,7 +25576,7 @@ fn prepareSimplePanic(sema: *Sema, block: *Block) !void {...@@ -25515,7 +25576,7 @@ fn prepareSimplePanic(sema: *Sema, block: *Block) !void {
25515 const stack_trace_ty = try sema.getBuiltinType("StackTrace");25576 const stack_trace_ty = try sema.getBuiltinType("StackTrace");
25516 try sema.resolveTypeFields(stack_trace_ty);25577 try sema.resolveTypeFields(stack_trace_ty);
25517 const target = mod.getTarget();25578 const target = mod.getTarget();
25518 const ptr_stack_trace_ty = try mod.ptrType(.{25579 const ptr_stack_trace_ty = try sema.ptrType(.{
25519 .child = stack_trace_ty.toIntern(),25580 .child = stack_trace_ty.toIntern(),
25520 .flags = .{25581 .flags = .{
25521 .address_space = target_util.defaultAddressSpace(target, .global_constant),25582 .address_space = target_util.defaultAddressSpace(target, .global_constant),
...@@ -25867,7 +25928,7 @@ fn fieldVal(...@@ -25867,7 +25928,7 @@ fn fieldVal(
25867 return Air.internedToRef((try mod.intValue(Type.usize, inner_ty.arrayLen(mod))).toIntern());25928 return Air.internedToRef((try mod.intValue(Type.usize, inner_ty.arrayLen(mod))).toIntern());
25868 } else if (ip.stringEqlSlice(field_name, "ptr") and is_pointer_to) {25929 } else if (ip.stringEqlSlice(field_name, "ptr") and is_pointer_to) {
25869 const ptr_info = object_ty.ptrInfo(mod);25930 const ptr_info = object_ty.ptrInfo(mod);
25870 const result_ty = try mod.ptrType(.{25931 const result_ty = try sema.ptrType(.{
25871 .child = ptr_info.child.toType().childType(mod).toIntern(),25932 .child = ptr_info.child.toType().childType(mod).toIntern(),
25872 .sentinel = ptr_info.sentinel,25933 .sentinel = ptr_info.sentinel,
25873 .flags = .{25934 .flags = .{
...@@ -26086,7 +26147,7 @@ fn fieldPtr(...@@ -26086,7 +26147,7 @@ fn fieldPtr(
26086 if (ip.stringEqlSlice(field_name, "ptr")) {26147 if (ip.stringEqlSlice(field_name, "ptr")) {
26087 const slice_ptr_ty = inner_ty.slicePtrFieldType(mod);26148 const slice_ptr_ty = inner_ty.slicePtrFieldType(mod);
2608826149
26089 const result_ty = try mod.ptrType(.{26150 const result_ty = try sema.ptrType(.{
26090 .child = slice_ptr_ty.toIntern(),26151 .child = slice_ptr_ty.toIntern(),
26091 .flags = .{26152 .flags = .{
26092 .is_const = !attr_ptr_ty.ptrIsMutable(mod),26153 .is_const = !attr_ptr_ty.ptrIsMutable(mod),
...@@ -26108,7 +26169,7 @@ fn fieldPtr(...@@ -26108,7 +26169,7 @@ fn fieldPtr(
2610826169
26109 return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr);26170 return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr);
26110 } else if (ip.stringEqlSlice(field_name, "len")) {26171 } else if (ip.stringEqlSlice(field_name, "len")) {
26111 const result_ty = try mod.ptrType(.{26172 const result_ty = try sema.ptrType(.{
26112 .child = .usize_type,26173 .child = .usize_type,
26113 .flags = .{26174 .flags = .{
26114 .is_const = !attr_ptr_ty.ptrIsMutable(mod),26175 .is_const = !attr_ptr_ty.ptrIsMutable(mod),
...@@ -26297,13 +26358,12 @@ fn fieldCallBind(...@@ -26297,13 +26358,12 @@ fn fieldCallBind(
26297 switch (concrete_ty.zigTypeTag(mod)) {26358 switch (concrete_ty.zigTypeTag(mod)) {
26298 .Struct => {26359 .Struct => {
26299 try sema.resolveTypeFields(concrete_ty);26360 try sema.resolveTypeFields(concrete_ty);
26300 if (mod.typeToStruct(concrete_ty)) |struct_obj| {26361 if (mod.typeToStruct(concrete_ty)) |struct_type| {
26301 const field_index_usize = struct_obj.fields.getIndex(field_name) orelse26362 const field_index = struct_type.nameIndex(ip, field_name) orelse
26302 break :find_field;26363 break :find_field;
26303 const field_index: u32 = @intCast(field_index_usize);26364 const field_ty = struct_type.field_types.get(ip)[field_index].toType();
26304 const field = struct_obj.fields.values()[field_index];
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);
26307 } else if (concrete_ty.isTuple(mod)) {26367 } else if (concrete_ty.isTuple(mod)) {
26308 if (ip.stringEqlSlice(field_name, "len")) {26368 if (ip.stringEqlSlice(field_name, "len")) {
26309 return .{ .direct = try mod.intRef(Type.usize, concrete_ty.structFieldCount(mod)) };26369 return .{ .direct = try mod.intRef(Type.usize, concrete_ty.structFieldCount(mod)) };
...@@ -26316,7 +26376,7 @@ fn fieldCallBind(...@@ -26316,7 +26376,7 @@ fn fieldCallBind(
26316 const max = concrete_ty.structFieldCount(mod);26376 const max = concrete_ty.structFieldCount(mod);
26317 for (0..max) |i_usize| {26377 for (0..max) |i_usize| {
26318 const i: u32 = @intCast(i_usize);26378 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().?) {
26320 return sema.finishFieldCallBind(block, src, ptr_ty, concrete_ty.structFieldType(i, mod), i, object_ptr);26380 return sema.finishFieldCallBind(block, src, ptr_ty, concrete_ty.structFieldType(i, mod), i, object_ptr);
26321 }26381 }
26322 }26382 }
...@@ -26434,7 +26494,7 @@ fn finishFieldCallBind(...@@ -26434,7 +26494,7 @@ fn finishFieldCallBind(
26434 object_ptr: Air.Inst.Ref,26494 object_ptr: Air.Inst.Ref,
26435) CompileError!ResolvedFieldCallee {26495) CompileError!ResolvedFieldCallee {
26436 const mod = sema.mod;26496 const mod = sema.mod;
26437 const ptr_field_ty = try mod.ptrType(.{26497 const ptr_field_ty = try sema.ptrType(.{
26438 .child = field_ty.toIntern(),26498 .child = field_ty.toIntern(),
26439 .flags = .{26499 .flags = .{
26440 .is_const = !ptr_ty.ptrIsMutable(mod),26500 .is_const = !ptr_ty.ptrIsMutable(mod),
...@@ -26526,13 +26586,14 @@ fn structFieldPtr(...@@ -26526,13 +26586,14 @@ fn structFieldPtr(
26526 initializing: bool,26586 initializing: bool,
26527) CompileError!Air.Inst.Ref {26587) CompileError!Air.Inst.Ref {
26528 const mod = sema.mod;26588 const mod = sema.mod;
26589 const ip = &mod.intern_pool;
26529 assert(struct_ty.zigTypeTag(mod) == .Struct);26590 assert(struct_ty.zigTypeTag(mod) == .Struct);
2653026591
26531 try sema.resolveTypeFields(struct_ty);26592 try sema.resolveTypeFields(struct_ty);
26532 try sema.resolveStructLayout(struct_ty);26593 try sema.resolveStructLayout(struct_ty);
2653326594
26534 if (struct_ty.isTuple(mod)) {26595 if (struct_ty.isTuple(mod)) {
26535 if (mod.intern_pool.stringEqlSlice(field_name, "len")) {26596 if (ip.stringEqlSlice(field_name, "len")) {
26536 const len_inst = try mod.intRef(Type.usize, struct_ty.structFieldCount(mod));26597 const len_inst = try mod.intRef(Type.usize, struct_ty.structFieldCount(mod));
26537 return sema.analyzeRef(block, src, len_inst);26598 return sema.analyzeRef(block, src, len_inst);
26538 }26599 }
...@@ -26543,11 +26604,10 @@ fn structFieldPtr(...@@ -26543,11 +26604,10 @@ fn structFieldPtr(
26543 return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing);26604 return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing);
26544 }26605 }
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) orelse26609 const field_index = struct_type.nameIndex(ip, field_name) orelse
26549 return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name);26610 return sema.failWithBadStructFieldAccess(block, struct_type, field_name_src, field_name);
26550 const field_index: u32 = @intCast(field_index_big);
2655126611
26552 return sema.structFieldPtrByIndex(block, src, struct_ptr, field_index, field_name_src, struct_ty, initializing);26612 return sema.structFieldPtrByIndex(block, src, struct_ptr, field_index, field_name_src, struct_ty, initializing);
26553}26613}
...@@ -26563,17 +26623,18 @@ fn structFieldPtrByIndex(...@@ -26563,17 +26623,18 @@ fn structFieldPtrByIndex(
26563 initializing: bool,26623 initializing: bool,
26564) CompileError!Air.Inst.Ref {26624) CompileError!Air.Inst.Ref {
26565 const mod = sema.mod;26625 const mod = sema.mod;
26626 const ip = &mod.intern_pool;
26566 if (struct_ty.isAnonStruct(mod)) {26627 if (struct_ty.isAnonStruct(mod)) {
26567 return sema.tupleFieldPtr(block, src, struct_ptr, field_src, field_index, initializing);26628 return sema.tupleFieldPtr(block, src, struct_ptr, field_src, field_index, initializing);
26568 }26629 }
2656926630
26570 const struct_obj = mod.typeToStruct(struct_ty).?;26631 const struct_type = mod.typeToStruct(struct_ty).?;
26571 const field = struct_obj.fields.values()[field_index];26632 const field_ty = struct_type.field_types.get(ip)[field_index];
26572 const struct_ptr_ty = sema.typeOf(struct_ptr);26633 const struct_ptr_ty = sema.typeOf(struct_ptr);
26573 const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(mod);26634 const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(mod);
2657426635
26575 var ptr_ty_data: InternPool.Key.PtrType = .{26636 var ptr_ty_data: InternPool.Key.PtrType = .{
26576 .child = field.ty.toIntern(),26637 .child = field_ty,
26577 .flags = .{26638 .flags = .{
26578 .is_const = struct_ptr_ty_info.flags.is_const,26639 .is_const = struct_ptr_ty_info.flags.is_const,
26579 .is_volatile = struct_ptr_ty_info.flags.is_volatile,26640 .is_volatile = struct_ptr_ty_info.flags.is_volatile,
...@@ -26583,20 +26644,23 @@ fn structFieldPtrByIndex(...@@ -26583,20 +26644,23 @@ fn structFieldPtrByIndex(
2658326644
26584 const target = mod.getTarget();26645 const target = mod.getTarget();
2658526646
26586 const parent_align = struct_ptr_ty_info.flags.alignment.toByteUnitsOptional() orelse26647 const parent_align = if (struct_ptr_ty_info.flags.alignment != .none)
26648 struct_ptr_ty_info.flags.alignment
26649 else
26587 try sema.typeAbiAlignment(struct_ptr_ty_info.child.toType());26650 try sema.typeAbiAlignment(struct_ptr_ty_info.child.toType());
2658826651
26589 if (struct_obj.layout == .Packed) {26652 if (struct_type.layout == .Packed) {
26590 comptime assert(Type.packed_struct_layout_version == 2);26653 comptime assert(Type.packed_struct_layout_version == 2);
2659126654
26592 var running_bits: u16 = 0;26655 var running_bits: u16 = 0;
26593 for (struct_obj.fields.values(), 0..) |f, i| {26656 for (0..struct_type.field_types.len) |i| {
26594 if (!(try sema.typeHasRuntimeBits(f.ty))) continue;26657 const f_ty = struct_type.field_types.get(ip)[i].toType();
26658 if (!(try sema.typeHasRuntimeBits(f_ty))) continue;
2659526659
26596 if (i == field_index) {26660 if (i == field_index) {
26597 ptr_ty_data.packed_offset.bit_offset = running_bits;26661 ptr_ty_data.packed_offset.bit_offset = running_bits;
26598 }26662 }
26599 running_bits += @intCast(f.ty.bitSize(mod));26663 running_bits += @intCast(f_ty.bitSize(mod));
26600 }26664 }
26601 ptr_ty_data.packed_offset.host_size = (running_bits + 7) / 8;26665 ptr_ty_data.packed_offset.host_size = (running_bits + 7) / 8;
2660226666
...@@ -26607,7 +26671,7 @@ fn structFieldPtrByIndex(...@@ -26607,7 +26671,7 @@ fn structFieldPtrByIndex(
26607 ptr_ty_data.packed_offset.bit_offset += struct_ptr_ty_info.packed_offset.bit_offset;26671 ptr_ty_data.packed_offset.bit_offset += struct_ptr_ty_info.packed_offset.bit_offset;
26608 }26672 }
2660926673
26610 ptr_ty_data.flags.alignment = Alignment.fromByteUnits(parent_align);26674 ptr_ty_data.flags.alignment = parent_align;
2661126675
26612 // If the field happens to be byte-aligned, simplify the pointer type.26676 // If the field happens to be byte-aligned, simplify the pointer type.
26613 // The pointee type bit size must match its ABI byte size so that loads and stores26677 // The pointee type bit size must match its ABI byte size so that loads and stores
...@@ -26617,38 +26681,47 @@ fn structFieldPtrByIndex(...@@ -26617,38 +26681,47 @@ fn structFieldPtrByIndex(
26617 // targets before adding the necessary complications to this code. This will not26681 // targets before adding the necessary complications to this code. This will not
26618 // cause miscompilations; it only means the field pointer uses bit masking when it26682 // cause miscompilations; it only means the field pointer uses bit masking when it
26619 // might not be strictly necessary.26683 // might not be strictly necessary.
26620 if (parent_align != 0 and ptr_ty_data.packed_offset.bit_offset % 8 == 0 and26684 if (parent_align != .none and ptr_ty_data.packed_offset.bit_offset % 8 == 0 and
26621 target.cpu.arch.endian() == .Little)26685 target.cpu.arch.endian() == .Little)
26622 {26686 {
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());
26624 const elem_size_bits = ptr_ty_data.child.toType().bitSize(mod);26688 const elem_size_bits = ptr_ty_data.child.toType().bitSize(mod);
26625 if (elem_size_bytes * 8 == elem_size_bits) {26689 if (elem_size_bytes * 8 == elem_size_bits) {
26626 const byte_offset = ptr_ty_data.packed_offset.bit_offset / 8;26690 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().?));
26628 assert(new_align != .none);26692 assert(new_align != .none);
26629 ptr_ty_data.flags.alignment = new_align;26693 ptr_ty_data.flags.alignment = new_align;
26630 ptr_ty_data.packed_offset = .{ .host_size = 0, .bit_offset = 0 };26694 ptr_ty_data.packed_offset = .{ .host_size = 0, .bit_offset = 0 };
26631 }26695 }
26632 }26696 }
26633 } else if (struct_obj.layout == .Extern) {26697 } else if (struct_type.layout == .Extern) {
26634 // For extern structs, field aligment might be bigger than type's natural alignment. Eg, in26698 // For extern structs, field alignment might be bigger than type's
26635 // `extern struct { x: u32, y: u16 }` the second field is aligned as u32.26699 // natural alignment. Eg, in `extern struct { x: u32, y: u16 }` the
26700 // second field is aligned as u32.
26636 const field_offset = struct_ty.structFieldOffset(field_index, mod);26701 const field_offset = struct_ty.structFieldOffset(field_index, mod);
26637 ptr_ty_data.flags.alignment = Alignment.fromByteUnits(26702 ptr_ty_data.flags.alignment = if (parent_align == .none)
26638 if (parent_align == 0) 0 else std.math.gcd(field_offset, parent_align),26703 .none
26639 );26704 else
26705 @enumFromInt(@min(@intFromEnum(parent_align), @ctz(field_offset)));
26640 } else {26706 } else {
26641 // Our alignment is capped at the field alignment26707 // Our alignment is capped at the field alignment.
26642 const field_align = try sema.structFieldAlignment(field, struct_obj.layout);26708 const field_align = try sema.structFieldAlignment(
26643 ptr_ty_data.flags.alignment = Alignment.fromByteUnits(@min(field_align, parent_align));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);
26644 }26717 }
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)) {
26649 const val = try mod.intern(.{ .ptr = .{26722 const val = try mod.intern(.{ .ptr = .{
26650 .ty = ptr_field_ty.toIntern(),26723 .ty = ptr_field_ty.toIntern(),
26651 .addr = .{ .comptime_field = field.default_val },26724 .addr = .{ .comptime_field = struct_type.field_inits.get(ip)[field_index] },
26652 } });26725 } });
26653 return Air.internedToRef(val);26726 return Air.internedToRef(val);
26654 }26727 }
...@@ -26678,33 +26751,34 @@ fn structFieldVal(...@@ -26678,33 +26751,34 @@ fn structFieldVal(
26678 struct_ty: Type,26751 struct_ty: Type,
26679) CompileError!Air.Inst.Ref {26752) CompileError!Air.Inst.Ref {
26680 const mod = sema.mod;26753 const mod = sema.mod;
26754 const ip = &mod.intern_pool;
26681 assert(struct_ty.zigTypeTag(mod) == .Struct);26755 assert(struct_ty.zigTypeTag(mod) == .Struct);
2668226756
26683 try sema.resolveTypeFields(struct_ty);26757 try sema.resolveTypeFields(struct_ty);
26684 switch (mod.intern_pool.indexToKey(struct_ty.toIntern())) {26758 switch (ip.indexToKey(struct_ty.toIntern())) {
26685 .struct_type => |struct_type| {26759 .struct_type => |struct_type| {
26686 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;26760 if (struct_type.isTuple(ip))
26687 if (struct_obj.is_tuple) return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty);26761 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];
2669326762
26694 if (field.is_comptime) {26763 const field_index = struct_type.nameIndex(ip, field_name) orelse
26695 return Air.internedToRef(field.default_val);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]);
26696 }26767 }
2669726768
26769 const field_ty = struct_type.field_types.get(ip)[field_index].toType();
26770
26698 if (try sema.resolveMaybeUndefVal(struct_byval)) |struct_val| {26771 if (try sema.resolveMaybeUndefVal(struct_byval)) |struct_val| {
26699 if (struct_val.isUndef(mod)) return mod.undefRef(field.ty);26772 if (struct_val.isUndef(mod)) return mod.undefRef(field_ty);
26700 if ((try sema.typeHasOnePossibleValue(field.ty))) |opv| {26773 if ((try sema.typeHasOnePossibleValue(field_ty))) |opv| {
26701 return Air.internedToRef(opv.toIntern());26774 return Air.internedToRef(opv.toIntern());
26702 }26775 }
26703 return Air.internedToRef((try struct_val.fieldValue(mod, field_index)).toIntern());26776 return Air.internedToRef((try struct_val.fieldValue(mod, field_index)).toIntern());
26704 }26777 }
2670526778
26706 try sema.requireRuntimeBlock(block, src, null);26779 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);
26708 },26782 },
26709 .anon_struct_type => |anon_struct| {26783 .anon_struct_type => |anon_struct| {
26710 if (anon_struct.names.len == 0) {26784 if (anon_struct.names.len == 0) {
...@@ -26792,6 +26866,7 @@ fn tupleFieldValByIndex(...@@ -26792,6 +26866,7 @@ fn tupleFieldValByIndex(
26792 }26866 }
2679326867
26794 try sema.requireRuntimeBlock(block, src, null);26868 try sema.requireRuntimeBlock(block, src, null);
26869 try sema.resolveTypeLayout(field_ty);
26795 return block.addStructFieldVal(tuple_byval, field_index, field_ty);26870 return block.addStructFieldVal(tuple_byval, field_index, field_ty);
26796}26871}
2679726872
...@@ -26816,16 +26891,19 @@ fn unionFieldPtr(...@@ -26816,16 +26891,19 @@ fn unionFieldPtr(
26816 const union_obj = mod.typeToUnion(union_ty).?;26891 const union_obj = mod.typeToUnion(union_ty).?;
26817 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);26892 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
26818 const field_ty = union_obj.field_types.get(ip)[field_index].toType();26893 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(.{
26820 .child = field_ty.toIntern(),26895 .child = field_ty.toIntern(),
26821 .flags = .{26896 .flags = .{
26822 .is_const = union_ptr_info.flags.is_const,26897 .is_const = union_ptr_info.flags.is_const,
26823 .is_volatile = union_ptr_info.flags.is_volatile,26898 .is_volatile = union_ptr_info.flags.is_volatile,
26824 .address_space = union_ptr_info.flags.address_space,26899 .address_space = union_ptr_info.flags.address_space,
26825 .alignment = if (union_obj.getLayout(ip) == .Auto) blk: {26900 .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);
26827 const field_align = try sema.unionFieldAlignment(union_obj, field_index);26905 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);
26829 } else union_ptr_info.flags.alignment,26907 } else union_ptr_info.flags.alignment,
26830 },26908 },
26831 .packed_offset = union_ptr_info.packed_offset,26909 .packed_offset = union_ptr_info.packed_offset,
...@@ -26970,6 +27048,7 @@ fn unionFieldVal(...@@ -26970,6 +27048,7 @@ fn unionFieldVal(
26970 _ = try block.addNoOp(.unreach);27048 _ = try block.addNoOp(.unreach);
26971 return .unreachable_value;27049 return .unreachable_value;
26972 }27050 }
27051 try sema.resolveTypeLayout(field_ty);
26973 return block.addStructFieldVal(union_byval, field_index, field_ty);27052 return block.addStructFieldVal(union_byval, field_index, field_ty);
26974}27053}
2697527054
...@@ -27194,7 +27273,7 @@ fn tupleFieldPtr(...@@ -27194,7 +27273,7 @@ fn tupleFieldPtr(
27194 }27273 }
2719527274
27196 const field_ty = tuple_ty.structFieldType(field_index, mod);27275 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(.{
27198 .child = field_ty.toIntern(),27277 .child = field_ty.toIntern(),
27199 .flags = .{27278 .flags = .{
27200 .is_const = !tuple_ptr_ty.ptrIsMutable(mod),27279 .is_const = !tuple_ptr_ty.ptrIsMutable(mod),
...@@ -27265,6 +27344,7 @@ fn tupleField(...@@ -27265,6 +27344,7 @@ fn tupleField(
27265 try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src);27344 try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src);
2726627345
27267 try sema.requireRuntimeBlock(block, tuple_src, null);27346 try sema.requireRuntimeBlock(block, tuple_src, null);
27347 try sema.resolveTypeLayout(field_ty);
27268 return block.addStructFieldVal(tuple, field_index, field_ty);27348 return block.addStructFieldVal(tuple, field_index, field_ty);
27269}27349}
2727027350
...@@ -28266,7 +28346,7 @@ const InMemoryCoercionResult = union(enum) {...@@ -28266,7 +28346,7 @@ const InMemoryCoercionResult = union(enum) {
28266 ptr_qualifiers: Qualifiers,28346 ptr_qualifiers: Qualifiers,
28267 ptr_allowzero: Pair,28347 ptr_allowzero: Pair,
28268 ptr_bit_range: BitRange,28348 ptr_bit_range: BitRange,
28269 ptr_alignment: IntPair,28349 ptr_alignment: AlignPair,
28270 double_ptr_to_anyopaque: Pair,28350 double_ptr_to_anyopaque: Pair,
28271 slice_to_anyopaque: Pair,28351 slice_to_anyopaque: Pair,
2827228352
...@@ -28312,6 +28392,11 @@ const InMemoryCoercionResult = union(enum) {...@@ -28312,6 +28392,11 @@ const InMemoryCoercionResult = union(enum) {
28312 wanted: u64,28392 wanted: u64,
28313 };28393 };
2831428394
28395 const AlignPair = struct {
28396 actual: Alignment,
28397 wanted: Alignment,
28398 };
28399
28315 const Size = struct {28400 const Size = struct {
28316 actual: std.builtin.Type.Pointer.Size,28401 actual: std.builtin.Type.Pointer.Size,
28317 wanted: std.builtin.Type.Pointer.Size,28402 wanted: std.builtin.Type.Pointer.Size,
...@@ -28555,8 +28640,8 @@ const InMemoryCoercionResult = union(enum) {...@@ -28555,8 +28640,8 @@ const InMemoryCoercionResult = union(enum) {
28555 break;28640 break;
28556 },28641 },
28557 .ptr_alignment => |pair| {28642 .ptr_alignment => |pair| {
28558 try sema.errNote(block, src, msg, "pointer alignment '{}' cannot cast into pointer alignment '{}'", .{28643 try sema.errNote(block, src, msg, "pointer alignment '{d}' cannot cast into pointer alignment '{d}'", .{
28559 pair.actual, pair.wanted,28644 pair.actual.toByteUnits(0), pair.wanted.toByteUnits(0),
28560 });28645 });
28561 break;28646 break;
28562 },28647 },
...@@ -29133,13 +29218,17 @@ fn coerceInMemoryAllowedPtrs(...@@ -29133,13 +29218,17 @@ fn coerceInMemoryAllowedPtrs(
29133 if (src_info.flags.alignment != .none or dest_info.flags.alignment != .none or29218 if (src_info.flags.alignment != .none or dest_info.flags.alignment != .none or
29134 dest_info.child != src_info.child)29219 dest_info.child != src_info.child)
29135 {29220 {
29136 const src_align = src_info.flags.alignment.toByteUnitsOptional() orelse29221 const src_align = if (src_info.flags.alignment != .none)
29137 src_info.child.toType().abiAlignment(mod);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() orelse29226 const dest_align = if (dest_info.flags.alignment != .none)
29140 dest_info.child.toType().abiAlignment(mod);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)) {
29143 return InMemoryCoercionResult{ .ptr_alignment = .{29232 return InMemoryCoercionResult{ .ptr_alignment = .{
29144 .actual = src_align,29233 .actual = src_align,
29145 .wanted = dest_align,29234 .wanted = dest_align,
...@@ -30378,13 +30467,17 @@ fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_resul...@@ -30378,13 +30467,17 @@ fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_resul
30378 if (inst_info.flags.alignment == .none and dest_info.flags.alignment == .none) return true;30467 if (inst_info.flags.alignment == .none and dest_info.flags.alignment == .none) return true;
30379 if (len0) return true;30468 if (len0) return true;
3038030469
30381 const inst_align = inst_info.flags.alignment.toByteUnitsOptional() orelse30470 const inst_align = if (inst_info.flags.alignment != .none)
30471 inst_info.flags.alignment
30472 else
30382 inst_info.child.toType().abiAlignment(mod);30473 inst_info.child.toType().abiAlignment(mod);
3038330474
30384 const dest_align = dest_info.flags.alignment.toByteUnitsOptional() orelse30475 const dest_align = if (dest_info.flags.alignment != .none)
30476 dest_info.flags.alignment
30477 else
30385 dest_info.child.toType().abiAlignment(mod);30478 dest_info.child.toType().abiAlignment(mod);
3038630479
30387 if (dest_align > inst_align) {30480 if (dest_align.compare(.gt, inst_align)) {
30388 in_memory_result.* = .{ .ptr_alignment = .{30481 in_memory_result.* = .{ .ptr_alignment = .{
30389 .actual = inst_align,30482 .actual = inst_align,
30390 .wanted = dest_align,30483 .wanted = dest_align,
...@@ -30598,7 +30691,7 @@ fn coerceAnonStructToUnion(...@@ -30598,7 +30691,7 @@ fn coerceAnonStructToUnion(
30598 else30691 else
30599 .{ .count = anon_struct_type.names.len },30692 .{ .count = anon_struct_type.names.len },
30600 .struct_type => |struct_type| name: {30693 .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);
30602 break :name if (field_names.len == 1)30695 break :name if (field_names.len == 1)
30603 .{ .name = field_names[0] }30696 .{ .name = field_names[0] }
30604 else30697 else
...@@ -30869,8 +30962,8 @@ fn coerceTupleToStruct(...@@ -30869,8 +30962,8 @@ fn coerceTupleToStruct(
30869 return sema.coerceTupleToTuple(block, struct_ty, inst, inst_src);30962 return sema.coerceTupleToTuple(block, struct_ty, inst, inst_src);
30870 }30963 }
3087130964
30872 const fields = struct_ty.structFields(mod);30965 const struct_type = mod.typeToStruct(struct_ty).?;
30873 const field_vals = try sema.arena.alloc(InternPool.Index, fields.count());30966 const field_vals = try sema.arena.alloc(InternPool.Index, struct_type.field_types.len);
30874 const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len);30967 const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len);
30875 @memset(field_refs, .none);30968 @memset(field_refs, .none);
3087630969
...@@ -30878,10 +30971,7 @@ fn coerceTupleToStruct(...@@ -30878,10 +30971,7 @@ fn coerceTupleToStruct(
30878 var runtime_src: ?LazySrcLoc = null;30971 var runtime_src: ?LazySrcLoc = null;
30879 const field_count = switch (ip.indexToKey(inst_ty.toIntern())) {30972 const field_count = switch (ip.indexToKey(inst_ty.toIntern())) {
30880 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,30973 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
30881 .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj|30974 .struct_type => |s| s.field_types.len,
30882 struct_obj.fields.count()
30883 else
30884 0,
30885 else => unreachable,30975 else => unreachable,
30886 };30976 };
30887 for (0..field_count) |field_index_usize| {30977 for (0..field_count) |field_index_usize| {
...@@ -30893,22 +30983,23 @@ fn coerceTupleToStruct(...@@ -30893,22 +30983,23 @@ fn coerceTupleToStruct(
30893 anon_struct_type.names.get(ip)[field_i]30983 anon_struct_type.names.get(ip)[field_i]
30894 else30984 else
30895 try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}),30985 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],
30897 else => unreachable,30987 else => unreachable,
30898 };30988 };
30899 const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src);30989 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();
30901 const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i);30991 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);
30903 field_refs[field_index] = coerced;30993 field_refs[field_index] = coerced;
30904 if (field.is_comptime) {30994 if (struct_type.fieldIsComptime(ip, field_index)) {
30905 const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse {30995 const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse {
30906 return sema.failWithNeededComptime(block, field_src, .{30996 return sema.failWithNeededComptime(block, field_src, .{
30907 .needed_comptime_reason = "value stored in comptime field must be comptime-known",30997 .needed_comptime_reason = "value stored in comptime field must be comptime-known",
30908 });30998 });
30909 };30999 };
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)) {
30912 return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i);31003 return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i);
30913 }31004 }
30914 }31005 }
...@@ -30928,10 +31019,10 @@ fn coerceTupleToStruct(...@@ -30928,10 +31019,10 @@ fn coerceTupleToStruct(
30928 for (field_refs, 0..) |*field_ref, i| {31019 for (field_refs, 0..) |*field_ref, i| {
30929 if (field_ref.* != .none) continue;31020 if (field_ref.* != .none) continue;
3093031021
30931 const field_name = fields.keys()[i];31022 const field_name = struct_type.field_names.get(ip)[i];
30932 const field = fields.values()[i];31023 const field_default_val = struct_type.fieldInit(ip, i);
30933 const field_src = inst_src; // TODO better source location31024 const field_src = inst_src; // TODO better source location
30934 if (field.default_val == .none) {31025 if (field_default_val == .none) {
30935 const template = "missing struct field: {}";31026 const template = "missing struct field: {}";
30936 const args = .{field_name.fmt(ip)};31027 const args = .{field_name.fmt(ip)};
30937 if (root_msg) |msg| {31028 if (root_msg) |msg| {
...@@ -30942,9 +31033,9 @@ fn coerceTupleToStruct(...@@ -30942,9 +31033,9 @@ fn coerceTupleToStruct(
30942 continue;31033 continue;
30943 }31034 }
30944 if (runtime_src == null) {31035 if (runtime_src == null) {
30945 field_vals[i] = field.default_val;31036 field_vals[i] = field_default_val;
30946 } else {31037 } else {
30947 field_ref.* = Air.internedToRef(field.default_val);31038 field_ref.* = Air.internedToRef(field_default_val);
30948 }31039 }
30949 }31040 }
3095031041
...@@ -30980,10 +31071,7 @@ fn coerceTupleToTuple(...@@ -30980,10 +31071,7 @@ fn coerceTupleToTuple(
30980 const ip = &mod.intern_pool;31071 const ip = &mod.intern_pool;
30981 const dest_field_count = switch (ip.indexToKey(tuple_ty.toIntern())) {31072 const dest_field_count = switch (ip.indexToKey(tuple_ty.toIntern())) {
30982 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,31073 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
30983 .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj|31074 .struct_type => |struct_type| struct_type.field_types.len,
30984 struct_obj.fields.count()
30985 else
30986 0,
30987 else => unreachable,31075 else => unreachable,
30988 };31076 };
30989 const field_vals = try sema.arena.alloc(InternPool.Index, dest_field_count);31077 const field_vals = try sema.arena.alloc(InternPool.Index, dest_field_count);
...@@ -30993,10 +31081,7 @@ fn coerceTupleToTuple(...@@ -30993,10 +31081,7 @@ fn coerceTupleToTuple(
30993 const inst_ty = sema.typeOf(inst);31081 const inst_ty = sema.typeOf(inst);
30994 const src_field_count = switch (ip.indexToKey(inst_ty.toIntern())) {31082 const src_field_count = switch (ip.indexToKey(inst_ty.toIntern())) {
30995 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,31083 .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
30996 .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj|31084 .struct_type => |struct_type| struct_type.field_types.len,
30997 struct_obj.fields.count()
30998 else
30999 0,
31000 else => unreachable,31085 else => unreachable,
31001 };31086 };
31002 if (src_field_count > dest_field_count) return error.NotCoercible;31087 if (src_field_count > dest_field_count) return error.NotCoercible;
...@@ -31011,7 +31096,7 @@ fn coerceTupleToTuple(...@@ -31011,7 +31096,7 @@ fn coerceTupleToTuple(
31011 anon_struct_type.names.get(ip)[field_i]31096 anon_struct_type.names.get(ip)[field_i]
31012 else31097 else
31013 try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}),31098 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],
31015 else => unreachable,31100 else => unreachable,
31016 };31101 };
3101731102
...@@ -31019,20 +31104,20 @@ fn coerceTupleToTuple(...@@ -31019,20 +31104,20 @@ fn coerceTupleToTuple(
31019 return sema.fail(block, field_src, "cannot assign to 'len' field of tuple", .{});31104 return sema.fail(block, field_src, "cannot assign to 'len' field of tuple", .{});
3102031105
31021 const field_ty = switch (ip.indexToKey(tuple_ty.toIntern())) {31106 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(),31107 .anon_struct_type => |anon_struct_type| anon_struct_type.types.get(ip)[field_index_usize],
31023 .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.values()[field_index_usize].ty,31108 .struct_type => |struct_type| struct_type.field_types.get(ip)[field_index_usize],
31024 else => unreachable,31109 else => unreachable,
31025 };31110 };
31026 const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {31111 const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {
31027 .anon_struct_type => |anon_struct_type| anon_struct_type.values.get(ip)[field_index_usize],31112 .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),
31029 else => unreachable,31114 else => unreachable,
31030 };31115 };
3103131116
31032 const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_src);31117 const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_src);
3103331118
31034 const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i);31119 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);
31036 field_refs[field_index] = coerced;31121 field_refs[field_index] = coerced;
31037 if (default_val != .none) {31122 if (default_val != .none) {
31038 const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse {31123 const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse {
...@@ -31041,7 +31126,7 @@ fn coerceTupleToTuple(...@@ -31041,7 +31126,7 @@ fn coerceTupleToTuple(
31041 });31126 });
31042 };31127 };
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)) {
31045 return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i);31130 return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i);
31046 }31131 }
31047 }31132 }
...@@ -31058,18 +31143,19 @@ fn coerceTupleToTuple(...@@ -31058,18 +31143,19 @@ fn coerceTupleToTuple(
31058 var root_msg: ?*Module.ErrorMsg = null;31143 var root_msg: ?*Module.ErrorMsg = null;
31059 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);31144 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);
31062 if (field_ref.* != .none) continue;31148 if (field_ref.* != .none) continue;
3106331149
31064 const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {31150 const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {
31065 .anon_struct_type => |anon_struct_type| anon_struct_type.values.get(ip)[i],31151 .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),
31067 else => unreachable,31153 else => unreachable,
31068 };31154 };
3106931155
31070 const field_src = inst_src; // TODO better source location31156 const field_src = inst_src; // TODO better source location
31071 if (default_val == .none) {31157 if (default_val == .none) {
31072 if (tuple_ty.isTuple(mod)) {31158 const field_name = tuple_ty.structFieldName(i, mod).unwrap() orelse {
31073 const template = "missing tuple field: {d}";31159 const template = "missing tuple field: {d}";
31074 if (root_msg) |msg| {31160 if (root_msg) |msg| {
31075 try sema.errNote(block, field_src, msg, template, .{i});31161 try sema.errNote(block, field_src, msg, template, .{i});
...@@ -31077,9 +31163,9 @@ fn coerceTupleToTuple(...@@ -31077,9 +31163,9 @@ fn coerceTupleToTuple(
31077 root_msg = try sema.errMsg(block, field_src, template, .{i});31163 root_msg = try sema.errMsg(block, field_src, template, .{i});
31078 }31164 }
31079 continue;31165 continue;
31080 }31166 };
31081 const template = "missing struct field: {}";31167 const template = "missing struct field: {}";
31082 const args = .{tuple_ty.structFieldName(i, mod).fmt(ip)};31168 const args = .{field_name.fmt(ip)};
31083 if (root_msg) |msg| {31169 if (root_msg) |msg| {
31084 try sema.errNote(block, field_src, msg, template, args);31170 try sema.errNote(block, field_src, msg, template, args);
31085 } else {31171 } else {
...@@ -31229,7 +31315,7 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: Decl.Index, analyze_fn_body: boo...@@ -31229,7 +31315,7 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: Decl.Index, analyze_fn_body: boo
3122931315
31230 const decl = mod.declPtr(decl_index);31316 const decl = mod.declPtr(decl_index);
31231 const decl_tv = try decl.typedValue();31317 const decl_tv = try decl.typedValue();
31232 const ptr_ty = try mod.ptrType(.{31318 const ptr_ty = try sema.ptrType(.{
31233 .child = decl_tv.ty.toIntern(),31319 .child = decl_tv.ty.toIntern(),
31234 .flags = .{31320 .flags = .{
31235 .alignment = decl.alignment,31321 .alignment = decl.alignment,
...@@ -31283,14 +31369,14 @@ fn analyzeRef(...@@ -31283,14 +31369,14 @@ fn analyzeRef(
3128331369
31284 try sema.requireRuntimeBlock(block, src, null);31370 try sema.requireRuntimeBlock(block, src, null);
31285 const address_space = target_util.defaultAddressSpace(mod.getTarget(), .local);31371 const address_space = target_util.defaultAddressSpace(mod.getTarget(), .local);
31286 const ptr_type = try mod.ptrType(.{31372 const ptr_type = try sema.ptrType(.{
31287 .child = operand_ty.toIntern(),31373 .child = operand_ty.toIntern(),
31288 .flags = .{31374 .flags = .{
31289 .is_const = true,31375 .is_const = true,
31290 .address_space = address_space,31376 .address_space = address_space,
31291 },31377 },
31292 });31378 });
31293 const mut_ptr_type = try mod.ptrType(.{31379 const mut_ptr_type = try sema.ptrType(.{
31294 .child = operand_ty.toIntern(),31380 .child = operand_ty.toIntern(),
31295 .flags = .{ .address_space = address_space },31381 .flags = .{ .address_space = address_space },
31296 });31382 });
...@@ -31662,7 +31748,7 @@ fn analyzeSlice(...@@ -31662,7 +31748,7 @@ fn analyzeSlice(
31662 assert(manyptr_ty_key.flags.size == .One);31748 assert(manyptr_ty_key.flags.size == .One);
31663 manyptr_ty_key.child = elem_ty.toIntern();31749 manyptr_ty_key.child = elem_ty.toIntern();
31664 manyptr_ty_key.flags.size = .Many;31750 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);
31666 } else ptr_or_slice;31752 } else ptr_or_slice;
3166731753
31668 const start = try sema.coerce(block, Type.usize, uncasted_start, start_src);31754 const start = try sema.coerce(block, Type.usize, uncasted_start, start_src);
...@@ -31885,7 +31971,7 @@ fn analyzeSlice(...@@ -31885,7 +31971,7 @@ fn analyzeSlice(
31885 if (opt_new_len_val) |new_len_val| {31971 if (opt_new_len_val) |new_len_val| {
31886 const new_len_int = new_len_val.toUnsignedInt(mod);31972 const new_len_int = new_len_val.toUnsignedInt(mod);
3188731973
31888 const return_ty = try mod.ptrType(.{31974 const return_ty = try sema.ptrType(.{
31889 .child = (try mod.arrayType(.{31975 .child = (try mod.arrayType(.{
31890 .len = new_len_int,31976 .len = new_len_int,
31891 .sentinel = if (sentinel) |s| s.toIntern() else .none,31977 .sentinel = if (sentinel) |s| s.toIntern() else .none,
...@@ -31946,7 +32032,7 @@ fn analyzeSlice(...@@ -31946,7 +32032,7 @@ fn analyzeSlice(
31946 return sema.fail(block, src, "non-zero length slice of undefined pointer", .{});32032 return sema.fail(block, src, "non-zero length slice of undefined pointer", .{});
31947 }32033 }
3194832034
31949 const return_ty = try mod.ptrType(.{32035 const return_ty = try sema.ptrType(.{
31950 .child = elem_ty.toIntern(),32036 .child = elem_ty.toIntern(),
31951 .sentinel = if (sentinel) |s| s.toIntern() else .none,32037 .sentinel = if (sentinel) |s| s.toIntern() else .none,
31952 .flags = .{32038 .flags = .{
...@@ -33181,12 +33267,17 @@ fn resolvePeerTypesInner(...@@ -33181,12 +33267,17 @@ fn resolvePeerTypesInner(
33181 }33267 }
3318233268
33183 // Note that the align can be always non-zero; Module.ptrType will canonicalize it33269 // Note that the align can be always non-zero; Module.ptrType will canonicalize it
33184 ptr_info.flags.alignment = Alignment.fromByteUnits(@min(33270 ptr_info.flags.alignment = InternPool.Alignment.min(
33185 ptr_info.flags.alignment.toByteUnitsOptional() orelse33271 if (ptr_info.flags.alignment != .none)
33272 ptr_info.flags.alignment
33273 else
33186 ptr_info.child.toType().abiAlignment(mod),33274 ptr_info.child.toType().abiAlignment(mod),
33187 peer_info.flags.alignment.toByteUnitsOptional() orelse33275
33276 if (peer_info.flags.alignment != .none)
33277 peer_info.flags.alignment
33278 else
33188 peer_info.child.toType().abiAlignment(mod),33279 peer_info.child.toType().abiAlignment(mod),
33189 ));33280 );
33190 if (ptr_info.flags.address_space != peer_info.flags.address_space) {33281 if (ptr_info.flags.address_space != peer_info.flags.address_space) {
33191 return .{ .conflict = .{33282 return .{ .conflict = .{
33192 .peer_idx_a = first_idx,33283 .peer_idx_a = first_idx,
...@@ -33208,7 +33299,7 @@ fn resolvePeerTypesInner(...@@ -33208,7 +33299,7 @@ fn resolvePeerTypesInner(
3320833299
33209 opt_ptr_info = ptr_info;33300 opt_ptr_info = ptr_info;
33210 }33301 }
33211 return .{ .success = try mod.ptrType(opt_ptr_info.?) };33302 return .{ .success = try sema.ptrType(opt_ptr_info.?) };
33212 },33303 },
3321333304
33214 .ptr => {33305 .ptr => {
...@@ -33260,12 +33351,17 @@ fn resolvePeerTypesInner(...@@ -33260,12 +33351,17 @@ fn resolvePeerTypesInner(
33260 } };33351 } };
3326133352
33262 // Note that the align can be always non-zero; Type.ptr will canonicalize it33353 // Note that the align can be always non-zero; Type.ptr will canonicalize it
33263 ptr_info.flags.alignment = Alignment.fromByteUnits(@min(33354 ptr_info.flags.alignment = Alignment.min(
33264 ptr_info.flags.alignment.toByteUnitsOptional() orelse33355 if (ptr_info.flags.alignment != .none)
33265 ptr_info.child.toType().abiAlignment(mod),33356 ptr_info.flags.alignment
33266 peer_info.flags.alignment.toByteUnitsOptional() orelse33357 else
33267 peer_info.child.toType().abiAlignment(mod),33358 try sema.typeAbiAlignment(ptr_info.child.toType()),
33268 ));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
33270 if (ptr_info.flags.address_space != peer_info.flags.address_space) {33366 if (ptr_info.flags.address_space != peer_info.flags.address_space) {
33271 return generic_err;33367 return generic_err;
...@@ -33513,7 +33609,7 @@ fn resolvePeerTypesInner(...@@ -33513,7 +33609,7 @@ fn resolvePeerTypesInner(
33513 },33609 },
33514 }33610 }
3351533611
33516 return .{ .success = try mod.ptrType(opt_ptr_info.?) };33612 return .{ .success = try sema.ptrType(opt_ptr_info.?) };
33517 },33613 },
3351833614
33519 .func => {33615 .func => {
...@@ -33802,8 +33898,9 @@ fn resolvePeerTypesInner(...@@ -33802,8 +33898,9 @@ fn resolvePeerTypesInner(
33802 }33898 }
3380333899
33804 if (!is_tuple) {33900 if (!is_tuple) {
33805 for (field_names, 0..) |expected, field_idx| {33901 for (field_names, 0..) |expected, field_index_usize| {
33806 const actual = ty.structFieldName(field_idx, mod);33902 const field_index: u32 = @intCast(field_index_usize);
33903 const actual = ty.structFieldName(field_index, mod).unwrap().?;
33807 if (actual == expected) continue;33904 if (actual == expected) continue;
33808 return .{ .conflict = .{33905 return .{ .conflict = .{
33809 .peer_idx_a = first_idx,33906 .peer_idx_a = first_idx,
...@@ -34190,104 +34287,246 @@ pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void {...@@ -34190,104 +34287,246 @@ pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void {
34190 }34287 }
34191}34288}
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
34193fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {34347fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
34194 const mod = sema.mod;34348 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
34195 try sema.resolveTypeFields(ty);34355 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;34357 if (struct_type.layout == .Packed) {
34216 for (struct_obj.fields.values(), 0..) |field, i| {34358 try semaBackingIntType(mod, struct_type);
34217 sema.resolveTypeLayout(field.ty) catch |err| switch (err) {34359 return;
34218 error.AnalysisFail => {34360 }
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 }
3422634361
34227 if (struct_obj.layout == .Packed) {34362 if (struct_type.setLayoutWip(ip)) {
34228 try semaBackingIntType(mod, struct_obj);34363 const msg = try Module.ErrorMsg.create(
34229 }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;34373 const aligns = try sema.arena.alloc(Alignment, struct_type.field_types.len);
34232 _ = try sema.typeRequiresComptime(ty);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))) {34376 var big_align: Alignment = .@"1";
34235 const msg = try Module.ErrorMsg.create(34377
34236 sema.gpa,34378 for (aligns, sizes, 0..) |*field_align, *field_size, i| {
34237 struct_obj.srcLoc(mod),34379 const field_ty = struct_type.field_types.get(ip)[i].toType();
34238 "struct layout depends on it having runtime bits",34380 if (struct_type.fieldIsComptime(ip, i) or try sema.typeRequiresComptime(field_ty)) {
34239 .{},34381 struct_type.offsets.get(ip)[i] = 0;
34240 );34382 field_size.* = 0;
34241 return sema.failWithOwnedErrorMsg(null, msg);34383 field_align.* = .none;
34384 continue;
34242 }34385 }
3424334386
34244 if (struct_obj.layout == .Auto and !struct_obj.is_tuple and34387 field_size.* = sema.typeAbiSize(field_ty) catch |err| switch (err) {
34245 mod.backendSupportsFeature(.field_reordering))34388 error.AnalysisFail => {
34246 {34389 const msg = sema.err orelse return err;
34247 const optimized_order = try mod.tmp_hack_arena.allocator().alloc(u32, struct_obj.fields.count());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| {34403 if (struct_type.flagsPtr(ip).assumed_runtime_bits and !(try sema.typeHasRuntimeBits(ty))) {
34250 optimized_order[i] = if (try sema.typeHasRuntimeBits(field.ty))34404 const msg = try Module.ErrorMsg.create(
34251 @intCast(i)34405 sema.gpa,
34252 else34406 mod.declPtr(struct_type.decl.unwrap().?).srcLoc(mod),
34253 Module.Struct.omitted_field;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);
34254 }34422 }
34423 }
34424
34425 const RuntimeOrder = InternPool.Key.StructType.RuntimeOrder;
3425534426
34256 const AlignSortContext = struct {34427 const AlignSortContext = struct {
34257 struct_obj: *Module.Struct,34428 aligns: []const Alignment,
34258 sema: *Sema,
3425934429
34260 fn lessThan(ctx: @This(), a: u32, b: u32) bool {34430 fn lessThan(ctx: @This(), a: RuntimeOrder, b: RuntimeOrder) bool {
34261 const m = ctx.sema.mod;34431 if (a == .omitted) return false;
34262 if (a == Module.Struct.omitted_field) return false;34432 if (b == .omitted) return true;
34263 if (b == Module.Struct.omitted_field) return true;34433 const a_align = ctx.aligns[@intFromEnum(a)];
34264 return ctx.struct_obj.fields.values()[a].ty.abiAlignment(m) >34434 const b_align = ctx.aligns[@intFromEnum(b)];
34265 ctx.struct_obj.fields.values()[b].ty.abiAlignment(m);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;
34266 }34450 }
34267 };34451 runtime_order[i] = runtime_order[i + off];
34268 mem.sort(u32, optimized_order, AlignSortContext{34452 i += 1;
34269 .struct_obj = struct_obj,34453 }
34270 .sema = sema,34454 @memset(runtime_order[i..], .omitted);
34455 } else {
34456 mem.sortUnstable(RuntimeOrder, runtime_order, AlignSortContext{
34457 .aligns = aligns,
34271 }, AlignSortContext.lessThan);34458 }, AlignSortContext.lessThan);
34272 struct_obj.optimized_order = optimized_order.ptr;
34273 }34459 }
34274 }34460 }
34275 // otherwise it's a tuple; no need to resolve anything34461
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);
34276}34475}
3427734476
34278fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!void {34477fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) CompileError!void {
34279 const gpa = mod.gpa;34478 const gpa = mod.gpa;
34479 const ip = &mod.intern_pool;
3428034480
34281 var fields_bit_sum: u64 = 0;34481 const decl_index = struct_type.decl.unwrap().?;
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;
34287 const decl = mod.declPtr(decl_index);34482 const decl = mod.declPtr(decl_index);
3428834483
34289 const zir = mod.namespacePtr(struct_obj.namespace).file_scope.zir;34484 const zir = mod.namespacePtr(struct_type.namespace.unwrap().?).file_scope.zir;
34290 const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended;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;
34291 assert(extended.opcode == .struct_decl);34530 assert(extended.opcode == .struct_decl);
34292 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);34531 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
3429334532
...@@ -34300,40 +34539,6 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi...@@ -34300,40 +34539,6 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi
34300 const backing_int_body_len = zir.extra[extra_index];34539 const backing_int_body_len = zir.extra[extra_index];
34301 extra_index += 1;34540 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
34337 const backing_int_src: LazySrcLoc = .{ .node_offset_container_tag = 0 };34542 const backing_int_src: LazySrcLoc = .{ .node_offset_container_tag = 0 };
34338 const backing_int_ty = blk: {34543 const backing_int_ty = blk: {
34339 if (backing_int_body_len == 0) {34544 if (backing_int_body_len == 0) {
...@@ -34341,48 +34546,24 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi...@@ -34341,48 +34546,24 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi
34341 break :blk try sema.resolveType(&block, backing_int_src, backing_int_ref);34546 break :blk try sema.resolveType(&block, backing_int_src, backing_int_ref);
34342 } else {34547 } else {
34343 const body = zir.extra[extra_index..][0..backing_int_body_len];34548 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);
34345 break :blk try sema.analyzeAsType(&block, backing_int_src, ty_ref);34550 break :blk try sema.analyzeAsType(&block, backing_int_src, ty_ref);
34346 }34551 }
34347 };34552 };
3434834553
34349 try sema.checkBackingIntType(&block, backing_int_src, backing_int_ty, fields_bit_sum);34554 try sema.checkBackingIntType(&block, backing_int_src, backing_int_ty, fields_bit_sum);
34350 struct_obj.backing_int_ty = backing_int_ty;34555 struct_type.backingIntType(ip).* = backing_int_ty.toIntern();
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 }
34355 } else {34556 } else {
34356 if (fields_bit_sum > std.math.maxInt(u16)) {34557 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 };
34383 return sema.fail(&block, LazySrcLoc.nodeOffset(0), "size of packed struct '{d}' exceeds maximum bit width of 65535", .{fields_bit_sum});34558 return sema.fail(&block, LazySrcLoc.nodeOffset(0), "size of packed struct '{d}' exceeds maximum bit width of 65535", .{fields_bit_sum});
34384 }34559 }
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);
34386 }34567 }
34387}34568}
3438834569
...@@ -34532,30 +34713,20 @@ fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void {...@@ -34532,30 +34713,20 @@ fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void {
34532 try sema.resolveStructLayout(ty);34713 try sema.resolveStructLayout(ty);
3453334714
34534 const mod = sema.mod;34715 const mod = sema.mod;
34535 try sema.resolveTypeFields(ty);34716 const ip = &mod.intern_pool;
34536 const struct_obj = mod.typeToStruct(ty).?;34717 const struct_type = mod.typeToStruct(ty).?;
3453734718
34538 switch (struct_obj.status) {34719 if (struct_type.setFullyResolved(ip)) return;
34539 .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},34720 errdefer struct_type.clearFullyResolved(ip);
34540 .fully_resolved_wip, .fully_resolved => return,
34541 }
3454234721
34543 {34722 // After we have resolve struct layout we have to go over the fields again to
34544 // After we have resolve struct layout we have to go over the fields again to34723 // make sure pointer fields get their child types resolved as well.
34545 // make sure pointer fields get their child types resolved as well.34724 // See also similar code for unions.
34546 // See also similar code for unions.
34547 const prev_status = struct_obj.status;
34548 errdefer struct_obj.status = prev_status;
3454934725
34550 struct_obj.status = .fully_resolved_wip;34726 for (0..struct_type.field_types.len) |i| {
34551 for (struct_obj.fields.values()) |field| {34727 const field_ty = struct_type.field_types.get(ip)[i].toType();
34552 try sema.resolveTypeFully(field.ty);34728 try sema.resolveTypeFully(field_ty);
34553 }
34554 struct_obj.status = .fully_resolved;
34555 }34729 }
34556
34557 // And let's not forget comptime-only status.
34558 _ = try sema.typeRequiresComptime(ty);
34559}34730}
3456034731
34561fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void {34732fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void {
...@@ -34591,8 +34762,10 @@ fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void {...@@ -34591,8 +34762,10 @@ fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void {
3459134762
34592pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void {34763pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void {
34593 const mod = sema.mod;34764 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) {
34596 .var_args_param_type => unreachable,34769 .var_args_param_type => unreachable,
3459734770
34598 .none => unreachable,34771 .none => unreachable,
...@@ -34673,20 +34846,15 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void {...@@ -34673,20 +34846,15 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void {
34673 .empty_struct => unreachable,34846 .empty_struct => unreachable,
34674 .generic_poison => unreachable,34847 .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)]) {
34677 .type_struct,34850 .type_struct,
34678 .type_struct_ns,34851 .type_struct_ns,
34679 .type_union,34852 .type_struct_packed,
34680 .simple_type,34853 .type_struct_packed_inits,
34681 => switch (mod.intern_pool.indexToKey(ty.toIntern())) {34854 => try sema.resolveTypeFieldsStruct(ty_ip, ip.indexToKey(ty_ip).struct_type),
34682 .struct_type => |struct_type| {34855
34683 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return;34856 .type_union => try sema.resolveTypeFieldsUnion(ty_ip.toType(), ip.indexToKey(ty_ip).union_type),
34684 try sema.resolveTypeFieldsStruct(ty, struct_obj);34857 .simple_type => try sema.resolveSimpleType(ip.indexToKey(ty_ip).simple_type),
34685 },
34686 .union_type => |union_type| try sema.resolveTypeFieldsUnion(ty, union_type),
34687 .simple_type => |simple_type| try sema.resolveSimpleType(simple_type),
34688 else => unreachable,
34689 },
34690 else => {},34858 else => {},
34691 },34859 },
34692 }34860 }
...@@ -34716,43 +34884,41 @@ fn resolveSimpleType(sema: *Sema, simple_type: InternPool.SimpleType) CompileErr...@@ -34716,43 +34884,41 @@ fn resolveSimpleType(sema: *Sema, simple_type: InternPool.SimpleType) CompileErr
3471634884
34717fn resolveTypeFieldsStruct(34885fn resolveTypeFieldsStruct(
34718 sema: *Sema,34886 sema: *Sema,
34719 ty: Type,34887 ty: InternPool.Index,
34720 struct_obj: *Module.Struct,34888 struct_type: InternPool.Key.StructType,
34721) CompileError!void {34889) 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) {
34723 .file_failure,34896 .file_failure,
34724 .dependency_failure,34897 .dependency_failure,
34725 .sema_failure,34898 .sema_failure,
34726 .sema_failure_retryable,34899 .sema_failure_retryable,
34727 => {34900 => {
34728 sema.owner_decl.analysis = .dependency_failure;34901 sema.owner_decl.analysis = .dependency_failure;
34729 sema.owner_decl.generation = sema.mod.generation;34902 sema.owner_decl.generation = mod.generation;
34730 return error.AnalysisFail;34903 return error.AnalysisFail;
34731 },34904 },
34732 else => {},34905 else => {},
34733 }34906 }
34734 switch (struct_obj.status) {34907
34735 .none => {},34908 if (struct_type.haveFieldTypes(ip)) return;
34736 .field_types_wip => {34909
34737 const msg = try Module.ErrorMsg.create(34910 if (struct_type.setTypesWip(ip)) {
34738 sema.gpa,34911 const msg = try Module.ErrorMsg.create(
34739 struct_obj.srcLoc(sema.mod),34912 sema.gpa,
34740 "struct '{}' depends on itself",34913 mod.declPtr(owner_decl).srcLoc(mod),
34741 .{ty.fmt(sema.mod)},34914 "struct '{}' depends on itself",
34742 );34915 .{ty.toType().fmt(mod)},
34743 return sema.failWithOwnedErrorMsg(null, msg);34916 );
34744 },34917 return sema.failWithOwnedErrorMsg(null, msg);
34745 .have_field_types,
34746 .have_layout,
34747 .layout_wip,
34748 .fully_resolved_wip,
34749 .fully_resolved,
34750 => return,
34751 }34918 }
34919 defer struct_type.clearTypesWip(ip);
3475234920
34753 struct_obj.status = .field_types_wip;34921 try semaStructFields(mod, sema.arena, struct_type);
34754 errdefer struct_obj.status = .none;
34755 try semaStructFields(sema.mod, struct_obj);
34756}34922}
3475734923
34758fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Key.UnionType) CompileError!void {34924fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Key.UnionType) CompileError!void {
...@@ -34936,12 +35102,19 @@ fn resolveInferredErrorSetTy(...@@ -34936,12 +35102,19 @@ fn resolveInferredErrorSetTy(
34936 }35102 }
34937}35103}
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 {
34940 const gpa = mod.gpa;35110 const gpa = mod.gpa;
34941 const ip = &mod.intern_pool;35111 const ip = &mod.intern_pool;
34942 const decl_index = struct_obj.owner_decl;35112 const decl_index = struct_type.decl.unwrap() orelse return;
34943 const zir = mod.namespacePtr(struct_obj.namespace).file_scope.zir;35113 const decl = mod.declPtr(decl_index);
34944 const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended;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;
34945 assert(extended.opcode == .struct_decl);35118 assert(extended.opcode == .struct_decl);
34946 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);35119 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
34947 var extra_index: usize = extended.operand;35120 var extra_index: usize = extended.operand;
...@@ -34977,18 +35150,16 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -34977,18 +35150,16 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
34977 while (decls_it.next()) |_| {}35150 while (decls_it.next()) |_| {}
34978 extra_index = decls_it.extra_index;35151 extra_index = decls_it.extra_index;
3497935152
34980 if (fields_len == 0) {35153 if (fields_len == 0) switch (struct_type.layout) {
34981 if (struct_obj.layout == .Packed) {35154 .Packed => {
34982 try semaBackingIntType(mod, struct_obj);35155 try semaBackingIntType(mod, struct_type);
34983 }35156 return;
34984 struct_obj.status = .have_layout;35157 },
34985 return;35158 .Auto, .Extern => {
34986 }35159 struct_type.flagsPtr(ip).layout_resolved = true;
3498735160 return;
34988 const decl = mod.declPtr(decl_index);35161 },
3498935162 };
34990 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
34991 defer analysis_arena.deinit();
3499235163
34993 var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);35164 var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);
34994 defer comptime_mutable_decls.deinit();35165 defer comptime_mutable_decls.deinit();
...@@ -34996,7 +35167,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -34996,7 +35167,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
34996 var sema: Sema = .{35167 var sema: Sema = .{
34997 .mod = mod,35168 .mod = mod,
34998 .gpa = gpa,35169 .gpa = gpa,
34999 .arena = analysis_arena.allocator(),35170 .arena = arena,
35000 .code = zir,35171 .code = zir,
35001 .owner_decl = decl,35172 .owner_decl = decl,
35002 .owner_decl_index = decl_index,35173 .owner_decl_index = decl_index,
...@@ -35013,7 +35184,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -35013,7 +35184,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
35013 .parent = null,35184 .parent = null,
35014 .sema = &sema,35185 .sema = &sema,
35015 .src_decl = decl_index,35186 .src_decl = decl_index,
35016 .namespace = struct_obj.namespace,35187 .namespace = namespace_index,
35017 .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),35188 .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
35018 .instructions = .{},35189 .instructions = .{},
35019 .inlining = null,35190 .inlining = null,
...@@ -35021,9 +35192,6 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -35021,9 +35192,6 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
35021 };35192 };
35022 defer assert(block_scope.instructions.items.len == 0);35193 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
35027 const Field = struct {35195 const Field = struct {
35028 type_body_len: u32 = 0,35196 type_body_len: u32 = 0,
35029 align_body_len: u32 = 0,35197 align_body_len: u32 = 0,
...@@ -35031,7 +35199,9 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -35031,7 +35199,9 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
35031 type_ref: Zir.Inst.Ref = .none,35199 type_ref: Zir.Inst.Ref = .none,
35032 };35200 };
35033 const fields = try sema.arena.alloc(Field, fields_len);35201 const fields = try sema.arena.alloc(Field, fields_len);
35202
35034 var any_inits = false;35203 var any_inits = false;
35204 var any_aligned = false;
3503535205
35036 {35206 {
35037 const bits_per_field = 4;35207 const bits_per_field = 4;
...@@ -35056,9 +35226,11 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -35056,9 +35226,11 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
35056 const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0;35226 const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0;
35057 cur_bit_bag >>= 1;35227 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;
35060 if (!small.is_tuple) {35232 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]);
35062 extra_index += 1;35234 extra_index += 1;
35063 }35235 }
35064 extra_index += 1; // doc_comment35236 extra_index += 1; // doc_comment
...@@ -35073,37 +35245,27 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -35073,37 +35245,27 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
35073 extra_index += 1;35245 extra_index += 1;
3507435246
35075 // This string needs to outlive the ZIR code.35247 // This string needs to outlive the ZIR code.
35076 const field_name = try ip.getOrPutString(gpa, if (field_name_zir) |s|35248 if (opt_field_name_zir) |field_name_zir| {
35077 s35249 const field_name = try ip.getOrPutString(gpa, field_name_zir);
35078 else35250 if (struct_type.addFieldName(ip, field_name)) |other_index| {
35079 try std.fmt.allocPrint(sema.arena, "{d}", .{field_i}));35251 const msg = msg: {
3508035252 const field_src = mod.fieldSrcLoc(decl_index, .{ .index = field_i }).lazy;
35081 const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);35253 const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{}'", .{field_name.fmt(ip)});
35082 if (gop.found_existing) {35254 errdefer msg.destroy(gpa);
35083 const msg = msg: {
35084 const field_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ .index = field_i }).lazy;
35085 const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{}'", .{field_name.fmt(ip)});
35086 errdefer msg.destroy(gpa);
3508735255
35088 const prev_field_index = struct_obj.fields.getIndex(field_name).?;35256 const prev_field_src = mod.fieldSrcLoc(decl_index, .{ .index = other_index });
35089 const prev_field_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ .index = prev_field_index });35257 try mod.errNoteNonLazy(prev_field_src, msg, "other field here", .{});
35090 try mod.errNoteNonLazy(prev_field_src, msg, "other field here", .{});35258 try sema.errNote(&block_scope, src, msg, "struct declared here", .{});
35091 try sema.errNote(&block_scope, src, msg, "struct declared here", .{});35259 break :msg msg;
35092 break :msg msg;35260 };
35093 };35261 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35094 return sema.failWithOwnedErrorMsg(&block_scope, msg);35262 }
35095 }35263 }
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
35104 if (has_align) {35265 if (has_align) {
35105 fields[field_i].align_body_len = zir.extra[extra_index];35266 fields[field_i].align_body_len = zir.extra[extra_index];
35106 extra_index += 1;35267 extra_index += 1;
35268 any_aligned = true;
35107 }35269 }
35108 if (has_init) {35270 if (has_init) {
35109 fields[field_i].init_body_len = zir.extra[extra_index];35271 fields[field_i].init_body_len = zir.extra[extra_index];
...@@ -35122,7 +35284,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -35122,7 +35284,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
35122 if (zir_field.type_ref != .none) {35284 if (zir_field.type_ref != .none) {
35123 break :ty sema.resolveType(&block_scope, .unneeded, zir_field.type_ref) catch |err| switch (err) {35285 break :ty sema.resolveType(&block_scope, .unneeded, zir_field.type_ref) catch |err| switch (err) {
35124 error.NeededSourceLocation => {35286 error.NeededSourceLocation => {
35125 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{35287 const ty_src = mod.fieldSrcLoc(decl_index, .{
35126 .index = field_i,35288 .index = field_i,
35127 .range = .type,35289 .range = .type,
35128 }).lazy;35290 }).lazy;
...@@ -35135,10 +35297,10 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -35135,10 +35297,10 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
35135 assert(zir_field.type_body_len != 0);35297 assert(zir_field.type_body_len != 0);
35136 const body = zir.extra[extra_index..][0..zir_field.type_body_len];35298 const body = zir.extra[extra_index..][0..zir_field.type_body_len];
35137 extra_index += body.len;35299 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);
35139 break :ty sema.analyzeAsType(&block_scope, .unneeded, ty_ref) catch |err| switch (err) {35301 break :ty sema.analyzeAsType(&block_scope, .unneeded, ty_ref) catch |err| switch (err) {
35140 error.NeededSourceLocation => {35302 error.NeededSourceLocation => {
35141 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{35303 const ty_src = mod.fieldSrcLoc(decl_index, .{
35142 .index = field_i,35304 .index = field_i,
35143 .range = .type,35305 .range = .type,
35144 }).lazy;35306 }).lazy;
...@@ -35152,12 +35314,11 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -35152,12 +35314,11 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
35152 return error.GenericPoison;35314 return error.GenericPoison;
35153 }35315 }
3515435316
35155 const field = &struct_obj.fields.values()[field_i];35317 struct_type.field_types.get(ip)[field_i] = field_ty.toIntern();
35156 field.ty = field_ty;
3515735318
35158 if (field_ty.zigTypeTag(mod) == .Opaque) {35319 if (field_ty.zigTypeTag(mod) == .Opaque) {
35159 const msg = msg: {35320 const msg = msg: {
35160 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{35321 const ty_src = mod.fieldSrcLoc(decl_index, .{
35161 .index = field_i,35322 .index = field_i,
35162 .range = .type,35323 .range = .type,
35163 }).lazy;35324 }).lazy;
...@@ -35171,7 +35332,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -35171,7 +35332,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
35171 }35332 }
35172 if (field_ty.zigTypeTag(mod) == .NoReturn) {35333 if (field_ty.zigTypeTag(mod) == .NoReturn) {
35173 const msg = msg: {35334 const msg = msg: {
35174 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{35335 const ty_src = mod.fieldSrcLoc(decl_index, .{
35175 .index = field_i,35336 .index = field_i,
35176 .range = .type,35337 .range = .type,
35177 }).lazy;35338 }).lazy;
...@@ -35183,45 +35344,49 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -35183,45 +35344,49 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
35183 };35344 };
35184 return sema.failWithOwnedErrorMsg(&block_scope, msg);35345 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35185 }35346 }
35186 if (struct_obj.layout == .Extern and !try sema.validateExternType(field.ty, .struct_field)) {35347 switch (struct_type.layout) {
35187 const msg = msg: {35348 .Extern => if (!try sema.validateExternType(field_ty, .struct_field)) {
35188 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{35349 const msg = msg: {
35189 .index = field_i,35350 const ty_src = mod.fieldSrcLoc(decl_index, .{
35190 .range = .type,35351 .index = field_i,
35191 });35352 .range = .type,
35192 const msg = try sema.errMsg(&block_scope, ty_src.lazy, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(mod)});35353 });
35193 errdefer msg.destroy(sema.gpa);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);35359 try sema.addDeclaredHereNote(msg, field_ty);
35198 break :msg msg;35360 break :msg msg;
35199 };35361 };
35200 return sema.failWithOwnedErrorMsg(&block_scope, msg);35362 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35201 } else if (struct_obj.layout == .Packed and !(validatePackedType(field.ty, mod))) {35363 },
35202 const msg = msg: {35364 .Packed => if (!validatePackedType(field_ty, mod)) {
35203 const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{35365 const msg = msg: {
35204 .index = field_i,35366 const ty_src = mod.fieldSrcLoc(decl_index, .{
35205 .range = .type,35367 .index = field_i,
35206 });35368 .range = .type,
35207 const msg = try sema.errMsg(&block_scope, ty_src.lazy, "packed structs cannot contain fields of type '{}'", .{field.ty.fmt(mod)});35369 });
35208 errdefer msg.destroy(sema.gpa);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);35375 try sema.addDeclaredHereNote(msg, field_ty);
35213 break :msg msg;35376 break :msg msg;
35214 };35377 };
35215 return sema.failWithOwnedErrorMsg(&block_scope, msg);35378 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35379 },
35380 else => {},
35216 }35381 }
3521735382
35218 if (zir_field.align_body_len > 0) {35383 if (zir_field.align_body_len > 0) {
35219 const body = zir.extra[extra_index..][0..zir_field.align_body_len];35384 const body = zir.extra[extra_index..][0..zir_field.align_body_len];
35220 extra_index += body.len;35385 extra_index += body.len;
35221 const align_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);35386 const align_ref = try sema.resolveBody(&block_scope, body, zir_index);
35222 field.abi_align = sema.analyzeAsAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) {35387 const field_align = sema.analyzeAsAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) {
35223 error.NeededSourceLocation => {35388 error.NeededSourceLocation => {
35224 const align_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{35389 const align_src = mod.fieldSrcLoc(decl_index, .{
35225 .index = field_i,35390 .index = field_i,
35226 .range = .alignment,35391 .range = .alignment,
35227 }).lazy;35392 }).lazy;
...@@ -35230,36 +35395,38 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -35230,36 +35395,38 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
35230 },35395 },
35231 else => |e| return e,35396 else => |e| return e,
35232 };35397 };
35398 struct_type.field_aligns.get(ip)[field_i] = field_align;
35233 }35399 }
3523435400
35235 extra_index += zir_field.init_body_len;35401 extra_index += zir_field.init_body_len;
35236 }35402 }
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
35240 if (any_inits) {35407 if (any_inits) {
35241 extra_index = bodies_index;35408 extra_index = bodies_index;
35242 for (fields, 0..) |zir_field, field_i| {35409 for (fields, 0..) |zir_field, field_i| {
35410 const field_ty = struct_type.field_types.get(ip)[field_i].toType();
35243 extra_index += zir_field.type_body_len;35411 extra_index += zir_field.type_body_len;
35244 extra_index += zir_field.align_body_len;35412 extra_index += zir_field.align_body_len;
35245 if (zir_field.init_body_len > 0) {35413 if (zir_field.init_body_len > 0) {
35246 const body = zir.extra[extra_index..][0..zir_field.init_body_len];35414 const body = zir.extra[extra_index..][0..zir_field.init_body_len];
35247 extra_index += body.len;35415 extra_index += body.len;
35248 const init = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);35416 const init = try sema.resolveBody(&block_scope, body, zir_index);
35249 const field = &struct_obj.fields.values()[field_i];35417 const coerced = sema.coerce(&block_scope, field_ty, init, .unneeded) catch |err| switch (err) {
35250 const coerced = sema.coerce(&block_scope, field.ty, init, .unneeded) catch |err| switch (err) {
35251 error.NeededSourceLocation => {35418 error.NeededSourceLocation => {
35252 const init_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{35419 const init_src = mod.fieldSrcLoc(decl_index, .{
35253 .index = field_i,35420 .index = field_i,
35254 .range = .value,35421 .range = .value,
35255 }).lazy;35422 }).lazy;
35256 _ = try sema.coerce(&block_scope, field.ty, init, init_src);35423 _ = try sema.coerce(&block_scope, field_ty, init, init_src);
35257 unreachable;35424 unreachable;
35258 },35425 },
35259 else => |e| return e,35426 else => |e| return e,
35260 };35427 };
35261 const default_val = (try sema.resolveMaybeUndefVal(coerced)) orelse {35428 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, .{
35263 .index = field_i,35430 .index = field_i,
35264 .range = .value,35431 .range = .value,
35265 }).lazy;35432 }).lazy;
...@@ -35267,7 +35434,8 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -35267,7 +35434,8 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
35267 .needed_comptime_reason = "struct field default value must be comptime-known",35434 .needed_comptime_reason = "struct field default value must be comptime-known",
35268 });35435 });
35269 };35436 };
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;
35271 }35439 }
35272 }35440 }
35273 }35441 }
...@@ -35275,8 +35443,6 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -35275,8 +35443,6 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
35275 const ct_decl = mod.declPtr(ct_decl_index);35443 const ct_decl = mod.declPtr(ct_decl_index);
35276 _ = try ct_decl.internValue(mod);35444 _ = try ct_decl.internValue(mod);
35277 }35445 }
35278
35279 struct_obj.have_field_inits = true;
35280}35446}
3528135447
35282fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.UnionType) CompileError!void {35448fn 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 {...@@ -36060,6 +36226,8 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
36060 .type_struct,36226 .type_struct,
36061 .type_struct_ns,36227 .type_struct_ns,
36062 .type_struct_anon,36228 .type_struct_anon,
36229 .type_struct_packed,
36230 .type_struct_packed_inits,
36063 .type_tuple_anon,36231 .type_tuple_anon,
36064 .type_union,36232 .type_union,
36065 => switch (ip.indexToKey(ty.toIntern())) {36233 => switch (ip.indexToKey(ty.toIntern())) {
...@@ -36081,41 +36249,46 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -36081,41 +36249,46 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3608136249
36082 .struct_type => |struct_type| {36250 .struct_type => |struct_type| {
36083 try sema.resolveTypeFields(ty);36251 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 and36253 if (struct_type.field_types.len == 0) {
36254 // In this case the struct has no fields at all and
36107 // therefore has one possible value.36255 // therefore has one possible value.
36108 return (try mod.intern(.{ .aggregate = .{36256 return (try mod.intern(.{ .aggregate = .{
36109 .ty = ty.toIntern(),36257 .ty = ty.toIntern(),
36110 .storage = .{ .elems = field_vals },36258 .storage = .{ .elems = &.{} },
36111 } })).toValue();36259 } })).toValue();
36112 }36260 }
3611336261
36114 // In this case the struct has no fields at all and36262 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
36115 // therefore has one possible value.36288 // therefore has one possible value.
36116 return (try mod.intern(.{ .aggregate = .{36289 return (try mod.intern(.{ .aggregate = .{
36117 .ty = ty.toIntern(),36290 .ty = ty.toIntern(),
36118 .storage = .{ .elems = &.{} },36291 .storage = .{ .elems = field_vals },
36119 } })).toValue();36292 } })).toValue();
36120 },36293 },
3612136294
...@@ -36266,7 +36439,7 @@ fn analyzeComptimeAlloc(...@@ -36266,7 +36439,7 @@ fn analyzeComptimeAlloc(
36266 // Needed to make an anon decl with type `var_type` (the `finish()` call below).36439 // Needed to make an anon decl with type `var_type` (the `finish()` call below).
36267 _ = try sema.typeHasOnePossibleValue(var_type);36440 _ = try sema.typeHasOnePossibleValue(var_type);
3626836441
36269 const ptr_type = try mod.ptrType(.{36442 const ptr_type = try sema.ptrType(.{
36270 .child = var_type.toIntern(),36443 .child = var_type.toIntern(),
36271 .flags = .{36444 .flags = .{
36272 .alignment = alignment,36445 .alignment = alignment,
...@@ -36574,25 +36747,36 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {...@@ -36574,25 +36747,36 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
36574 => true,36747 => true,
36575 },36748 },
36576 .struct_type => |struct_type| {36749 .struct_type => |struct_type| {
36577 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false;36750 if (struct_type.layout == .Packed) {
36578 switch (struct_obj.requires_comptime) {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) {
36579 .no, .wip => return false,36756 .no, .wip => return false,
36580 .yes => return true,36757 .yes => return true,
36581 .unknown => {36758 .unknown => {
36582 if (struct_obj.status == .field_types_wip)36759 if (struct_type.flagsPtr(ip).field_types_wip)
36583 return false;36760 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;36766 for (0..struct_type.field_types.len) |i_usize| {
36588 for (struct_obj.fields.values()) |field| {36767 const i: u32 = @intCast(i_usize);
36589 if (field.is_comptime) continue;36768 if (struct_type.fieldIsComptime(ip, i)) continue;
36590 if (try sema.typeRequiresComptime(field.ty)) {36769 const field_ty = struct_type.field_types.get(ip)[i];
36591 struct_obj.requires_comptime = .yes;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;
36592 return true;36776 return true;
36593 }36777 }
36594 }36778 }
36595 struct_obj.requires_comptime = .no;36779 struct_type.flagsPtr(ip).requires_comptime = .no;
36596 return false;36780 return false;
36597 },36781 },
36598 }36782 }
...@@ -36673,40 +36857,41 @@ fn typeAbiSize(sema: *Sema, ty: Type) !u64 {...@@ -36673,40 +36857,41 @@ fn typeAbiSize(sema: *Sema, ty: Type) !u64 {
36673 return ty.abiSize(sema.mod);36857 return ty.abiSize(sema.mod);
36674}36858}
3667536859
36676fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!u32 {36860fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!Alignment {
36677 return (try ty.abiAlignmentAdvanced(sema.mod, .{ .sema = sema })).scalar;36861 return (try ty.abiAlignmentAdvanced(sema.mod, .{ .sema = sema })).scalar;
36678}36862}
3667936863
36680/// Not valid to call for packed unions.36864/// Not valid to call for packed unions.
36681/// Keep implementation in sync with `Module.unionFieldNormalAlignment`.36865/// Keep implementation in sync with `Module.unionFieldNormalAlignment`.
36682/// TODO: this returns alignment in byte units should should be a u6436866fn unionFieldAlignment(sema: *Sema, u: InternPool.UnionType, field_index: u32) !Alignment {
36683fn unionFieldAlignment(sema: *Sema, u: InternPool.UnionType, field_index: u32) !u32 {
36684 const mod = sema.mod;36867 const mod = sema.mod;
36685 const ip = &mod.intern_pool;36868 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;
36687 const field_ty = u.field_types.get(ip)[field_index].toType();36871 const field_ty = u.field_types.get(ip)[field_index].toType();
36688 if (field_ty.isNoReturn(sema.mod)) return 0;36872 if (field_ty.isNoReturn(sema.mod)) return .none;
36689 return @intCast(try sema.typeAbiAlignment(field_ty));36873 return sema.typeAbiAlignment(field_ty);
36690}36874}
3669136875
36692/// Keep implementation in sync with `Module.Struct.Field.alignment`.36876/// Keep implementation in sync with `Module.structFieldAlignment`.
36693fn structFieldAlignment(sema: *Sema, field: Module.Struct.Field, layout: std.builtin.Type.ContainerLayout) !u32 {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;
36694 const mod = sema.mod;36885 const mod = sema.mod;
36695 if (field.abi_align.toByteUnitsOptional()) |a| {
36696 assert(layout != .Packed);
36697 return @intCast(a);
36698 }
36699 switch (layout) {36886 switch (layout) {
36700 .Packed => return 0,36887 .Packed => return .none,
36701 .Auto => if (mod.getTarget().ofmt != .c) {36888 .Auto => if (mod.getTarget().ofmt != .c) return sema.typeAbiAlignment(field_ty),
36702 return sema.typeAbiAlignment(field.ty);
36703 },
36704 .Extern => {},36889 .Extern => {},
36705 }36890 }
36706 // extern36891 // extern
36707 const ty_abi_align = try sema.typeAbiAlignment(field.ty);36892 const ty_abi_align = try sema.typeAbiAlignment(field_ty);
36708 if (field.ty.isAbiInt(mod) and field.ty.intInfo(mod).bits >= 128) {36893 if (field_ty.isAbiInt(mod) and field_ty.intInfo(mod).bits >= 128) {
36709 return @max(ty_abi_align, 16);36894 return ty_abi_align.maxStrict(.@"16");
36710 }36895 }
36711 return ty_abi_align;36896 return ty_abi_align;
36712}36897}
...@@ -36752,14 +36937,14 @@ fn structFieldIndex(...@@ -36752,14 +36937,14 @@ fn structFieldIndex(
36752 field_src: LazySrcLoc,36937 field_src: LazySrcLoc,
36753) !u32 {36938) !u32 {
36754 const mod = sema.mod;36939 const mod = sema.mod;
36940 const ip = &mod.intern_pool;
36755 try sema.resolveTypeFields(struct_ty);36941 try sema.resolveTypeFields(struct_ty);
36756 if (struct_ty.isAnonStruct(mod)) {36942 if (struct_ty.isAnonStruct(mod)) {
36757 return sema.anonStructFieldIndex(block, struct_ty, field_name, field_src);36943 return sema.anonStructFieldIndex(block, struct_ty, field_name, field_src);
36758 } else {36944 } else {
36759 const struct_obj = mod.typeToStruct(struct_ty).?;36945 const struct_type = mod.typeToStruct(struct_ty).?;
36760 const field_index_usize = struct_obj.fields.getIndex(field_name) orelse36946 return struct_type.nameIndex(ip, field_name) orelse
36761 return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);36947 return sema.failWithBadStructFieldAccess(block, struct_type, field_src, field_name);
36762 return @intCast(field_index_usize);
36763 }36948 }
36764}36949}
3676536950
...@@ -36776,13 +36961,7 @@ fn anonStructFieldIndex(...@@ -36776,13 +36961,7 @@ fn anonStructFieldIndex(
36776 .anon_struct_type => |anon_struct_type| for (anon_struct_type.names.get(ip), 0..) |name, i| {36961 .anon_struct_type => |anon_struct_type| for (anon_struct_type.names.get(ip), 0..) |name, i| {
36777 if (name == field_name) return @intCast(i);36962 if (name == field_name) return @intCast(i);
36778 },36963 },
36779 .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| {36964 .struct_type => |struct_type| if (struct_type.nameIndex(ip, field_name)) |i| return i,
36780 for (struct_obj.fields.keys(), 0..) |name, i| {
36781 if (name == field_name) {
36782 return @intCast(i);
36783 }
36784 }
36785 },
36786 else => unreachable,36965 else => unreachable,
36787 }36966 }
36788 return sema.fail(block, field_src, "no field named '{}' in anonymous struct '{}'", .{36967 return sema.fail(block, field_src, "no field named '{}' in anonymous struct '{}'", .{
...@@ -37167,8 +37346,8 @@ fn intFitsInType(...@@ -37167,8 +37346,8 @@ fn intFitsInType(
37167 // If it is u16 or bigger we know the alignment fits without resolving it.37346 // If it is u16 or bigger we know the alignment fits without resolving it.
37168 if (info.bits >= max_needed_bits) return true;37347 if (info.bits >= max_needed_bits) return true;
37169 const x = try sema.typeAbiAlignment(lazy_ty.toType());37348 const x = try sema.typeAbiAlignment(lazy_ty.toType());
37170 if (x == 0) return true;37349 if (x == .none) return true;
37171 const actual_needed_bits = std.math.log2(x) + 1 + @intFromBool(info.signedness == .signed);37350 const actual_needed_bits = @as(usize, x.toLog2Units()) + 1 + @intFromBool(info.signedness == .signed);
37172 return info.bits >= actual_needed_bits;37351 return info.bits >= actual_needed_bits;
37173 },37352 },
37174 .lazy_size => |lazy_ty| {37353 .lazy_size => |lazy_ty| {
...@@ -37381,7 +37560,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {...@@ -37381,7 +37560,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
3738137560
37382 const vector_info: struct {37561 const vector_info: struct {
37383 host_size: u16 = 0,37562 host_size: u16 = 0,
37384 alignment: u32 = 0,37563 alignment: Alignment = .none,
37385 vector_index: VI = .none,37564 vector_index: VI = .none,
37386 } = if (parent_ty.isVector(mod) and ptr_info.flags.size == .One) blk: {37565 } = if (parent_ty.isVector(mod) and ptr_info.flags.size == .One) blk: {
37387 const elem_bits = elem_ty.bitSize(mod);37566 const elem_bits = elem_ty.bitSize(mod);
...@@ -37391,7 +37570,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {...@@ -37391,7 +37570,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
3739137570
37392 break :blk .{37571 break :blk .{
37393 .host_size = @intCast(parent_ty.arrayLen(mod)),37572 .host_size = @intCast(parent_ty.arrayLen(mod)),
37394 .alignment = @intCast(parent_ty.abiAlignment(mod)),37573 .alignment = parent_ty.abiAlignment(mod),
37395 .vector_index = if (offset) |some| @enumFromInt(some) else .runtime,37574 .vector_index = if (offset) |some| @enumFromInt(some) else .runtime,
37396 };37575 };
37397 } else .{};37576 } else .{};
...@@ -37399,9 +37578,9 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {...@@ -37399,9 +37578,9 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
37399 const alignment: Alignment = a: {37578 const alignment: Alignment = a: {
37400 // Calculate the new pointer alignment.37579 // Calculate the new pointer alignment.
37401 if (ptr_info.flags.alignment == .none) {37580 if (ptr_info.flags.alignment == .none) {
37402 if (vector_info.alignment != 0) break :a Alignment.fromNonzeroByteUnits(vector_info.alignment);37581 // In case of an ABI-aligned pointer, any pointer arithmetic
37403 // ABI-aligned pointer. Any pointer arithmetic maintains the same ABI-alignedness.37582 // maintains the same ABI-alignedness.
37404 break :a .none;37583 break :a vector_info.alignment;
37405 }37584 }
37406 // If the addend is not a comptime-known value we can still count on37585 // If the addend is not a comptime-known value we can still count on
37407 // it being a multiple of the type size.37586 // it being a multiple of the type size.
...@@ -37413,12 +37592,12 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {...@@ -37413,12 +37592,12 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
37413 // non zero).37592 // non zero).
37414 const new_align: Alignment = @enumFromInt(@min(37593 const new_align: Alignment = @enumFromInt(@min(
37415 @ctz(addend),37594 @ctz(addend),
37416 @intFromEnum(ptr_info.flags.alignment),37595 ptr_info.flags.alignment.toLog2Units(),
37417 ));37596 ));
37418 assert(new_align != .none);37597 assert(new_align != .none);
37419 break :a new_align;37598 break :a new_align;
37420 };37599 };
37421 return mod.ptrType(.{37600 return sema.ptrType(.{
37422 .child = elem_ty.toIntern(),37601 .child = elem_ty.toIntern(),
37423 .flags = .{37602 .flags = .{
37424 .alignment = alignment,37603 .alignment = alignment,
...@@ -37473,3 +37652,10 @@ fn isKnownZigType(sema: *Sema, ref: Air.Inst.Ref, tag: std.builtin.TypeId) bool...@@ -37473,3 +37652,10 @@ fn isKnownZigType(sema: *Sema, ref: Air.Inst.Ref, tag: std.builtin.TypeId) bool
37473 };37652 };
37474 return sema.typeOf(ref).zigTypeTag(sema.mod) == tag;37653 return sema.typeOf(ref).zigTypeTag(sema.mod) == tag;
37475}37654}
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(...@@ -135,9 +135,10 @@ pub fn print(
135135
136 var i: u32 = 0;136 var i: u32 = 0;
137 while (i < max_len) : (i += 1) {137 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) {
139 error.OutOfMemory => @panic("OOM"), // TODO: eliminate this panic139 error.OutOfMemory => @panic("OOM"), // TODO: eliminate this panic
140 };140 };
141 const elem_val = maybe_elem_val orelse return writer.writeAll(".{ (reinterpreted data) }");
141 if (elem_val.isUndef(mod)) break :str;142 if (elem_val.isUndef(mod)) break :str;
142 buf[i] = std.math.cast(u8, elem_val.toUnsignedInt(mod)) orelse break :str;143 buf[i] = std.math.cast(u8, elem_val.toUnsignedInt(mod)) orelse break :str;
143 }144 }
...@@ -153,9 +154,10 @@ pub fn print(...@@ -153,9 +154,10 @@ pub fn print(
153 var i: u32 = 0;154 var i: u32 = 0;
154 while (i < max_len) : (i += 1) {155 while (i < max_len) : (i += 1) {
155 if (i != 0) try writer.writeAll(", ");156 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) {
157 error.OutOfMemory => @panic("OOM"), // TODO: eliminate this panic158 error.OutOfMemory => @panic("OOM"), // TODO: eliminate this panic
158 };159 };
160 const elem_val = maybe_elem_val orelse return writer.writeAll("(reinterpreted data) }");
159 try print(.{161 try print(.{
160 .ty = elem_ty,162 .ty = elem_ty,
161 .val = elem_val,163 .val = elem_val,
...@@ -272,7 +274,8 @@ pub fn print(...@@ -272,7 +274,8 @@ pub fn print(
272 const max_len = @min(len, max_string_len);274 const max_len = @min(len, max_string_len);
273 var buf: [max_string_len]u8 = undefined;275 var buf: [max_string_len]u8 = undefined;
274 for (buf[0..max_len], 0..) |*c, i| {276 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) }");
276 if (elem.isUndef(mod)) break :str;279 if (elem.isUndef(mod)) break :str;
277 c.* = @as(u8, @intCast(elem.toUnsignedInt(mod)));280 c.* = @as(u8, @intCast(elem.toUnsignedInt(mod)));
278 }281 }
...@@ -283,9 +286,11 @@ pub fn print(...@@ -283,9 +286,11 @@ pub fn print(
283 const max_len = @min(len, max_aggregate_items);286 const max_len = @min(len, max_aggregate_items);
284 for (0..max_len) |i| {287 for (0..max_len) |i| {
285 if (i != 0) try writer.writeAll(", ");288 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) }");
286 try print(.{291 try print(.{
287 .ty = elem_ty,292 .ty = elem_ty,
288 .val = try val.elemValue(mod, i),293 .val = elem,
289 }, writer, level - 1, mod);294 }, writer, level - 1, mod);
290 }295 }
291 if (len > max_aggregate_items) {296 if (len > max_aggregate_items) {
...@@ -350,11 +355,11 @@ pub fn print(...@@ -350,11 +355,11 @@ pub fn print(
350 const container_ty = ptr_container_ty.childType(mod);355 const container_ty = ptr_container_ty.childType(mod);
351 switch (container_ty.zigTypeTag(mod)) {356 switch (container_ty.zigTypeTag(mod)) {
352 .Struct => {357 .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 {
354 try writer.print("[{d}]", .{field.index});361 try writer.print("[{d}]", .{field.index});
355 }362 }
356 const field_name = container_ty.structFieldName(@as(usize, @intCast(field.index)), mod);
357 try writer.print(".{i}", .{field_name.fmt(ip)});
358 },363 },
359 .Union => {364 .Union => {
360 const field_name = mod.typeToUnion(container_ty).?.field_names.get(ip)[@intCast(field.index)];365 const field_name = mod.typeToUnion(container_ty).?.field_names.get(ip)[@intCast(field.index)];
...@@ -432,7 +437,7 @@ fn printAggregate(...@@ -432,7 +437,7 @@ fn printAggregate(
432 if (i != 0) try writer.writeAll(", ");437 if (i != 0) try writer.writeAll(", ");
433438
434 const field_name = switch (ip.indexToKey(ty.toIntern())) {439 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),
436 .anon_struct_type => |x| if (x.isTuple()) .none else x.names.get(ip)[i].toOptional(),441 .anon_struct_type => |x| if (x.isTuple()) .none else x.names.get(ip)[i].toOptional(),
437 else => unreachable,442 else => unreachable,
438 };443 };
src/Zir.zig+4-1
...@@ -2840,7 +2840,10 @@ pub const Inst = struct {...@@ -2840,7 +2840,10 @@ pub const Inst = struct {
2840 is_tuple: bool,2840 is_tuple: bool,
2841 name_strategy: NameStrategy,2841 name_strategy: NameStrategy,
2842 layout: std.builtin.Type.ContainerLayout,2842 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,
2844 };2847 };
2845 };2848 };
28462849
src/arch/aarch64/CodeGen.zig+20-27
...@@ -23,6 +23,7 @@ const DW = std.dwarf;...@@ -23,6 +23,7 @@ const DW = std.dwarf;
23const leb128 = std.leb;23const leb128 = std.leb;
24const log = std.log.scoped(.codegen);24const log = std.log.scoped(.codegen);
25const build_options = @import("build_options");25const build_options = @import("build_options");
26const Alignment = InternPool.Alignment;
2627
27const CodeGenError = codegen.CodeGenError;28const CodeGenError = codegen.CodeGenError;
28const Result = codegen.Result;29const Result = codegen.Result;
...@@ -506,11 +507,9 @@ fn gen(self: *Self) !void {...@@ -506,11 +507,9 @@ fn gen(self: *Self) !void {
506 // (or w0 when pointer size is 32 bits). As this register507 // (or w0 when pointer size is 32 bits). As this register
507 // might get overwritten along the way, save the address508 // might get overwritten along the way, save the address
508 // to the stack.509 // to the stack.
509 const ptr_bits = self.target.ptrBitWidth();
510 const ptr_bytes = @divExact(ptr_bits, 8);
511 const ret_ptr_reg = self.registerAlias(.x0, Type.usize);510 const ret_ptr_reg = self.registerAlias(.x0, Type.usize);
512511
513 const stack_offset = try self.allocMem(ptr_bytes, ptr_bytes, null);512 const stack_offset = try self.allocMem(8, .@"8", null);
514513
515 try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = ret_ptr_reg });514 try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = ret_ptr_reg });
516 self.ret_mcv = MCValue{ .stack_offset = stack_offset };515 self.ret_mcv = MCValue{ .stack_offset = stack_offset };
...@@ -998,11 +997,11 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {...@@ -998,11 +997,11 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
998fn allocMem(997fn allocMem(
999 self: *Self,998 self: *Self,
1000 abi_size: u32,999 abi_size: u32,
1001 abi_align: u32,1000 abi_align: Alignment,
1002 maybe_inst: ?Air.Inst.Index,1001 maybe_inst: ?Air.Inst.Index,
1003) !u32 {1002) !u32 {
1004 assert(abi_size > 0);1003 assert(abi_size > 0);
1005 assert(abi_align > 0);1004 assert(abi_align != .none);
10061005
1007 // In order to efficiently load and store stack items that fit1006 // In order to efficiently load and store stack items that fit
1008 // into registers, we bump up the alignment to the next power of1007 // into registers, we bump up the alignment to the next power of
...@@ -1010,10 +1009,10 @@ fn allocMem(...@@ -1010,10 +1009,10 @@ fn allocMem(
1010 const adjusted_align = if (abi_size > 8)1009 const adjusted_align = if (abi_size > 8)
1011 abi_align1010 abi_align
1012 else1011 else
1013 std.math.ceilPowerOfTwoAssert(u32, abi_size);1012 Alignment.fromNonzeroByteUnits(std.math.ceilPowerOfTwoAssert(u64, abi_size));
10141013
1015 // TODO find a free slot instead of always appending1014 // TODO find a free slot instead of always appending
1016 const offset = mem.alignForward(u32, self.next_stack_offset, adjusted_align) + abi_size;1015 const offset: u32 = @intCast(adjusted_align.forward(self.next_stack_offset) + abi_size);
1017 self.next_stack_offset = offset;1016 self.next_stack_offset = offset;
1018 self.max_end_stack = @max(self.max_end_stack, self.next_stack_offset);1017 self.max_end_stack = @max(self.max_end_stack, self.next_stack_offset);
10191018
...@@ -1515,12 +1514,9 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -1515,12 +1514,9 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
1515 const len = try self.resolveInst(bin_op.rhs);1514 const len = try self.resolveInst(bin_op.rhs);
1516 const len_ty = self.typeOf(bin_op.rhs);1515 const len_ty = self.typeOf(bin_op.rhs);
15171516
1518 const ptr_bits = self.target.ptrBitWidth();1517 const stack_offset = try self.allocMem(16, .@"8", inst);
1519 const ptr_bytes = @divExact(ptr_bits, 8);
1520
1521 const stack_offset = try self.allocMem(ptr_bytes * 2, ptr_bytes * 2, inst);
1522 try self.genSetStack(ptr_ty, stack_offset, ptr);1518 try self.genSetStack(ptr_ty, stack_offset, ptr);
1523 try self.genSetStack(len_ty, stack_offset - ptr_bytes, len);1519 try self.genSetStack(len_ty, stack_offset - 8, len);
1524 break :result MCValue{ .stack_offset = stack_offset };1520 break :result MCValue{ .stack_offset = stack_offset };
1525 };1521 };
1526 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1522 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
...@@ -3285,9 +3281,9 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {...@@ -3285,9 +3281,9 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
3285 break :result MCValue{ .register = reg };3281 break :result MCValue{ .register = reg };
3286 }3282 }
32873283
3288 const optional_abi_size = @as(u32, @intCast(optional_ty.abiSize(mod)));3284 const optional_abi_size: u32 = @intCast(optional_ty.abiSize(mod));
3289 const optional_abi_align = optional_ty.abiAlignment(mod);3285 const optional_abi_align = optional_ty.abiAlignment(mod);
3290 const offset = @as(u32, @intCast(payload_ty.abiSize(mod)));3286 const offset: u32 = @intCast(payload_ty.abiSize(mod));
32913287
3292 const stack_offset = try self.allocMem(optional_abi_size, optional_abi_align, inst);3288 const stack_offset = try self.allocMem(optional_abi_size, optional_abi_align, inst);
3293 try self.genSetStack(payload_ty, stack_offset, operand);3289 try self.genSetStack(payload_ty, stack_offset, operand);
...@@ -3376,7 +3372,7 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -3376,7 +3372,7 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
3376fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {3372fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
3377 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3373 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3378 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {3374 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
3379 const ptr_bits = self.target.ptrBitWidth();3375 const ptr_bits = 64;
3380 const ptr_bytes = @divExact(ptr_bits, 8);3376 const ptr_bytes = @divExact(ptr_bits, 8);
3381 const mcv = try self.resolveInst(ty_op.operand);3377 const mcv = try self.resolveInst(ty_op.operand);
3382 switch (mcv) {3378 switch (mcv) {
...@@ -3400,7 +3396,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {...@@ -3400,7 +3396,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
3400fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {3396fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void {
3401 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3397 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3402 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {3398 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
3403 const ptr_bits = self.target.ptrBitWidth();3399 const ptr_bits = 64;
3404 const ptr_bytes = @divExact(ptr_bits, 8);3400 const ptr_bytes = @divExact(ptr_bits, 8);
3405 const mcv = try self.resolveInst(ty_op.operand);3401 const mcv = try self.resolveInst(ty_op.operand);
3406 switch (mcv) {3402 switch (mcv) {
...@@ -4272,8 +4268,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4272,8 +4268,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4272 if (info.return_value == .stack_offset) {4268 if (info.return_value == .stack_offset) {
4273 log.debug("airCall: return by reference", .{});4269 log.debug("airCall: return by reference", .{});
4274 const ret_ty = fn_ty.fnReturnType(mod);4270 const ret_ty = fn_ty.fnReturnType(mod);
4275 const ret_abi_size = @as(u32, @intCast(ret_ty.abiSize(mod)));4271 const ret_abi_size: u32 = @intCast(ret_ty.abiSize(mod));
4276 const ret_abi_align = @as(u32, @intCast(ret_ty.abiAlignment(mod)));4272 const ret_abi_align = ret_ty.abiAlignment(mod);
4277 const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst);4273 const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst);
42784274
4279 const ret_ptr_reg = self.registerAlias(.x0, Type.usize);4275 const ret_ptr_reg = self.registerAlias(.x0, Type.usize);
...@@ -5939,11 +5935,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -5939,11 +5935,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
5939 const ptr = try self.resolveInst(ty_op.operand);5935 const ptr = try self.resolveInst(ty_op.operand);
5940 const array_ty = ptr_ty.childType(mod);5936 const array_ty = ptr_ty.childType(mod);
5941 const array_len = @as(u32, @intCast(array_ty.arrayLen(mod)));5937 const array_len = @as(u32, @intCast(array_ty.arrayLen(mod)));
59425938 const ptr_bytes = 8;
5943 const ptr_bits = self.target.ptrBitWidth();5939 const stack_offset = try self.allocMem(ptr_bytes * 2, .@"8", inst);
5944 const ptr_bytes = @divExact(ptr_bits, 8);
5945
5946 const stack_offset = try self.allocMem(ptr_bytes * 2, ptr_bytes * 2, inst);
5947 try self.genSetStack(ptr_ty, stack_offset, ptr);5940 try self.genSetStack(ptr_ty, stack_offset, ptr);
5948 try self.genSetStack(Type.usize, stack_offset - ptr_bytes, .{ .immediate = array_len });5941 try self.genSetStack(Type.usize, stack_offset - ptr_bytes, .{ .immediate = array_len });
5949 break :result MCValue{ .stack_offset = stack_offset };5942 break :result MCValue{ .stack_offset = stack_offset };
...@@ -6254,7 +6247,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -6254,7 +6247,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
62546247
6255 // We round up NCRN only for non-Apple platforms which allow the 16-byte aligned6248 // We round up NCRN only for non-Apple platforms which allow the 16-byte aligned
6256 // values to spread across odd-numbered registers.6249 // values to spread across odd-numbered registers.
6257 if (ty.toType().abiAlignment(mod) == 16 and !self.target.isDarwin()) {6250 if (ty.toType().abiAlignment(mod) == .@"16" and !self.target.isDarwin()) {
6258 // Round up NCRN to the next even number6251 // Round up NCRN to the next even number
6259 ncrn += ncrn % 2;6252 ncrn += ncrn % 2;
6260 }6253 }
...@@ -6272,7 +6265,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -6272,7 +6265,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
6272 ncrn = 8;6265 ncrn = 8;
6273 // TODO Apple allows the arguments on the stack to be non-8-byte aligned provided6266 // TODO Apple allows the arguments on the stack to be non-8-byte aligned provided
6274 // that the entire stack space consumed by the arguments is 8-byte aligned.6267 // that the entire stack space consumed by the arguments is 8-byte aligned.
6275 if (ty.toType().abiAlignment(mod) == 8) {6268 if (ty.toType().abiAlignment(mod) == .@"8") {
6276 if (nsaa % 8 != 0) {6269 if (nsaa % 8 != 0) {
6277 nsaa += 8 - (nsaa % 8);6270 nsaa += 8 - (nsaa % 8);
6278 }6271 }
...@@ -6312,10 +6305,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -6312,10 +6305,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
63126305
6313 for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| {6306 for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| {
6314 if (ty.toType().abiSize(mod) > 0) {6307 if (ty.toType().abiSize(mod) > 0) {
6315 const param_size = @as(u32, @intCast(ty.toType().abiSize(mod)));6308 const param_size: u32 = @intCast(ty.toType().abiSize(mod));
6316 const param_alignment = ty.toType().abiAlignment(mod);6309 const param_alignment = ty.toType().abiAlignment(mod);
63176310
6318 stack_offset = std.mem.alignForward(u32, stack_offset, param_alignment);6311 stack_offset = @intCast(param_alignment.forward(stack_offset));
6319 result_arg.* = .{ .stack_argument_offset = stack_offset };6312 result_arg.* = .{ .stack_argument_offset = stack_offset };
6320 stack_offset += param_size;6313 stack_offset += param_size;
6321 } else {6314 } else {
src/arch/arm/CodeGen.zig+13-12
...@@ -23,6 +23,7 @@ const DW = std.dwarf;...@@ -23,6 +23,7 @@ const DW = std.dwarf;
23const leb128 = std.leb;23const leb128 = std.leb;
24const log = std.log.scoped(.codegen);24const log = std.log.scoped(.codegen);
25const build_options = @import("build_options");25const build_options = @import("build_options");
26const Alignment = InternPool.Alignment;
2627
27const Result = codegen.Result;28const Result = codegen.Result;
28const CodeGenError = codegen.CodeGenError;29const CodeGenError = codegen.CodeGenError;
...@@ -508,7 +509,7 @@ fn gen(self: *Self) !void {...@@ -508,7 +509,7 @@ fn gen(self: *Self) !void {
508 // The address of where to store the return value is in509 // The address of where to store the return value is in
509 // r0. As this register might get overwritten along the510 // r0. As this register might get overwritten along the
510 // way, save the address to the stack.511 // way, save the address to the stack.
511 const stack_offset = try self.allocMem(4, 4, null);512 const stack_offset = try self.allocMem(4, .@"4", null);
512513
513 try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = .r0 });514 try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = .r0 });
514 self.ret_mcv = MCValue{ .stack_offset = stack_offset };515 self.ret_mcv = MCValue{ .stack_offset = stack_offset };
...@@ -986,14 +987,14 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {...@@ -986,14 +987,14 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
986fn allocMem(987fn allocMem(
987 self: *Self,988 self: *Self,
988 abi_size: u32,989 abi_size: u32,
989 abi_align: u32,990 abi_align: Alignment,
990 maybe_inst: ?Air.Inst.Index,991 maybe_inst: ?Air.Inst.Index,
991) !u32 {992) !u32 {
992 assert(abi_size > 0);993 assert(abi_size > 0);
993 assert(abi_align > 0);994 assert(abi_align != .none);
994995
995 // TODO find a free slot instead of always appending996 // TODO find a free slot instead of always appending
996 const offset = mem.alignForward(u32, self.next_stack_offset, abi_align) + abi_size;997 const offset: u32 = @intCast(abi_align.forward(self.next_stack_offset) + abi_size);
997 self.next_stack_offset = offset;998 self.next_stack_offset = offset;
998 self.max_end_stack = @max(self.max_end_stack, self.next_stack_offset);999 self.max_end_stack = @max(self.max_end_stack, self.next_stack_offset);
9991000
...@@ -1490,7 +1491,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -1490,7 +1491,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
1490 const len = try self.resolveInst(bin_op.rhs);1491 const len = try self.resolveInst(bin_op.rhs);
1491 const len_ty = self.typeOf(bin_op.rhs);1492 const len_ty = self.typeOf(bin_op.rhs);
14921493
1493 const stack_offset = try self.allocMem(8, 4, inst);1494 const stack_offset = try self.allocMem(8, .@"4", inst);
1494 try self.genSetStack(ptr_ty, stack_offset, ptr);1495 try self.genSetStack(ptr_ty, stack_offset, ptr);
1495 try self.genSetStack(len_ty, stack_offset - 4, len);1496 try self.genSetStack(len_ty, stack_offset - 4, len);
1496 break :result MCValue{ .stack_offset = stack_offset };1497 break :result MCValue{ .stack_offset = stack_offset };
...@@ -4251,8 +4252,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4251,8 +4252,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4251 const r0_lock: ?RegisterLock = if (info.return_value == .stack_offset) blk: {4252 const r0_lock: ?RegisterLock = if (info.return_value == .stack_offset) blk: {
4252 log.debug("airCall: return by reference", .{});4253 log.debug("airCall: return by reference", .{});
4253 const ret_ty = fn_ty.fnReturnType(mod);4254 const ret_ty = fn_ty.fnReturnType(mod);
4254 const ret_abi_size = @as(u32, @intCast(ret_ty.abiSize(mod)));4255 const ret_abi_size: u32 = @intCast(ret_ty.abiSize(mod));
4255 const ret_abi_align = @as(u32, @intCast(ret_ty.abiAlignment(mod)));4256 const ret_abi_align = ret_ty.abiAlignment(mod);
4256 const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst);4257 const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst);
42574258
4258 const ptr_ty = try mod.singleMutPtrType(ret_ty);4259 const ptr_ty = try mod.singleMutPtrType(ret_ty);
...@@ -5896,7 +5897,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -5896,7 +5897,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
5896 const array_ty = ptr_ty.childType(mod);5897 const array_ty = ptr_ty.childType(mod);
5897 const array_len = @as(u32, @intCast(array_ty.arrayLen(mod)));5898 const array_len = @as(u32, @intCast(array_ty.arrayLen(mod)));
58985899
5899 const stack_offset = try self.allocMem(8, 8, inst);5900 const stack_offset = try self.allocMem(8, .@"8", inst);
5900 try self.genSetStack(ptr_ty, stack_offset, ptr);5901 try self.genSetStack(ptr_ty, stack_offset, ptr);
5901 try self.genSetStack(Type.usize, stack_offset - 4, .{ .immediate = array_len });5902 try self.genSetStack(Type.usize, stack_offset - 4, .{ .immediate = array_len });
5902 break :result MCValue{ .stack_offset = stack_offset };5903 break :result MCValue{ .stack_offset = stack_offset };
...@@ -6201,7 +6202,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -6201,7 +6202,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
6201 }6202 }
62026203
6203 for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| {6204 for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| {
6204 if (ty.toType().abiAlignment(mod) == 8)6205 if (ty.toType().abiAlignment(mod) == .@"8")
6205 ncrn = std.mem.alignForward(usize, ncrn, 2);6206 ncrn = std.mem.alignForward(usize, ncrn, 2);
62066207
6207 const param_size = @as(u32, @intCast(ty.toType().abiSize(mod)));6208 const param_size = @as(u32, @intCast(ty.toType().abiSize(mod)));
...@@ -6216,7 +6217,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -6216,7 +6217,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
6216 return self.fail("TODO MCValues split between registers and stack", .{});6217 return self.fail("TODO MCValues split between registers and stack", .{});
6217 } else {6218 } else {
6218 ncrn = 4;6219 ncrn = 4;
6219 if (ty.toType().abiAlignment(mod) == 8)6220 if (ty.toType().abiAlignment(mod) == .@"8")
6220 nsaa = std.mem.alignForward(u32, nsaa, 8);6221 nsaa = std.mem.alignForward(u32, nsaa, 8);
62216222
6222 result_arg.* = .{ .stack_argument_offset = nsaa };6223 result_arg.* = .{ .stack_argument_offset = nsaa };
...@@ -6252,10 +6253,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -6252,10 +6253,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
62526253
6253 for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| {6254 for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| {
6254 if (ty.toType().abiSize(mod) > 0) {6255 if (ty.toType().abiSize(mod) > 0) {
6255 const param_size = @as(u32, @intCast(ty.toType().abiSize(mod)));6256 const param_size: u32 = @intCast(ty.toType().abiSize(mod));
6256 const param_alignment = ty.toType().abiAlignment(mod);6257 const param_alignment = ty.toType().abiAlignment(mod);
62576258
6258 stack_offset = std.mem.alignForward(u32, stack_offset, param_alignment);6259 stack_offset = @intCast(param_alignment.forward(stack_offset));
6259 result_arg.* = .{ .stack_argument_offset = stack_offset };6260 result_arg.* = .{ .stack_argument_offset = stack_offset };
6260 stack_offset += param_size;6261 stack_offset += param_size;
6261 } else {6262 } else {
src/arch/arm/abi.zig+2-2
...@@ -47,7 +47,7 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class {...@@ -47,7 +47,7 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class {
47 const field_ty = ty.structFieldType(i, mod);47 const field_ty = ty.structFieldType(i, mod);
48 const field_alignment = ty.structFieldAlign(i, mod);48 const field_alignment = ty.structFieldAlign(i, mod);
49 const field_size = field_ty.bitSize(mod);49 const field_size = field_ty.bitSize(mod);
50 if (field_size > 32 or field_alignment > 32) {50 if (field_size > 32 or field_alignment.compare(.gt, .@"32")) {
51 return Class.arrSize(bit_size, 64);51 return Class.arrSize(bit_size, 64);
52 }52 }
53 }53 }
...@@ -66,7 +66,7 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class {...@@ -66,7 +66,7 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class {
6666
67 for (union_obj.field_types.get(ip), 0..) |field_ty, field_index| {67 for (union_obj.field_types.get(ip), 0..) |field_ty, field_index| {
68 if (field_ty.toType().bitSize(mod) > 32 or68 if (field_ty.toType().bitSize(mod) > 32 or
69 mod.unionFieldNormalAlignment(union_obj, @intCast(field_index)) > 32)69 mod.unionFieldNormalAlignment(union_obj, @intCast(field_index)).compare(.gt, .@"32"))
70 {70 {
71 return Class.arrSize(bit_size, 64);71 return Class.arrSize(bit_size, 64);
72 }72 }
src/arch/riscv64/CodeGen.zig+9-10
...@@ -23,6 +23,7 @@ const leb128 = std.leb;...@@ -23,6 +23,7 @@ const leb128 = std.leb;
23const log = std.log.scoped(.codegen);23const log = std.log.scoped(.codegen);
24const build_options = @import("build_options");24const build_options = @import("build_options");
25const codegen = @import("../../codegen.zig");25const codegen = @import("../../codegen.zig");
26const Alignment = InternPool.Alignment;
2627
27const CodeGenError = codegen.CodeGenError;28const CodeGenError = codegen.CodeGenError;
28const Result = codegen.Result;29const Result = codegen.Result;
...@@ -53,7 +54,7 @@ ret_mcv: MCValue,...@@ -53,7 +54,7 @@ ret_mcv: MCValue,
53fn_type: Type,54fn_type: Type,
54arg_index: usize,55arg_index: usize,
55src_loc: Module.SrcLoc,56src_loc: Module.SrcLoc,
56stack_align: u32,57stack_align: Alignment,
5758
58/// MIR Instructions59/// MIR Instructions
59mir_instructions: std.MultiArrayList(Mir.Inst) = .{},60mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
...@@ -788,11 +789,10 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {...@@ -788,11 +789,10 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
788 try table.ensureUnusedCapacity(self.gpa, additional_count);789 try table.ensureUnusedCapacity(self.gpa, additional_count);
789}790}
790791
791fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 {792fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: Alignment) !u32 {
792 if (abi_align > self.stack_align)793 self.stack_align = self.stack_align.max(abi_align);
793 self.stack_align = abi_align;
794 // TODO find a free slot instead of always appending794 // TODO find a free slot instead of always appending
795 const offset = mem.alignForward(u32, self.next_stack_offset, abi_align);795 const offset: u32 = @intCast(abi_align.forward(self.next_stack_offset));
796 self.next_stack_offset = offset + abi_size;796 self.next_stack_offset = offset + abi_size;
797 if (self.next_stack_offset > self.max_end_stack)797 if (self.next_stack_offset > self.max_end_stack)
798 self.max_end_stack = self.next_stack_offset;798 self.max_end_stack = self.next_stack_offset;
...@@ -822,8 +822,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {...@@ -822,8 +822,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
822 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)});822 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)});
823 };823 };
824 const abi_align = elem_ty.abiAlignment(mod);824 const abi_align = elem_ty.abiAlignment(mod);
825 if (abi_align > self.stack_align)825 self.stack_align = self.stack_align.max(abi_align);
826 self.stack_align = abi_align;
827826
828 if (reg_ok) {827 if (reg_ok) {
829 // Make sure the type can fit in a register before we try to allocate one.828 // Make sure the type can fit in a register before we try to allocate one.
...@@ -2602,7 +2601,7 @@ const CallMCValues = struct {...@@ -2602,7 +2601,7 @@ const CallMCValues = struct {
2602 args: []MCValue,2601 args: []MCValue,
2603 return_value: MCValue,2602 return_value: MCValue,
2604 stack_byte_count: u32,2603 stack_byte_count: u32,
2605 stack_align: u32,2604 stack_align: Alignment,
26062605
2607 fn deinit(self: *CallMCValues, func: *Self) void {2606 fn deinit(self: *CallMCValues, func: *Self) void {
2608 func.gpa.free(self.args);2607 func.gpa.free(self.args);
...@@ -2632,7 +2631,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -2632,7 +2631,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
2632 assert(result.args.len == 0);2631 assert(result.args.len == 0);
2633 result.return_value = .{ .unreach = {} };2632 result.return_value = .{ .unreach = {} };
2634 result.stack_byte_count = 0;2633 result.stack_byte_count = 0;
2635 result.stack_align = 1;2634 result.stack_align = .@"1";
2636 return result;2635 return result;
2637 },2636 },
2638 .Unspecified, .C => {2637 .Unspecified, .C => {
...@@ -2671,7 +2670,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -2671,7 +2670,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
2671 }2670 }
26722671
2673 result.stack_byte_count = next_stack_offset;2672 result.stack_byte_count = next_stack_offset;
2674 result.stack_align = 16;2673 result.stack_align = .@"16";
2675 },2674 },
2676 else => return self.fail("TODO implement function parameters for {} on riscv64", .{cc}),2675 else => return self.fail("TODO implement function parameters for {} on riscv64", .{cc}),
2677 }2676 }
src/arch/sparc64/CodeGen.zig+14-21
...@@ -24,6 +24,7 @@ const CodeGenError = codegen.CodeGenError;...@@ -24,6 +24,7 @@ const CodeGenError = codegen.CodeGenError;
24const Result = @import("../../codegen.zig").Result;24const Result = @import("../../codegen.zig").Result;
25const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;25const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
26const Endian = std.builtin.Endian;26const Endian = std.builtin.Endian;
27const Alignment = InternPool.Alignment;
2728
28const build_options = @import("build_options");29const build_options = @import("build_options");
2930
...@@ -62,7 +63,7 @@ ret_mcv: MCValue,...@@ -62,7 +63,7 @@ ret_mcv: MCValue,
62fn_type: Type,63fn_type: Type,
63arg_index: usize,64arg_index: usize,
64src_loc: Module.SrcLoc,65src_loc: Module.SrcLoc,
65stack_align: u32,66stack_align: Alignment,
6667
67/// MIR Instructions68/// MIR Instructions
68mir_instructions: std.MultiArrayList(Mir.Inst) = .{},69mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
...@@ -227,7 +228,7 @@ const CallMCValues = struct {...@@ -227,7 +228,7 @@ const CallMCValues = struct {
227 args: []MCValue,228 args: []MCValue,
228 return_value: MCValue,229 return_value: MCValue,
229 stack_byte_count: u32,230 stack_byte_count: u32,
230 stack_align: u32,231 stack_align: Alignment,
231232
232 fn deinit(self: *CallMCValues, func: *Self) void {233 fn deinit(self: *CallMCValues, func: *Self) void {
233 func.gpa.free(self.args);234 func.gpa.free(self.args);
...@@ -424,7 +425,7 @@ fn gen(self: *Self) !void {...@@ -424,7 +425,7 @@ fn gen(self: *Self) !void {
424425
425 // Backpatch stack offset426 // Backpatch stack offset
426 const total_stack_size = self.max_end_stack + abi.stack_reserved_area;427 const total_stack_size = self.max_end_stack + abi.stack_reserved_area;
427 const stack_size = mem.alignForward(u32, total_stack_size, self.stack_align);428 const stack_size = self.stack_align.forward(total_stack_size);
428 if (math.cast(i13, stack_size)) |size| {429 if (math.cast(i13, stack_size)) |size| {
429 self.mir_instructions.set(save_inst, .{430 self.mir_instructions.set(save_inst, .{
430 .tag = .save,431 .tag = .save,
...@@ -880,11 +881,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -880,11 +881,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
880 const ptr = try self.resolveInst(ty_op.operand);881 const ptr = try self.resolveInst(ty_op.operand);
881 const array_ty = ptr_ty.childType(mod);882 const array_ty = ptr_ty.childType(mod);
882 const array_len = @as(u32, @intCast(array_ty.arrayLen(mod)));883 const array_len = @as(u32, @intCast(array_ty.arrayLen(mod)));
883884 const ptr_bytes = 8;
884 const ptr_bits = self.target.ptrBitWidth();885 const stack_offset = try self.allocMem(inst, ptr_bytes * 2, .@"8");
885 const ptr_bytes = @divExact(ptr_bits, 8);
886
887 const stack_offset = try self.allocMem(inst, ptr_bytes * 2, ptr_bytes * 2);
888 try self.genSetStack(ptr_ty, stack_offset, ptr);886 try self.genSetStack(ptr_ty, stack_offset, ptr);
889 try self.genSetStack(Type.usize, stack_offset - ptr_bytes, .{ .immediate = array_len });887 try self.genSetStack(Type.usize, stack_offset - ptr_bytes, .{ .immediate = array_len });
890 break :result MCValue{ .stack_offset = stack_offset };888 break :result MCValue{ .stack_offset = stack_offset };
...@@ -2438,11 +2436,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -2438,11 +2436,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
2438 const ptr_ty = self.typeOf(bin_op.lhs);2436 const ptr_ty = self.typeOf(bin_op.lhs);
2439 const len = try self.resolveInst(bin_op.rhs);2437 const len = try self.resolveInst(bin_op.rhs);
2440 const len_ty = self.typeOf(bin_op.rhs);2438 const len_ty = self.typeOf(bin_op.rhs);
24412439 const ptr_bytes = 8;
2442 const ptr_bits = self.target.ptrBitWidth();2440 const stack_offset = try self.allocMem(inst, ptr_bytes * 2, .@"8");
2443 const ptr_bytes = @divExact(ptr_bits, 8);
2444
2445 const stack_offset = try self.allocMem(inst, ptr_bytes * 2, ptr_bytes * 2);
2446 try self.genSetStack(ptr_ty, stack_offset, ptr);2441 try self.genSetStack(ptr_ty, stack_offset, ptr);
2447 try self.genSetStack(len_ty, stack_offset - ptr_bytes, len);2442 try self.genSetStack(len_ty, stack_offset - ptr_bytes, len);
2448 break :result MCValue{ .stack_offset = stack_offset };2443 break :result MCValue{ .stack_offset = stack_offset };
...@@ -2782,11 +2777,10 @@ fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {...@@ -2782,11 +2777,10 @@ fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
2782 return result_index;2777 return result_index;
2783}2778}
27842779
2785fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 {2780fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: Alignment) !u32 {
2786 if (abi_align > self.stack_align)2781 self.stack_align = self.stack_align.max(abi_align);
2787 self.stack_align = abi_align;
2788 // TODO find a free slot instead of always appending2782 // TODO find a free slot instead of always appending
2789 const offset = mem.alignForward(u32, self.next_stack_offset, abi_align) + abi_size;2783 const offset: u32 = @intCast(abi_align.forward(self.next_stack_offset) + abi_size);
2790 self.next_stack_offset = offset;2784 self.next_stack_offset = offset;
2791 if (self.next_stack_offset > self.max_end_stack)2785 if (self.next_stack_offset > self.max_end_stack)
2792 self.max_end_stack = self.next_stack_offset;2786 self.max_end_stack = self.next_stack_offset;
...@@ -2825,8 +2819,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {...@@ -2825,8 +2819,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
2825 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)});2819 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)});
2826 };2820 };
2827 const abi_align = elem_ty.abiAlignment(mod);2821 const abi_align = elem_ty.abiAlignment(mod);
2828 if (abi_align > self.stack_align)2822 self.stack_align = self.stack_align.max(abi_align);
2829 self.stack_align = abi_align;
28302823
2831 if (reg_ok) {2824 if (reg_ok) {
2832 // Make sure the type can fit in a register before we try to allocate one.2825 // Make sure the type can fit in a register before we try to allocate one.
...@@ -4479,7 +4472,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView)...@@ -4479,7 +4472,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView)
4479 assert(result.args.len == 0);4472 assert(result.args.len == 0);
4480 result.return_value = .{ .unreach = {} };4473 result.return_value = .{ .unreach = {} };
4481 result.stack_byte_count = 0;4474 result.stack_byte_count = 0;
4482 result.stack_align = 1;4475 result.stack_align = .@"1";
4483 return result;4476 return result;
4484 },4477 },
4485 .Unspecified, .C => {4478 .Unspecified, .C => {
...@@ -4521,7 +4514,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView)...@@ -4521,7 +4514,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView)
4521 }4514 }
45224515
4523 result.stack_byte_count = next_stack_offset;4516 result.stack_byte_count = next_stack_offset;
4524 result.stack_align = 16;4517 result.stack_align = .@"16";
45254518
4526 if (ret_ty.zigTypeTag(mod) == .NoReturn) {4519 if (ret_ty.zigTypeTag(mod) == .NoReturn) {
4527 result.return_value = .{ .unreach = {} };4520 result.return_value = .{ .unreach = {} };
src/arch/wasm/CodeGen.zig+88-75
...@@ -25,6 +25,7 @@ const target_util = @import("../../target.zig");...@@ -25,6 +25,7 @@ const target_util = @import("../../target.zig");
25const Mir = @import("Mir.zig");25const Mir = @import("Mir.zig");
26const Emit = @import("Emit.zig");26const Emit = @import("Emit.zig");
27const abi = @import("abi.zig");27const abi = @import("abi.zig");
28const Alignment = InternPool.Alignment;
28const errUnionPayloadOffset = codegen.errUnionPayloadOffset;29const errUnionPayloadOffset = codegen.errUnionPayloadOffset;
29const errUnionErrorOffset = codegen.errUnionErrorOffset;30const errUnionErrorOffset = codegen.errUnionErrorOffset;
3031
...@@ -709,7 +710,7 @@ stack_size: u32 = 0,...@@ -709,7 +710,7 @@ stack_size: u32 = 0,
709/// tool-conventions: https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md710/// tool-conventions: https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md
710/// and also what the llvm backend will emit.711/// and also what the llvm backend will emit.
711/// However, local variables or the usage of `@setAlignStack` can overwrite this default.712/// However, local variables or the usage of `@setAlignStack` can overwrite this default.
712stack_alignment: u32 = 16,713stack_alignment: Alignment = .@"16",
713714
714// For each individual Wasm valtype we store a seperate free list which715// For each individual Wasm valtype we store a seperate free list which
715// allows us to re-use locals that are no longer used. e.g. a temporary local.716// allows us to re-use locals that are no longer used. e.g. a temporary local.
...@@ -991,6 +992,7 @@ fn addExtraAssumeCapacity(func: *CodeGen, extra: anytype) error{OutOfMemory}!u32...@@ -991,6 +992,7 @@ fn addExtraAssumeCapacity(func: *CodeGen, extra: anytype) error{OutOfMemory}!u32
991/// Using a given `Type`, returns the corresponding type992/// Using a given `Type`, returns the corresponding type
992fn typeToValtype(ty: Type, mod: *Module) wasm.Valtype {993fn typeToValtype(ty: Type, mod: *Module) wasm.Valtype {
993 const target = mod.getTarget();994 const target = mod.getTarget();
995 const ip = &mod.intern_pool;
994 return switch (ty.zigTypeTag(mod)) {996 return switch (ty.zigTypeTag(mod)) {
995 .Float => switch (ty.floatBits(target)) {997 .Float => switch (ty.floatBits(target)) {
996 16 => wasm.Valtype.i32, // stored/loaded as u16998 16 => wasm.Valtype.i32, // stored/loaded as u16
...@@ -1005,12 +1007,12 @@ fn typeToValtype(ty: Type, mod: *Module) wasm.Valtype {...@@ -1005,12 +1007,12 @@ fn typeToValtype(ty: Type, mod: *Module) wasm.Valtype {
1005 if (info.bits > 32 and info.bits <= 128) break :blk wasm.Valtype.i64;1007 if (info.bits > 32 and info.bits <= 128) break :blk wasm.Valtype.i64;
1006 break :blk wasm.Valtype.i32; // represented as pointer to stack1008 break :blk wasm.Valtype.i32; // represented as pointer to stack
1007 },1009 },
1008 .Struct => switch (ty.containerLayout(mod)) {1010 .Struct => {
1009 .Packed => {1011 if (mod.typeToPackedStruct(ty)) |packed_struct| {
1010 const struct_obj = mod.typeToStruct(ty).?;1012 return typeToValtype(packed_struct.backingIntType(ip).toType(), mod);
1011 return typeToValtype(struct_obj.backing_int_ty, mod);1013 } else {
1012 },1014 return wasm.Valtype.i32;
1013 else => wasm.Valtype.i32,1015 }
1014 },1016 },
1015 .Vector => switch (determineSimdStoreStrategy(ty, mod)) {1017 .Vector => switch (determineSimdStoreStrategy(ty, mod)) {
1016 .direct => wasm.Valtype.v128,1018 .direct => wasm.Valtype.v128,
...@@ -1285,12 +1287,12 @@ fn genFunc(func: *CodeGen) InnerError!void {...@@ -1285,12 +1287,12 @@ fn genFunc(func: *CodeGen) InnerError!void {
1285 // store stack pointer so we can restore it when we return from the function1287 // store stack pointer so we can restore it when we return from the function
1286 try prologue.append(.{ .tag = .local_tee, .data = .{ .label = func.initial_stack_value.local.value } });1288 try prologue.append(.{ .tag = .local_tee, .data = .{ .label = func.initial_stack_value.local.value } });
1287 // get the total stack size1289 // get the total stack size
1288 const aligned_stack = std.mem.alignForward(u32, func.stack_size, func.stack_alignment);1290 const aligned_stack = func.stack_alignment.forward(func.stack_size);
1289 try prologue.append(.{ .tag = .i32_const, .data = .{ .imm32 = @as(i32, @intCast(aligned_stack)) } });1291 try prologue.append(.{ .tag = .i32_const, .data = .{ .imm32 = @intCast(aligned_stack) } });
1290 // substract it from the current stack pointer1292 // subtract it from the current stack pointer
1291 try prologue.append(.{ .tag = .i32_sub, .data = .{ .tag = {} } });1293 try prologue.append(.{ .tag = .i32_sub, .data = .{ .tag = {} } });
1292 // Get negative stack aligment1294 // Get negative stack aligment
1293 try prologue.append(.{ .tag = .i32_const, .data = .{ .imm32 = @as(i32, @intCast(func.stack_alignment)) * -1 } });1295 try prologue.append(.{ .tag = .i32_const, .data = .{ .imm32 = @as(i32, @intCast(func.stack_alignment.toByteUnitsOptional().?)) * -1 } });
1294 // Bitwise-and the value to get the new stack pointer to ensure the pointers are aligned with the abi alignment1296 // Bitwise-and the value to get the new stack pointer to ensure the pointers are aligned with the abi alignment
1295 try prologue.append(.{ .tag = .i32_and, .data = .{ .tag = {} } });1297 try prologue.append(.{ .tag = .i32_and, .data = .{ .tag = {} } });
1296 // store the current stack pointer as the bottom, which will be used to calculate all stack pointer offsets1298 // store the current stack pointer as the bottom, which will be used to calculate all stack pointer offsets
...@@ -1438,7 +1440,7 @@ fn lowerArg(func: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value:...@@ -1438,7 +1440,7 @@ fn lowerArg(func: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value:
1438 });1440 });
1439 try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{1441 try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{
1440 .offset = value.offset(),1442 .offset = value.offset(),
1441 .alignment = scalar_type.abiAlignment(mod),1443 .alignment = @intCast(scalar_type.abiAlignment(mod).toByteUnitsOptional().?),
1442 });1444 });
1443 }1445 }
1444 },1446 },
...@@ -1527,11 +1529,9 @@ fn allocStack(func: *CodeGen, ty: Type) !WValue {...@@ -1527,11 +1529,9 @@ fn allocStack(func: *CodeGen, ty: Type) !WValue {
1527 };1529 };
1528 const abi_align = ty.abiAlignment(mod);1530 const abi_align = ty.abiAlignment(mod);
15291531
1530 if (abi_align > func.stack_alignment) {1532 func.stack_alignment = func.stack_alignment.max(abi_align);
1531 func.stack_alignment = abi_align;
1532 }
15331533
1534 const offset = std.mem.alignForward(u32, func.stack_size, abi_align);1534 const offset: u32 = @intCast(abi_align.forward(func.stack_size));
1535 defer func.stack_size = offset + abi_size;1535 defer func.stack_size = offset + abi_size;
15361536
1537 return WValue{ .stack_offset = .{ .value = offset, .references = 1 } };1537 return WValue{ .stack_offset = .{ .value = offset, .references = 1 } };
...@@ -1560,11 +1560,9 @@ fn allocStackPtr(func: *CodeGen, inst: Air.Inst.Index) !WValue {...@@ -1560,11 +1560,9 @@ fn allocStackPtr(func: *CodeGen, inst: Air.Inst.Index) !WValue {
1560 pointee_ty.fmt(mod), pointee_ty.abiSize(mod),1560 pointee_ty.fmt(mod), pointee_ty.abiSize(mod),
1561 });1561 });
1562 };1562 };
1563 if (abi_alignment > func.stack_alignment) {1563 func.stack_alignment = func.stack_alignment.max(abi_alignment);
1564 func.stack_alignment = abi_alignment;
1565 }
15661564
1567 const offset = std.mem.alignForward(u32, func.stack_size, abi_alignment);1565 const offset: u32 = @intCast(abi_alignment.forward(func.stack_size));
1568 defer func.stack_size = offset + abi_size;1566 defer func.stack_size = offset + abi_size;
15691567
1570 return WValue{ .stack_offset = .{ .value = offset, .references = 1 } };1568 return WValue{ .stack_offset = .{ .value = offset, .references = 1 } };
...@@ -1749,10 +1747,8 @@ fn isByRef(ty: Type, mod: *Module) bool {...@@ -1749,10 +1747,8 @@ fn isByRef(ty: Type, mod: *Module) bool {
1749 return ty.hasRuntimeBitsIgnoreComptime(mod);1747 return ty.hasRuntimeBitsIgnoreComptime(mod);
1750 },1748 },
1751 .Struct => {1749 .Struct => {
1752 if (mod.typeToStruct(ty)) |struct_obj| {1750 if (mod.typeToPackedStruct(ty)) |packed_struct| {
1753 if (struct_obj.layout == .Packed and struct_obj.haveFieldTypes()) {1751 return isByRef(packed_struct.backingIntType(ip).toType(), mod);
1754 return isByRef(struct_obj.backing_int_ty, mod);
1755 }
1756 }1752 }
1757 return ty.hasRuntimeBitsIgnoreComptime(mod);1753 return ty.hasRuntimeBitsIgnoreComptime(mod);
1758 },1754 },
...@@ -2120,7 +2116,7 @@ fn airRet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2120,7 +2116,7 @@ fn airRet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2120 });2116 });
2121 try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{2117 try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{
2122 .offset = operand.offset(),2118 .offset = operand.offset(),
2123 .alignment = scalar_type.abiAlignment(mod),2119 .alignment = @intCast(scalar_type.abiAlignment(mod).toByteUnitsOptional().?),
2124 });2120 });
2125 },2121 },
2126 else => try func.emitWValue(operand),2122 else => try func.emitWValue(operand),
...@@ -2385,19 +2381,19 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE...@@ -2385,19 +2381,19 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
2385 },2381 },
2386 .Vector => switch (determineSimdStoreStrategy(ty, mod)) {2382 .Vector => switch (determineSimdStoreStrategy(ty, mod)) {
2387 .unrolled => {2383 .unrolled => {
2388 const len = @as(u32, @intCast(abi_size));2384 const len: u32 = @intCast(abi_size);
2389 return func.memcpy(lhs, rhs, .{ .imm32 = len });2385 return func.memcpy(lhs, rhs, .{ .imm32 = len });
2390 },2386 },
2391 .direct => {2387 .direct => {
2392 try func.emitWValue(lhs);2388 try func.emitWValue(lhs);
2393 try func.lowerToStack(rhs);2389 try func.lowerToStack(rhs);
2394 // TODO: Add helper functions for simd opcodes2390 // TODO: Add helper functions for simd opcodes
2395 const extra_index = @as(u32, @intCast(func.mir_extra.items.len));2391 const extra_index: u32 = @intCast(func.mir_extra.items.len);
2396 // stores as := opcode, offset, alignment (opcode::memarg)2392 // stores as := opcode, offset, alignment (opcode::memarg)
2397 try func.mir_extra.appendSlice(func.gpa, &[_]u32{2393 try func.mir_extra.appendSlice(func.gpa, &[_]u32{
2398 std.wasm.simdOpcode(.v128_store),2394 std.wasm.simdOpcode(.v128_store),
2399 offset + lhs.offset(),2395 offset + lhs.offset(),
2400 ty.abiAlignment(mod),2396 @intCast(ty.abiAlignment(mod).toByteUnits(0)),
2401 });2397 });
2402 return func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });2398 return func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
2403 },2399 },
...@@ -2451,7 +2447,10 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE...@@ -2451,7 +2447,10 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
2451 // store rhs value at stack pointer's location in memory2447 // store rhs value at stack pointer's location in memory
2452 try func.addMemArg(2448 try func.addMemArg(
2453 Mir.Inst.Tag.fromOpcode(opcode),2449 Mir.Inst.Tag.fromOpcode(opcode),
2454 .{ .offset = offset + lhs.offset(), .alignment = ty.abiAlignment(mod) },2450 .{
2451 .offset = offset + lhs.offset(),
2452 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
2453 },
2455 );2454 );
2456}2455}
24572456
...@@ -2510,7 +2509,7 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu...@@ -2510,7 +2509,7 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu
2510 try func.mir_extra.appendSlice(func.gpa, &[_]u32{2509 try func.mir_extra.appendSlice(func.gpa, &[_]u32{
2511 std.wasm.simdOpcode(.v128_load),2510 std.wasm.simdOpcode(.v128_load),
2512 offset + operand.offset(),2511 offset + operand.offset(),
2513 ty.abiAlignment(mod),2512 @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
2514 });2513 });
2515 try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });2514 try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
2516 return WValue{ .stack = {} };2515 return WValue{ .stack = {} };
...@@ -2526,7 +2525,10 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu...@@ -2526,7 +2525,10 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu
25262525
2527 try func.addMemArg(2526 try func.addMemArg(
2528 Mir.Inst.Tag.fromOpcode(opcode),2527 Mir.Inst.Tag.fromOpcode(opcode),
2529 .{ .offset = offset + operand.offset(), .alignment = ty.abiAlignment(mod) },2528 .{
2529 .offset = offset + operand.offset(),
2530 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
2531 },
2530 );2532 );
25312533
2532 return WValue{ .stack = {} };2534 return WValue{ .stack = {} };
...@@ -3023,10 +3025,10 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue...@@ -3023,10 +3025,10 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue
3023 else => blk: {3025 else => blk: {
3024 const layout: Module.UnionLayout = parent_ty.unionGetLayout(mod);3026 const layout: Module.UnionLayout = parent_ty.unionGetLayout(mod);
3025 if (layout.payload_size == 0) break :blk 0;3027 if (layout.payload_size == 0) break :blk 0;
3026 if (layout.payload_align > layout.tag_align) break :blk 0;3028 if (layout.payload_align.compare(.gt, layout.tag_align)) break :blk 0;
30273029
3028 // tag is stored first so calculate offset from where payload starts3030 // tag is stored first so calculate offset from where payload starts
3029 break :blk @as(u32, @intCast(std.mem.alignForward(u64, layout.tag_size, layout.tag_align)));3031 break :blk layout.tag_align.forward(layout.tag_size);
3030 },3032 },
3031 },3033 },
3032 .Pointer => switch (parent_ty.ptrSize(mod)) {3034 .Pointer => switch (parent_ty.ptrSize(mod)) {
...@@ -3103,8 +3105,12 @@ fn toTwosComplement(value: anytype, bits: u7) std.meta.Int(.unsigned, @typeInfo(...@@ -3103,8 +3105,12 @@ fn toTwosComplement(value: anytype, bits: u7) std.meta.Int(.unsigned, @typeInfo(
3103 return @as(WantedT, @intCast(result));3105 return @as(WantedT, @intCast(result));
3104}3106}
31053107
3108/// This function is intended to assert that `isByRef` returns `false` for `ty`.
3109/// However such an assertion fails on the behavior tests currently.
3106fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {3110fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
3107 const mod = func.bin_file.base.options.module.?;3111 const mod = func.bin_file.base.options.module.?;
3112 // TODO: enable this assertion
3113 //assert(!isByRef(ty, mod));
3108 const ip = &mod.intern_pool;3114 const ip = &mod.intern_pool;
3109 var val = arg_val;3115 var val = arg_val;
3110 switch (ip.indexToKey(val.ip_index)) {3116 switch (ip.indexToKey(val.ip_index)) {
...@@ -3235,16 +3241,18 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {...@@ -3235,16 +3241,18 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
3235 val.writeToMemory(ty, mod, &buf) catch unreachable;3241 val.writeToMemory(ty, mod, &buf) catch unreachable;
3236 return func.storeSimdImmd(buf);3242 return func.storeSimdImmd(buf);
3237 },3243 },
3238 .struct_type, .anon_struct_type => {3244 .struct_type => |struct_type| {
3239 const struct_obj = mod.typeToStruct(ty).?;3245 // non-packed structs are not handled in this function because they
3240 assert(struct_obj.layout == .Packed);3246 // are by-ref types.
3247 assert(struct_type.layout == .Packed);
3241 var buf: [8]u8 = .{0} ** 8; // zero the buffer so we do not read 0xaa as integer3248 var buf: [8]u8 = .{0} ** 8; // zero the buffer so we do not read 0xaa as integer
3242 val.writeToPackedMemory(ty, func.bin_file.base.options.module.?, &buf, 0) catch unreachable;3249 val.writeToPackedMemory(ty, mod, &buf, 0) catch unreachable;
3250 const backing_int_ty = struct_type.backingIntType(ip).toType();
3243 const int_val = try mod.intValue(3251 const int_val = try mod.intValue(
3244 struct_obj.backing_int_ty,3252 backing_int_ty,
3245 std.mem.readIntLittle(u64, &buf),3253 mem.readIntLittle(u64, &buf),
3246 );3254 );
3247 return func.lowerConstant(int_val, struct_obj.backing_int_ty);3255 return func.lowerConstant(int_val, backing_int_ty);
3248 },3256 },
3249 else => unreachable,3257 else => unreachable,
3250 },3258 },
...@@ -3269,6 +3277,7 @@ fn storeSimdImmd(func: *CodeGen, value: [16]u8) !WValue {...@@ -3269,6 +3277,7 @@ fn storeSimdImmd(func: *CodeGen, value: [16]u8) !WValue {
32693277
3270fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue {3278fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue {
3271 const mod = func.bin_file.base.options.module.?;3279 const mod = func.bin_file.base.options.module.?;
3280 const ip = &mod.intern_pool;
3272 switch (ty.zigTypeTag(mod)) {3281 switch (ty.zigTypeTag(mod)) {
3273 .Bool, .ErrorSet => return WValue{ .imm32 = 0xaaaaaaaa },3282 .Bool, .ErrorSet => return WValue{ .imm32 = 0xaaaaaaaa },
3274 .Int, .Enum => switch (ty.intInfo(mod).bits) {3283 .Int, .Enum => switch (ty.intInfo(mod).bits) {
...@@ -3298,9 +3307,8 @@ fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue {...@@ -3298,9 +3307,8 @@ fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue {
3298 return WValue{ .imm32 = 0xaaaaaaaa };3307 return WValue{ .imm32 = 0xaaaaaaaa };
3299 },3308 },
3300 .Struct => {3309 .Struct => {
3301 const struct_obj = mod.typeToStruct(ty).?;3310 const packed_struct = mod.typeToPackedStruct(ty).?;
3302 assert(struct_obj.layout == .Packed);3311 return func.emitUndefined(packed_struct.backingIntType(ip).toType());
3303 return func.emitUndefined(struct_obj.backing_int_ty);
3304 },3312 },
3305 else => return func.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty.zigTypeTag(mod)}),3313 else => return func.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty.zigTypeTag(mod)}),
3306 }3314 }
...@@ -3340,7 +3348,7 @@ fn intStorageAsI32(storage: InternPool.Key.Int.Storage, mod: *Module) i32 {...@@ -3340,7 +3348,7 @@ fn intStorageAsI32(storage: InternPool.Key.Int.Storage, mod: *Module) i32 {
3340 .i64 => |x| @as(i32, @intCast(x)),3348 .i64 => |x| @as(i32, @intCast(x)),
3341 .u64 => |x| @as(i32, @bitCast(@as(u32, @intCast(x)))),3349 .u64 => |x| @as(i32, @bitCast(@as(u32, @intCast(x)))),
3342 .big_int => unreachable,3350 .big_int => unreachable,
3343 .lazy_align => |ty| @as(i32, @bitCast(ty.toType().abiAlignment(mod))),3351 .lazy_align => |ty| @as(i32, @bitCast(@as(u32, @intCast(ty.toType().abiAlignment(mod).toByteUnits(0))))),
3344 .lazy_size => |ty| @as(i32, @bitCast(@as(u32, @intCast(ty.toType().abiSize(mod))))),3352 .lazy_size => |ty| @as(i32, @bitCast(@as(u32, @intCast(ty.toType().abiSize(mod))))),
3345 };3353 };
3346}3354}
...@@ -3757,6 +3765,7 @@ fn structFieldPtr(...@@ -3757,6 +3765,7 @@ fn structFieldPtr(
37573765
3758fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {3766fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3759 const mod = func.bin_file.base.options.module.?;3767 const mod = func.bin_file.base.options.module.?;
3768 const ip = &mod.intern_pool;
3760 const ty_pl = func.air.instructions.items(.data)[inst].ty_pl;3769 const ty_pl = func.air.instructions.items(.data)[inst].ty_pl;
3761 const struct_field = func.air.extraData(Air.StructField, ty_pl.payload).data;3770 const struct_field = func.air.extraData(Air.StructField, ty_pl.payload).data;
37623771
...@@ -3769,9 +3778,9 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -3769,9 +3778,9 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3769 const result = switch (struct_ty.containerLayout(mod)) {3778 const result = switch (struct_ty.containerLayout(mod)) {
3770 .Packed => switch (struct_ty.zigTypeTag(mod)) {3779 .Packed => switch (struct_ty.zigTypeTag(mod)) {
3771 .Struct => result: {3780 .Struct => result: {
3772 const struct_obj = mod.typeToStruct(struct_ty).?;3781 const packed_struct = mod.typeToPackedStruct(struct_ty).?;
3773 const offset = struct_obj.packedFieldBitOffset(mod, field_index);3782 const offset = mod.structPackedFieldBitOffset(packed_struct, field_index);
3774 const backing_ty = struct_obj.backing_int_ty;3783 const backing_ty = packed_struct.backingIntType(ip).toType();
3775 const wasm_bits = toWasmBits(backing_ty.intInfo(mod).bits) orelse {3784 const wasm_bits = toWasmBits(backing_ty.intInfo(mod).bits) orelse {
3776 return func.fail("TODO: airStructFieldVal for packed structs larger than 128 bits", .{});3785 return func.fail("TODO: airStructFieldVal for packed structs larger than 128 bits", .{});
3777 };3786 };
...@@ -3793,7 +3802,7 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -3793,7 +3802,7 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3793 const truncated = try func.trunc(shifted_value, int_type, backing_ty);3802 const truncated = try func.trunc(shifted_value, int_type, backing_ty);
3794 const bitcasted = try func.bitcast(field_ty, int_type, truncated);3803 const bitcasted = try func.bitcast(field_ty, int_type, truncated);
3795 break :result try bitcasted.toLocal(func, field_ty);3804 break :result try bitcasted.toLocal(func, field_ty);
3796 } else if (field_ty.isPtrAtRuntime(mod) and struct_obj.fields.count() == 1) {3805 } else if (field_ty.isPtrAtRuntime(mod) and packed_struct.field_types.len == 1) {
3797 // In this case we do not have to perform any transformations,3806 // In this case we do not have to perform any transformations,
3798 // we can simply reuse the operand.3807 // we can simply reuse the operand.
3799 break :result func.reuseOperand(struct_field.struct_operand, operand);3808 break :result func.reuseOperand(struct_field.struct_operand, operand);
...@@ -4053,7 +4062,7 @@ fn airIsErr(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerErro...@@ -4053,7 +4062,7 @@ fn airIsErr(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerErro
4053 if (pl_ty.hasRuntimeBitsIgnoreComptime(mod)) {4062 if (pl_ty.hasRuntimeBitsIgnoreComptime(mod)) {
4054 try func.addMemArg(.i32_load16_u, .{4063 try func.addMemArg(.i32_load16_u, .{
4055 .offset = operand.offset() + @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod))),4064 .offset = operand.offset() + @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod))),
4056 .alignment = Type.anyerror.abiAlignment(mod),4065 .alignment = @intCast(Type.anyerror.abiAlignment(mod).toByteUnitsOptional().?),
4057 });4066 });
4058 }4067 }
40594068
...@@ -4141,7 +4150,10 @@ fn airWrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void...@@ -4141,7 +4150,10 @@ fn airWrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void
4141 try func.emitWValue(err_union);4150 try func.emitWValue(err_union);
4142 try func.addImm32(0);4151 try func.addImm32(0);
4143 const err_val_offset = @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod)));4152 const err_val_offset = @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod)));
4144 try func.addMemArg(.i32_store16, .{ .offset = err_union.offset() + err_val_offset, .alignment = 2 });4153 try func.addMemArg(.i32_store16, .{
4154 .offset = err_union.offset() + err_val_offset,
4155 .alignment = 2,
4156 });
4145 break :result err_union;4157 break :result err_union;
4146 };4158 };
4147 func.finishAir(inst, result, &.{ty_op.operand});4159 func.finishAir(inst, result, &.{ty_op.operand});
...@@ -4977,7 +4989,7 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4977,7 +4989,7 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4977 try func.mir_extra.appendSlice(func.gpa, &[_]u32{4989 try func.mir_extra.appendSlice(func.gpa, &[_]u32{
4978 opcode,4990 opcode,
4979 operand.offset(),4991 operand.offset(),
4980 elem_ty.abiAlignment(mod),4992 @intCast(elem_ty.abiAlignment(mod).toByteUnitsOptional().?),
4981 });4993 });
4982 try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });4994 try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
4983 try func.addLabel(.local_set, result.local.value);4995 try func.addLabel(.local_set, result.local.value);
...@@ -5065,7 +5077,7 @@ fn airShuffle(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5065,7 +5077,7 @@ fn airShuffle(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5065 std.wasm.simdOpcode(.i8x16_shuffle),5077 std.wasm.simdOpcode(.i8x16_shuffle),
5066 } ++ [1]u32{undefined} ** 4;5078 } ++ [1]u32{undefined} ** 4;
50675079
5068 var lanes = std.mem.asBytes(operands[1..]);5080 var lanes = mem.asBytes(operands[1..]);
5069 for (0..@as(usize, @intCast(mask_len))) |index| {5081 for (0..@as(usize, @intCast(mask_len))) |index| {
5070 const mask_elem = (try mask.elemValue(mod, index)).toSignedInt(mod);5082 const mask_elem = (try mask.elemValue(mod, index)).toSignedInt(mod);
5071 const base_index = if (mask_elem >= 0)5083 const base_index = if (mask_elem >= 0)
...@@ -5099,6 +5111,7 @@ fn airReduce(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5099,6 +5111,7 @@ fn airReduce(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
50995111
5100fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {5112fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5101 const mod = func.bin_file.base.options.module.?;5113 const mod = func.bin_file.base.options.module.?;
5114 const ip = &mod.intern_pool;
5102 const ty_pl = func.air.instructions.items(.data)[inst].ty_pl;5115 const ty_pl = func.air.instructions.items(.data)[inst].ty_pl;
5103 const result_ty = func.typeOfIndex(inst);5116 const result_ty = func.typeOfIndex(inst);
5104 const len = @as(usize, @intCast(result_ty.arrayLen(mod)));5117 const len = @as(usize, @intCast(result_ty.arrayLen(mod)));
...@@ -5150,13 +5163,13 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5150,13 +5163,13 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5150 if (isByRef(result_ty, mod)) {5163 if (isByRef(result_ty, mod)) {
5151 return func.fail("TODO: airAggregateInit for packed structs larger than 64 bits", .{});5164 return func.fail("TODO: airAggregateInit for packed structs larger than 64 bits", .{});
5152 }5165 }
5153 const struct_obj = mod.typeToStruct(result_ty).?;5166 const packed_struct = mod.typeToPackedStruct(result_ty).?;
5154 const fields = struct_obj.fields.values();5167 const field_types = packed_struct.field_types;
5155 const backing_type = struct_obj.backing_int_ty;5168 const backing_type = packed_struct.backingIntType(ip).toType();
51565169
5157 // ensure the result is zero'd5170 // ensure the result is zero'd
5158 const result = try func.allocLocal(backing_type);5171 const result = try func.allocLocal(backing_type);
5159 if (struct_obj.backing_int_ty.bitSize(mod) <= 32)5172 if (backing_type.bitSize(mod) <= 32)
5160 try func.addImm32(0)5173 try func.addImm32(0)
5161 else5174 else
5162 try func.addImm64(0);5175 try func.addImm64(0);
...@@ -5164,22 +5177,22 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5164,22 +5177,22 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
51645177
5165 var current_bit: u16 = 0;5178 var current_bit: u16 = 0;
5166 for (elements, 0..) |elem, elem_index| {5179 for (elements, 0..) |elem, elem_index| {
5167 const field = fields[elem_index];5180 const field_ty = field_types.get(ip)[elem_index].toType();
5168 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;5181 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
51695182
5170 const shift_val = if (struct_obj.backing_int_ty.bitSize(mod) <= 32)5183 const shift_val = if (backing_type.bitSize(mod) <= 32)
5171 WValue{ .imm32 = current_bit }5184 WValue{ .imm32 = current_bit }
5172 else5185 else
5173 WValue{ .imm64 = current_bit };5186 WValue{ .imm64 = current_bit };
51745187
5175 const value = try func.resolveInst(elem);5188 const value = try func.resolveInst(elem);
5176 const value_bit_size = @as(u16, @intCast(field.ty.bitSize(mod)));5189 const value_bit_size: u16 = @intCast(field_ty.bitSize(mod));
5177 const int_ty = try mod.intType(.unsigned, value_bit_size);5190 const int_ty = try mod.intType(.unsigned, value_bit_size);
51785191
5179 // load our current result on stack so we can perform all transformations5192 // load our current result on stack so we can perform all transformations
5180 // using only stack values. Saving the cost of loads and stores.5193 // using only stack values. Saving the cost of loads and stores.
5181 try func.emitWValue(result);5194 try func.emitWValue(result);
5182 const bitcasted = try func.bitcast(int_ty, field.ty, value);5195 const bitcasted = try func.bitcast(int_ty, field_ty, value);
5183 const extended_val = try func.intcast(bitcasted, int_ty, backing_type);5196 const extended_val = try func.intcast(bitcasted, int_ty, backing_type);
5184 // no need to shift any values when the current offset is 05197 // no need to shift any values when the current offset is 0
5185 const shifted = if (current_bit != 0) shifted: {5198 const shifted = if (current_bit != 0) shifted: {
...@@ -5199,7 +5212,7 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5199,7 +5212,7 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5199 if ((try result_ty.structFieldValueComptime(mod, elem_index)) != null) continue;5212 if ((try result_ty.structFieldValueComptime(mod, elem_index)) != null) continue;
52005213
5201 const elem_ty = result_ty.structFieldType(elem_index, mod);5214 const elem_ty = result_ty.structFieldType(elem_index, mod);
5202 const elem_size = @as(u32, @intCast(elem_ty.abiSize(mod)));5215 const elem_size: u32 = @intCast(elem_ty.abiSize(mod));
5203 const value = try func.resolveInst(elem);5216 const value = try func.resolveInst(elem);
5204 try func.store(offset, value, elem_ty, 0);5217 try func.store(offset, value, elem_ty, 0);
52055218
...@@ -5256,7 +5269,7 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5256,7 +5269,7 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5256 if (isByRef(union_ty, mod)) {5269 if (isByRef(union_ty, mod)) {
5257 const result_ptr = try func.allocStack(union_ty);5270 const result_ptr = try func.allocStack(union_ty);
5258 const payload = try func.resolveInst(extra.init);5271 const payload = try func.resolveInst(extra.init);
5259 if (layout.tag_align >= layout.payload_align) {5272 if (layout.tag_align.compare(.gte, layout.payload_align)) {
5260 if (isByRef(field_ty, mod)) {5273 if (isByRef(field_ty, mod)) {
5261 const payload_ptr = try func.buildPointerOffset(result_ptr, layout.tag_size, .new);5274 const payload_ptr = try func.buildPointerOffset(result_ptr, layout.tag_size, .new);
5262 try func.store(payload_ptr, payload, field_ty, 0);5275 try func.store(payload_ptr, payload, field_ty, 0);
...@@ -5420,9 +5433,9 @@ fn airSetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5420,9 +5433,9 @@ fn airSetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
54205433
5421 // when the tag alignment is smaller than the payload, the field will be stored5434 // when the tag alignment is smaller than the payload, the field will be stored
5422 // after the payload.5435 // after the payload.
5423 const offset = if (layout.tag_align < layout.payload_align) blk: {5436 const offset: u32 = if (layout.tag_align.compare(.lt, layout.payload_align)) blk: {
5424 break :blk @as(u32, @intCast(layout.payload_size));5437 break :blk @intCast(layout.payload_size);
5425 } else @as(u32, 0);5438 } else 0;
5426 try func.store(union_ptr, new_tag, tag_ty, offset);5439 try func.store(union_ptr, new_tag, tag_ty, offset);
5427 func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });5440 func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
5428}5441}
...@@ -5439,9 +5452,9 @@ fn airGetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5439,9 +5452,9 @@ fn airGetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5439 const operand = try func.resolveInst(ty_op.operand);5452 const operand = try func.resolveInst(ty_op.operand);
5440 // when the tag alignment is smaller than the payload, the field will be stored5453 // when the tag alignment is smaller than the payload, the field will be stored
5441 // after the payload.5454 // after the payload.
5442 const offset = if (layout.tag_align < layout.payload_align) blk: {5455 const offset: u32 = if (layout.tag_align.compare(.lt, layout.payload_align)) blk: {
5443 break :blk @as(u32, @intCast(layout.payload_size));5456 break :blk @intCast(layout.payload_size);
5444 } else @as(u32, 0);5457 } else 0;
5445 const tag = try func.load(operand, tag_ty, offset);5458 const tag = try func.load(operand, tag_ty, offset);
5446 const result = try tag.toLocal(func, tag_ty);5459 const result = try tag.toLocal(func, tag_ty);
5447 func.finishAir(inst, result, &.{ty_op.operand});5460 func.finishAir(inst, result, &.{ty_op.operand});
...@@ -6366,7 +6379,7 @@ fn lowerTry(...@@ -6366,7 +6379,7 @@ fn lowerTry(
6366 const err_offset = @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod)));6379 const err_offset = @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod)));
6367 try func.addMemArg(.i32_load16_u, .{6380 try func.addMemArg(.i32_load16_u, .{
6368 .offset = err_union.offset() + err_offset,6381 .offset = err_union.offset() + err_offset,
6369 .alignment = Type.anyerror.abiAlignment(mod),6382 .alignment = @intCast(Type.anyerror.abiAlignment(mod).toByteUnitsOptional().?),
6370 });6383 });
6371 }6384 }
6372 try func.addTag(.i32_eqz);6385 try func.addTag(.i32_eqz);
...@@ -7287,7 +7300,7 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7287,7 +7300,7 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7287 else => |size| return func.fail("TODO: implement `@cmpxchg` for types with abi size '{d}'", .{size}),7300 else => |size| return func.fail("TODO: implement `@cmpxchg` for types with abi size '{d}'", .{size}),
7288 }, .{7301 }, .{
7289 .offset = ptr_operand.offset(),7302 .offset = ptr_operand.offset(),
7290 .alignment = ty.abiAlignment(mod),7303 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
7291 });7304 });
7292 try func.addLabel(.local_tee, val_local.local.value);7305 try func.addLabel(.local_tee, val_local.local.value);
7293 _ = try func.cmp(.stack, expected_val, ty, .eq);7306 _ = try func.cmp(.stack, expected_val, ty, .eq);
...@@ -7349,7 +7362,7 @@ fn airAtomicLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7349,7 +7362,7 @@ fn airAtomicLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7349 try func.emitWValue(ptr);7362 try func.emitWValue(ptr);
7350 try func.addAtomicMemArg(tag, .{7363 try func.addAtomicMemArg(tag, .{
7351 .offset = ptr.offset(),7364 .offset = ptr.offset(),
7352 .alignment = ty.abiAlignment(mod),7365 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
7353 });7366 });
7354 } else {7367 } else {
7355 _ = try func.load(ptr, ty, 0);7368 _ = try func.load(ptr, ty, 0);
...@@ -7410,7 +7423,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7410,7 +7423,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7410 },7423 },
7411 .{7424 .{
7412 .offset = ptr.offset(),7425 .offset = ptr.offset(),
7413 .alignment = ty.abiAlignment(mod),7426 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
7414 },7427 },
7415 );7428 );
7416 const select_res = try func.allocLocal(ty);7429 const select_res = try func.allocLocal(ty);
...@@ -7470,7 +7483,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7470,7 +7483,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7470 };7483 };
7471 try func.addAtomicMemArg(tag, .{7484 try func.addAtomicMemArg(tag, .{
7472 .offset = ptr.offset(),7485 .offset = ptr.offset(),
7473 .alignment = ty.abiAlignment(mod),7486 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
7474 });7487 });
7475 const result = try WValue.toLocal(.stack, func, ty);7488 const result = try WValue.toLocal(.stack, func, ty);
7476 return func.finishAir(inst, result, &.{ pl_op.operand, extra.operand });7489 return func.finishAir(inst, result, &.{ pl_op.operand, extra.operand });
...@@ -7566,7 +7579,7 @@ fn airAtomicStore(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7566,7 +7579,7 @@ fn airAtomicStore(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7566 try func.lowerToStack(operand);7579 try func.lowerToStack(operand);
7567 try func.addAtomicMemArg(tag, .{7580 try func.addAtomicMemArg(tag, .{
7568 .offset = ptr.offset(),7581 .offset = ptr.offset(),
7569 .alignment = ty.abiAlignment(mod),7582 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
7570 });7583 });
7571 } else {7584 } else {
7572 try func.store(ptr, operand, ty, 0);7585 try func.store(ptr, operand, ty, 0);
src/arch/wasm/abi.zig+16-18
...@@ -28,20 +28,22 @@ pub fn classifyType(ty: Type, mod: *Module) [2]Class {...@@ -28,20 +28,22 @@ pub fn classifyType(ty: Type, mod: *Module) [2]Class {
28 if (!ty.hasRuntimeBitsIgnoreComptime(mod)) return none;28 if (!ty.hasRuntimeBitsIgnoreComptime(mod)) return none;
29 switch (ty.zigTypeTag(mod)) {29 switch (ty.zigTypeTag(mod)) {
30 .Struct => {30 .Struct => {
31 if (ty.containerLayout(mod) == .Packed) {31 const struct_type = mod.typeToStruct(ty).?;
32 if (struct_type.layout == .Packed) {
32 if (ty.bitSize(mod) <= 64) return direct;33 if (ty.bitSize(mod) <= 64) return direct;
33 return .{ .direct, .direct };34 return .{ .direct, .direct };
34 }35 }
35 // When the struct type is non-scalar36 if (struct_type.field_types.len > 1) {
36 if (ty.structFieldCount(mod) > 1) return memory;37 // The struct type is non-scalar.
37 // When the struct's alignment is non-natural38 return memory;
38 const field = ty.structFields(mod).values()[0];39 }
39 if (field.abi_align != .none) {40 const field_ty = struct_type.field_types.get(ip)[0].toType();
40 if (field.abi_align.toByteUnitsOptional().? > field.ty.abiAlignment(mod)) {41 const explicit_align = struct_type.fieldAlign(ip, 0);
42 if (explicit_align != .none) {
43 if (explicit_align.compareStrict(.gt, field_ty.abiAlignment(mod)))
41 return memory;44 return memory;
42 }
43 }45 }
44 return classifyType(field.ty, mod);46 return classifyType(field_ty, mod);
45 },47 },
46 .Int, .Enum, .ErrorSet, .Vector => {48 .Int, .Enum, .ErrorSet, .Vector => {
47 const int_bits = ty.intInfo(mod).bits;49 const int_bits = ty.intInfo(mod).bits;
...@@ -101,15 +103,11 @@ pub fn scalarType(ty: Type, mod: *Module) Type {...@@ -101,15 +103,11 @@ pub fn scalarType(ty: Type, mod: *Module) Type {
101 const ip = &mod.intern_pool;103 const ip = &mod.intern_pool;
102 switch (ty.zigTypeTag(mod)) {104 switch (ty.zigTypeTag(mod)) {
103 .Struct => {105 .Struct => {
104 switch (ty.containerLayout(mod)) {106 if (mod.typeToPackedStruct(ty)) |packed_struct| {
105 .Packed => {107 return scalarType(packed_struct.backingIntType(ip).toType(), mod);
106 const struct_obj = mod.typeToStruct(ty).?;108 } else {
107 return scalarType(struct_obj.backing_int_ty, mod);109 assert(ty.structFieldCount(mod) == 1);
108 },110 return scalarType(ty.structFieldType(0, mod), mod);
109 else => {
110 assert(ty.structFieldCount(mod) == 1);
111 return scalarType(ty.structFieldType(0, mod), mod);
112 },
113 }111 }
114 },112 },
115 .Union => {113 .Union => {
src/arch/x86_64/CodeGen.zig+61-58
...@@ -27,6 +27,7 @@ const Lower = @import("Lower.zig");...@@ -27,6 +27,7 @@ const Lower = @import("Lower.zig");
27const Mir = @import("Mir.zig");27const Mir = @import("Mir.zig");
28const Module = @import("../../Module.zig");28const Module = @import("../../Module.zig");
29const InternPool = @import("../../InternPool.zig");29const InternPool = @import("../../InternPool.zig");
30const Alignment = InternPool.Alignment;
30const Target = std.Target;31const Target = std.Target;
31const Type = @import("../../type.zig").Type;32const Type = @import("../../type.zig").Type;
32const TypedValue = @import("../../TypedValue.zig");33const TypedValue = @import("../../TypedValue.zig");
...@@ -607,19 +608,21 @@ const InstTracking = struct {...@@ -607,19 +608,21 @@ const InstTracking = struct {
607608
608const FrameAlloc = struct {609const FrameAlloc = struct {
609 abi_size: u31,610 abi_size: u31,
610 abi_align: u5,611 abi_align: Alignment,
611 ref_count: u16,612 ref_count: u16,
612613
613 fn init(alloc_abi: struct { size: u64, alignment: u32 }) FrameAlloc {614 fn init(alloc_abi: struct { size: u64, alignment: Alignment }) FrameAlloc {
614 assert(math.isPowerOfTwo(alloc_abi.alignment));
615 return .{615 return .{
616 .abi_size = @intCast(alloc_abi.size),616 .abi_size = @intCast(alloc_abi.size),
617 .abi_align = math.log2_int(u32, alloc_abi.alignment),617 .abi_align = alloc_abi.alignment,
618 .ref_count = 0,618 .ref_count = 0,
619 };619 };
620 }620 }
621 fn initType(ty: Type, mod: *Module) FrameAlloc {621 fn initType(ty: Type, mod: *Module) FrameAlloc {
622 return init(.{ .size = ty.abiSize(mod), .alignment = ty.abiAlignment(mod) });622 return init(.{
623 .size = ty.abiSize(mod),
624 .alignment = ty.abiAlignment(mod),
625 });
623 }626 }
624};627};
625628
...@@ -702,12 +705,12 @@ pub fn generate(...@@ -702,12 +705,12 @@ pub fn generate(
702 @intFromEnum(FrameIndex.stack_frame),705 @intFromEnum(FrameIndex.stack_frame),
703 FrameAlloc.init(.{706 FrameAlloc.init(.{
704 .size = 0,707 .size = 0,
705 .alignment = @intCast(func.analysis(ip).stack_alignment.toByteUnitsOptional() orelse 1),708 .alignment = func.analysis(ip).stack_alignment.max(.@"1"),
706 }),709 }),
707 );710 );
708 function.frame_allocs.set(711 function.frame_allocs.set(
709 @intFromEnum(FrameIndex.call_frame),712 @intFromEnum(FrameIndex.call_frame),
710 FrameAlloc.init(.{ .size = 0, .alignment = 1 }),713 FrameAlloc.init(.{ .size = 0, .alignment = .@"1" }),
711 );714 );
712715
713 const fn_info = mod.typeToFunc(fn_type).?;716 const fn_info = mod.typeToFunc(fn_type).?;
...@@ -729,15 +732,21 @@ pub fn generate(...@@ -729,15 +732,21 @@ pub fn generate(
729 function.ret_mcv = call_info.return_value;732 function.ret_mcv = call_info.return_value;
730 function.frame_allocs.set(@intFromEnum(FrameIndex.ret_addr), FrameAlloc.init(.{733 function.frame_allocs.set(@intFromEnum(FrameIndex.ret_addr), FrameAlloc.init(.{
731 .size = Type.usize.abiSize(mod),734 .size = Type.usize.abiSize(mod),
732 .alignment = @min(Type.usize.abiAlignment(mod), call_info.stack_align),735 .alignment = Type.usize.abiAlignment(mod).min(call_info.stack_align),
733 }));736 }));
734 function.frame_allocs.set(@intFromEnum(FrameIndex.base_ptr), FrameAlloc.init(.{737 function.frame_allocs.set(@intFromEnum(FrameIndex.base_ptr), FrameAlloc.init(.{
735 .size = Type.usize.abiSize(mod),738 .size = Type.usize.abiSize(mod),
736 .alignment = @min(Type.usize.abiAlignment(mod) * 2, call_info.stack_align),739 .alignment = Alignment.min(
740 call_info.stack_align,
741 Alignment.fromNonzeroByteUnits(bin_file.options.target.stackAlignment()),
742 ),
737 }));743 }));
738 function.frame_allocs.set(744 function.frame_allocs.set(
739 @intFromEnum(FrameIndex.args_frame),745 @intFromEnum(FrameIndex.args_frame),
740 FrameAlloc.init(.{ .size = call_info.stack_byte_count, .alignment = call_info.stack_align }),746 FrameAlloc.init(.{
747 .size = call_info.stack_byte_count,
748 .alignment = call_info.stack_align,
749 }),
741 );750 );
742751
743 function.gen() catch |err| switch (err) {752 function.gen() catch |err| switch (err) {
...@@ -2156,8 +2165,8 @@ fn setFrameLoc(...@@ -2156,8 +2165,8 @@ fn setFrameLoc(
2156) void {2165) void {
2157 const frame_i = @intFromEnum(frame_index);2166 const frame_i = @intFromEnum(frame_index);
2158 if (aligned) {2167 if (aligned) {
2159 const alignment = @as(i32, 1) << self.frame_allocs.items(.abi_align)[frame_i];2168 const alignment = self.frame_allocs.items(.abi_align)[frame_i];
2160 offset.* = mem.alignForward(i32, offset.*, alignment);2169 offset.* = @intCast(alignment.forward(@intCast(offset.*)));
2161 }2170 }
2162 self.frame_locs.set(frame_i, .{ .base = base, .disp = offset.* });2171 self.frame_locs.set(frame_i, .{ .base = base, .disp = offset.* });
2163 offset.* += self.frame_allocs.items(.abi_size)[frame_i];2172 offset.* += self.frame_allocs.items(.abi_size)[frame_i];
...@@ -2179,7 +2188,7 @@ fn computeFrameLayout(self: *Self) !FrameLayout {...@@ -2179,7 +2188,7 @@ fn computeFrameLayout(self: *Self) !FrameLayout {
2179 const SortContext = struct {2188 const SortContext = struct {
2180 frame_align: @TypeOf(frame_align),2189 frame_align: @TypeOf(frame_align),
2181 pub fn lessThan(context: @This(), lhs: FrameIndex, rhs: FrameIndex) bool {2190 pub fn lessThan(context: @This(), lhs: FrameIndex, rhs: FrameIndex) bool {
2182 return context.frame_align[@intFromEnum(lhs)] > context.frame_align[@intFromEnum(rhs)];2191 return context.frame_align[@intFromEnum(lhs)].compare(.gt, context.frame_align[@intFromEnum(rhs)]);
2183 }2192 }
2184 };2193 };
2185 const sort_context = SortContext{ .frame_align = frame_align };2194 const sort_context = SortContext{ .frame_align = frame_align };
...@@ -2189,8 +2198,8 @@ fn computeFrameLayout(self: *Self) !FrameLayout {...@@ -2189,8 +2198,8 @@ fn computeFrameLayout(self: *Self) !FrameLayout {
2189 const call_frame_align = frame_align[@intFromEnum(FrameIndex.call_frame)];2198 const call_frame_align = frame_align[@intFromEnum(FrameIndex.call_frame)];
2190 const stack_frame_align = frame_align[@intFromEnum(FrameIndex.stack_frame)];2199 const stack_frame_align = frame_align[@intFromEnum(FrameIndex.stack_frame)];
2191 const args_frame_align = frame_align[@intFromEnum(FrameIndex.args_frame)];2200 const args_frame_align = frame_align[@intFromEnum(FrameIndex.args_frame)];
2192 const needed_align = @max(call_frame_align, stack_frame_align);2201 const needed_align = call_frame_align.max(stack_frame_align);
2193 const need_align_stack = needed_align > args_frame_align;2202 const need_align_stack = needed_align.compare(.gt, args_frame_align);
21942203
2195 // Create list of registers to save in the prologue.2204 // Create list of registers to save in the prologue.
2196 // TODO handle register classes2205 // TODO handle register classes
...@@ -2214,21 +2223,21 @@ fn computeFrameLayout(self: *Self) !FrameLayout {...@@ -2214,21 +2223,21 @@ fn computeFrameLayout(self: *Self) !FrameLayout {
2214 self.setFrameLoc(.stack_frame, .rsp, &rsp_offset, true);2223 self.setFrameLoc(.stack_frame, .rsp, &rsp_offset, true);
2215 for (stack_frame_order) |frame_index| self.setFrameLoc(frame_index, .rsp, &rsp_offset, true);2224 for (stack_frame_order) |frame_index| self.setFrameLoc(frame_index, .rsp, &rsp_offset, true);
2216 rsp_offset += stack_frame_align_offset;2225 rsp_offset += stack_frame_align_offset;
2217 rsp_offset = mem.alignForward(i32, rsp_offset, @as(i32, 1) << needed_align);2226 rsp_offset = @intCast(needed_align.forward(@intCast(rsp_offset)));
2218 rsp_offset -= stack_frame_align_offset;2227 rsp_offset -= stack_frame_align_offset;
2219 frame_size[@intFromEnum(FrameIndex.call_frame)] =2228 frame_size[@intFromEnum(FrameIndex.call_frame)] =
2220 @intCast(rsp_offset - frame_offset[@intFromEnum(FrameIndex.stack_frame)]);2229 @intCast(rsp_offset - frame_offset[@intFromEnum(FrameIndex.stack_frame)]);
22212230
2222 return .{2231 return .{
2223 .stack_mask = @as(u32, math.maxInt(u32)) << (if (need_align_stack) needed_align else 0),2232 .stack_mask = @as(u32, math.maxInt(u32)) << @intCast(if (need_align_stack) @intFromEnum(needed_align) else 0),
2224 .stack_adjust = @intCast(rsp_offset - frame_offset[@intFromEnum(FrameIndex.call_frame)]),2233 .stack_adjust = @intCast(rsp_offset - frame_offset[@intFromEnum(FrameIndex.call_frame)]),
2225 .save_reg_list = save_reg_list,2234 .save_reg_list = save_reg_list,
2226 };2235 };
2227}2236}
22282237
2229fn getFrameAddrAlignment(self: *Self, frame_addr: FrameAddr) u32 {2238fn getFrameAddrAlignment(self: *Self, frame_addr: FrameAddr) Alignment {
2230 const alloc_align = @as(u32, 1) << self.frame_allocs.get(@intFromEnum(frame_addr.index)).abi_align;2239 const alloc_align = self.frame_allocs.get(@intFromEnum(frame_addr.index)).abi_align;
2231 return @min(alloc_align, @as(u32, @bitCast(frame_addr.off)) & (alloc_align - 1));2240 return @enumFromInt(@min(@intFromEnum(alloc_align), @ctz(frame_addr.off)));
2232}2241}
22332242
2234fn getFrameAddrSize(self: *Self, frame_addr: FrameAddr) u32 {2243fn getFrameAddrSize(self: *Self, frame_addr: FrameAddr) u32 {
...@@ -2241,13 +2250,13 @@ fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex {...@@ -2241,13 +2250,13 @@ fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex {
2241 const frame_align = frame_allocs_slice.items(.abi_align);2250 const frame_align = frame_allocs_slice.items(.abi_align);
22422251
2243 const stack_frame_align = &frame_align[@intFromEnum(FrameIndex.stack_frame)];2252 const stack_frame_align = &frame_align[@intFromEnum(FrameIndex.stack_frame)];
2244 stack_frame_align.* = @max(stack_frame_align.*, alloc.abi_align);2253 stack_frame_align.* = stack_frame_align.max(alloc.abi_align);
22452254
2246 for (self.free_frame_indices.keys(), 0..) |frame_index, free_i| {2255 for (self.free_frame_indices.keys(), 0..) |frame_index, free_i| {
2247 const abi_size = frame_size[@intFromEnum(frame_index)];2256 const abi_size = frame_size[@intFromEnum(frame_index)];
2248 if (abi_size != alloc.abi_size) continue;2257 if (abi_size != alloc.abi_size) continue;
2249 const abi_align = &frame_align[@intFromEnum(frame_index)];2258 const abi_align = &frame_align[@intFromEnum(frame_index)];
2250 abi_align.* = @max(abi_align.*, alloc.abi_align);2259 abi_align.* = abi_align.max(alloc.abi_align);
22512260
2252 _ = self.free_frame_indices.swapRemoveAt(free_i);2261 _ = self.free_frame_indices.swapRemoveAt(free_i);
2253 return frame_index;2262 return frame_index;
...@@ -2266,7 +2275,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !FrameIndex {...@@ -2266,7 +2275,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !FrameIndex {
2266 .size = math.cast(u32, val_ty.abiSize(mod)) orelse {2275 .size = math.cast(u32, val_ty.abiSize(mod)) orelse {
2267 return self.fail("type '{}' too big to fit into stack frame", .{val_ty.fmt(mod)});2276 return self.fail("type '{}' too big to fit into stack frame", .{val_ty.fmt(mod)});
2268 },2277 },
2269 .alignment = @max(ptr_ty.ptrAlignment(mod), 1),2278 .alignment = ptr_ty.ptrAlignment(mod).max(.@"1"),
2270 }));2279 }));
2271}2280}
22722281
...@@ -4266,7 +4275,7 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void {...@@ -4266,7 +4275,7 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
4266 };4275 };
4267 defer if (tag_lock) |lock| self.register_manager.unlockReg(lock);4276 defer if (tag_lock) |lock| self.register_manager.unlockReg(lock);
42684277
4269 const adjusted_ptr: MCValue = if (layout.payload_size > 0 and layout.tag_align < layout.payload_align) blk: {4278 const adjusted_ptr: MCValue = if (layout.payload_size > 0 and layout.tag_align.compare(.lt, layout.payload_align)) blk: {
4270 // TODO reusing the operand4279 // TODO reusing the operand
4271 const reg = try self.copyToTmpRegister(ptr_union_ty, ptr);4280 const reg = try self.copyToTmpRegister(ptr_union_ty, ptr);
4272 try self.genBinOpMir(4281 try self.genBinOpMir(
...@@ -4309,7 +4318,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {...@@ -4309,7 +4318,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
4309 switch (operand) {4318 switch (operand) {
4310 .load_frame => |frame_addr| {4319 .load_frame => |frame_addr| {
4311 if (tag_abi_size <= 8) {4320 if (tag_abi_size <= 8) {
4312 const off: i32 = if (layout.tag_align < layout.payload_align)4321 const off: i32 = if (layout.tag_align.compare(.lt, layout.payload_align))
4313 @intCast(layout.payload_size)4322 @intCast(layout.payload_size)
4314 else4323 else
4315 0;4324 0;
...@@ -4321,7 +4330,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {...@@ -4321,7 +4330,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
4321 return self.fail("TODO implement get_union_tag for ABI larger than 8 bytes and operand {}", .{operand});4330 return self.fail("TODO implement get_union_tag for ABI larger than 8 bytes and operand {}", .{operand});
4322 },4331 },
4323 .register => {4332 .register => {
4324 const shift: u6 = if (layout.tag_align < layout.payload_align)4333 const shift: u6 = if (layout.tag_align.compare(.lt, layout.payload_align))
4325 @intCast(layout.payload_size * 8)4334 @intCast(layout.payload_size * 8)
4326 else4335 else
4327 0;4336 0;
...@@ -5600,8 +5609,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -5600,8 +5609,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
5600 const src_mcv = try self.resolveInst(operand);5609 const src_mcv = try self.resolveInst(operand);
5601 const field_off: u32 = switch (container_ty.containerLayout(mod)) {5610 const field_off: u32 = switch (container_ty.containerLayout(mod)) {
5602 .Auto, .Extern => @intCast(container_ty.structFieldOffset(index, mod) * 8),5611 .Auto, .Extern => @intCast(container_ty.structFieldOffset(index, mod) * 8),
5603 .Packed => if (mod.typeToStruct(container_ty)) |struct_obj|5612 .Packed => if (mod.typeToStruct(container_ty)) |struct_type|
5604 struct_obj.packedFieldBitOffset(mod, index)5613 mod.structPackedFieldBitOffset(struct_type, index)
5605 else5614 else
5606 0,5615 0,
5607 };5616 };
...@@ -8084,14 +8093,17 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -8084,14 +8093,17 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
8084 // We need a properly aligned and sized call frame to be able to call this function.8093 // We need a properly aligned and sized call frame to be able to call this function.
8085 {8094 {
8086 const needed_call_frame =8095 const needed_call_frame =
8087 FrameAlloc.init(.{ .size = info.stack_byte_count, .alignment = info.stack_align });8096 FrameAlloc.init(.{
8097 .size = info.stack_byte_count,
8098 .alignment = info.stack_align,
8099 });
8088 const frame_allocs_slice = self.frame_allocs.slice();8100 const frame_allocs_slice = self.frame_allocs.slice();
8089 const stack_frame_size =8101 const stack_frame_size =
8090 &frame_allocs_slice.items(.abi_size)[@intFromEnum(FrameIndex.call_frame)];8102 &frame_allocs_slice.items(.abi_size)[@intFromEnum(FrameIndex.call_frame)];
8091 stack_frame_size.* = @max(stack_frame_size.*, needed_call_frame.abi_size);8103 stack_frame_size.* = @max(stack_frame_size.*, needed_call_frame.abi_size);
8092 const stack_frame_align =8104 const stack_frame_align =
8093 &frame_allocs_slice.items(.abi_align)[@intFromEnum(FrameIndex.call_frame)];8105 &frame_allocs_slice.items(.abi_align)[@intFromEnum(FrameIndex.call_frame)];
8094 stack_frame_align.* = @max(stack_frame_align.*, needed_call_frame.abi_align);8106 stack_frame_align.* = stack_frame_align.max(needed_call_frame.abi_align);
8095 }8107 }
80968108
8097 try self.spillEflagsIfOccupied();8109 try self.spillEflagsIfOccupied();
...@@ -9944,7 +9956,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -9944,7 +9956,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
9944 .indirect => try self.moveStrategy(ty, false),9956 .indirect => try self.moveStrategy(ty, false),
9945 .load_frame => |frame_addr| try self.moveStrategy(9957 .load_frame => |frame_addr| try self.moveStrategy(
9946 ty,9958 ty,
9947 self.getFrameAddrAlignment(frame_addr) >= ty.abiAlignment(mod),9959 self.getFrameAddrAlignment(frame_addr).compare(.gte, ty.abiAlignment(mod)),
9948 ),9960 ),
9949 .lea_frame => .{ .move = .{ ._, .lea } },9961 .lea_frame => .{ .move = .{ ._, .lea } },
9950 else => unreachable,9962 else => unreachable,
...@@ -9973,10 +9985,8 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr...@@ -9973,10 +9985,8 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
9973 .base = .{ .reg = .ds },9985 .base = .{ .reg = .ds },
9974 .disp = small_addr,9986 .disp = small_addr,
9975 });9987 });
9976 switch (try self.moveStrategy(ty, mem.isAlignedGeneric(9988 switch (try self.moveStrategy(ty, ty.abiAlignment(mod).check(
9977 u32,
9978 @as(u32, @bitCast(small_addr)),9989 @as(u32, @bitCast(small_addr)),
9979 ty.abiAlignment(mod),
9980 ))) {9990 ))) {
9981 .move => |tag| try self.asmRegisterMemory(tag, dst_alias, src_mem),9991 .move => |tag| try self.asmRegisterMemory(tag, dst_alias, src_mem),
9982 .insert_extract => |ie| try self.asmRegisterMemoryImmediate(9992 .insert_extract => |ie| try self.asmRegisterMemoryImmediate(
...@@ -10142,22 +10152,14 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal...@@ -10142,22 +10152,14 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal
10142 );10152 );
10143 const src_alias = registerAlias(src_reg, abi_size);10153 const src_alias = registerAlias(src_reg, abi_size);
10144 switch (try self.moveStrategy(ty, switch (base) {10154 switch (try self.moveStrategy(ty, switch (base) {
10145 .none => mem.isAlignedGeneric(10155 .none => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))),
10146 u32,
10147 @as(u32, @bitCast(disp)),
10148 ty.abiAlignment(mod),
10149 ),
10150 .reg => |reg| switch (reg) {10156 .reg => |reg| switch (reg) {
10151 .es, .cs, .ss, .ds => mem.isAlignedGeneric(10157 .es, .cs, .ss, .ds => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))),
10152 u32,
10153 @as(u32, @bitCast(disp)),
10154 ty.abiAlignment(mod),
10155 ),
10156 else => false,10158 else => false,
10157 },10159 },
10158 .frame => |frame_index| self.getFrameAddrAlignment(10160 .frame => |frame_index| self.getFrameAddrAlignment(
10159 .{ .index = frame_index, .off = disp },10161 .{ .index = frame_index, .off = disp },
10160 ) >= ty.abiAlignment(mod),10162 ).compare(.gte, ty.abiAlignment(mod)),
10161 })) {10163 })) {
10162 .move => |tag| try self.asmMemoryRegister(tag, dst_mem, src_alias),10164 .move => |tag| try self.asmMemoryRegister(tag, dst_mem, src_alias),
10163 .insert_extract, .vex_insert_extract => |ie| try self.asmMemoryRegisterImmediate(10165 .insert_extract, .vex_insert_extract => |ie| try self.asmMemoryRegisterImmediate(
...@@ -11079,7 +11081,7 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {...@@ -11079,7 +11081,7 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
11079 stack_frame_size.* = @max(stack_frame_size.*, needed_call_frame.abi_size);11081 stack_frame_size.* = @max(stack_frame_size.*, needed_call_frame.abi_size);
11080 const stack_frame_align =11082 const stack_frame_align =
11081 &frame_allocs_slice.items(.abi_align)[@intFromEnum(FrameIndex.call_frame)];11083 &frame_allocs_slice.items(.abi_align)[@intFromEnum(FrameIndex.call_frame)];
11082 stack_frame_align.* = @max(stack_frame_align.*, needed_call_frame.abi_align);11084 stack_frame_align.* = stack_frame_align.max(needed_call_frame.abi_align);
11083 }11085 }
1108411086
11085 try self.spillEflagsIfOccupied();11087 try self.spillEflagsIfOccupied();
...@@ -11418,13 +11420,14 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {...@@ -11418,13 +11420,14 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
11418 const frame_index =11420 const frame_index =
11419 try self.allocFrameIndex(FrameAlloc.initType(result_ty, mod));11421 try self.allocFrameIndex(FrameAlloc.initType(result_ty, mod));
11420 if (result_ty.containerLayout(mod) == .Packed) {11422 if (result_ty.containerLayout(mod) == .Packed) {
11421 const struct_obj = mod.typeToStruct(result_ty).?;11423 const struct_type = mod.typeToStruct(result_ty).?;
11422 try self.genInlineMemset(11424 try self.genInlineMemset(
11423 .{ .lea_frame = .{ .index = frame_index } },11425 .{ .lea_frame = .{ .index = frame_index } },
11424 .{ .immediate = 0 },11426 .{ .immediate = 0 },
11425 .{ .immediate = result_ty.abiSize(mod) },11427 .{ .immediate = result_ty.abiSize(mod) },
11426 );11428 );
11427 for (elements, 0..) |elem, elem_i| {11429 for (elements, 0..) |elem, elem_i_usize| {
11430 const elem_i: u32 = @intCast(elem_i_usize);
11428 if ((try result_ty.structFieldValueComptime(mod, elem_i)) != null) continue;11431 if ((try result_ty.structFieldValueComptime(mod, elem_i)) != null) continue;
1142911432
11430 const elem_ty = result_ty.structFieldType(elem_i, mod);11433 const elem_ty = result_ty.structFieldType(elem_i, mod);
...@@ -11437,7 +11440,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {...@@ -11437,7 +11440,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
11437 }11440 }
11438 const elem_abi_size: u32 = @intCast(elem_ty.abiSize(mod));11441 const elem_abi_size: u32 = @intCast(elem_ty.abiSize(mod));
11439 const elem_abi_bits = elem_abi_size * 8;11442 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);
11441 const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size);11444 const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size);
11442 const elem_bit_off = elem_off % elem_abi_bits;11445 const elem_bit_off = elem_off % elem_abi_bits;
11443 const elem_mcv = try self.resolveInst(elem);11446 const elem_mcv = try self.resolveInst(elem);
...@@ -11576,13 +11579,13 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {...@@ -11576,13 +11579,13 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
11576 const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index);11579 const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index);
11577 const tag_int_val = try tag_val.intFromEnum(tag_ty, mod);11580 const tag_int_val = try tag_val.intFromEnum(tag_ty, mod);
11578 const tag_int = tag_int_val.toUnsignedInt(mod);11581 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))
11580 @intCast(layout.payload_size)11583 @intCast(layout.payload_size)
11581 else11584 else
11582 0;11585 0;
11583 try self.genCopy(tag_ty, dst_mcv.address().offset(tag_off).deref(), .{ .immediate = tag_int });11586 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))
11586 011589 0
11587 else11590 else
11588 @intCast(layout.tag_size);11591 @intCast(layout.tag_size);
...@@ -11823,7 +11826,7 @@ const CallMCValues = struct {...@@ -11823,7 +11826,7 @@ const CallMCValues = struct {
11823 args: []MCValue,11826 args: []MCValue,
11824 return_value: InstTracking,11827 return_value: InstTracking,
11825 stack_byte_count: u31,11828 stack_byte_count: u31,
11826 stack_align: u31,11829 stack_align: Alignment,
1182711830
11828 fn deinit(self: *CallMCValues, func: *Self) void {11831 fn deinit(self: *CallMCValues, func: *Self) void {
11829 func.gpa.free(self.args);11832 func.gpa.free(self.args);
...@@ -11867,12 +11870,12 @@ fn resolveCallingConventionValues(...@@ -11867,12 +11870,12 @@ fn resolveCallingConventionValues(
11867 .Naked => {11870 .Naked => {
11868 assert(result.args.len == 0);11871 assert(result.args.len == 0);
11869 result.return_value = InstTracking.init(.unreach);11872 result.return_value = InstTracking.init(.unreach);
11870 result.stack_align = 8;11873 result.stack_align = .@"8";
11871 },11874 },
11872 .C => {11875 .C => {
11873 var param_reg_i: usize = 0;11876 var param_reg_i: usize = 0;
11874 var param_sse_reg_i: usize = 0;11877 var param_sse_reg_i: usize = 0;
11875 result.stack_align = 16;11878 result.stack_align = .@"16";
1187611879
11877 switch (self.target.os.tag) {11880 switch (self.target.os.tag) {
11878 .windows => {11881 .windows => {
...@@ -11957,7 +11960,7 @@ fn resolveCallingConventionValues(...@@ -11957,7 +11960,7 @@ fn resolveCallingConventionValues(
11957 }11960 }
1195811961
11959 const param_size: u31 = @intCast(ty.abiSize(mod));11962 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().?);
11961 result.stack_byte_count =11964 result.stack_byte_count =
11962 mem.alignForward(u31, result.stack_byte_count, param_align);11965 mem.alignForward(u31, result.stack_byte_count, param_align);
11963 arg.* = .{ .load_frame = .{11966 arg.* = .{ .load_frame = .{
...@@ -11968,7 +11971,7 @@ fn resolveCallingConventionValues(...@@ -11968,7 +11971,7 @@ fn resolveCallingConventionValues(
11968 }11971 }
11969 },11972 },
11970 .Unspecified => {11973 .Unspecified => {
11971 result.stack_align = 16;11974 result.stack_align = .@"16";
1197211975
11973 // Return values11976 // Return values
11974 if (ret_ty.zigTypeTag(mod) == .NoReturn) {11977 if (ret_ty.zigTypeTag(mod) == .NoReturn) {
...@@ -11997,7 +12000,7 @@ fn resolveCallingConventionValues(...@@ -11997,7 +12000,7 @@ fn resolveCallingConventionValues(
11997 continue;12000 continue;
11998 }12001 }
11999 const param_size: u31 = @intCast(ty.abiSize(mod));12002 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().?);
12001 result.stack_byte_count =12004 result.stack_byte_count =
12002 mem.alignForward(u31, result.stack_byte_count, param_align);12005 mem.alignForward(u31, result.stack_byte_count, param_align);
12003 arg.* = .{ .load_frame = .{12006 arg.* = .{ .load_frame = .{
...@@ -12010,7 +12013,7 @@ fn resolveCallingConventionValues(...@@ -12010,7 +12013,7 @@ fn resolveCallingConventionValues(
12010 else => return self.fail("TODO implement function parameters and return values for {} on x86_64", .{cc}),12013 else => return self.fail("TODO implement function parameters and return values for {} on x86_64", .{cc}),
12011 }12014 }
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));
12014 return result;12017 return result;
12015}12018}
1201612019
src/arch/x86_64/abi.zig+14-24
...@@ -210,8 +210,9 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {...@@ -210,8 +210,9 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {
210 // it contains unaligned fields, it has class MEMORY"210 // it contains unaligned fields, it has class MEMORY"
211 // "If the size of the aggregate exceeds a single eightbyte, each is classified211 // "If the size of the aggregate exceeds a single eightbyte, each is classified
212 // separately.".212 // separately.".
213 const struct_type = mod.typeToStruct(ty).?;
213 const ty_size = ty.abiSize(mod);214 const ty_size = ty.abiSize(mod);
214 if (ty.containerLayout(mod) == .Packed) {215 if (struct_type.layout == .Packed) {
215 assert(ty_size <= 128);216 assert(ty_size <= 128);
216 result[0] = .integer;217 result[0] = .integer;
217 if (ty_size > 64) result[1] = .integer;218 if (ty_size > 64) result[1] = .integer;
...@@ -222,15 +223,13 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {...@@ -222,15 +223,13 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {
222223
223 var result_i: usize = 0; // out of 8224 var result_i: usize = 0; // out of 8
224 var byte_i: usize = 0; // out of 8225 var byte_i: usize = 0; // out of 8
225 const fields = ty.structFields(mod);226 for (struct_type.field_types.get(ip), 0..) |field_ty_ip, i| {
226 for (fields.values()) |field| {227 const field_ty = field_ty_ip.toType();
227 if (field.abi_align != .none) {228 const field_align = struct_type.fieldAlign(ip, i);
228 if (field.abi_align.toByteUnitsOptional().? < field.ty.abiAlignment(mod)) {229 if (field_align != .none and field_align.compare(.lt, field_ty.abiAlignment(mod)))
229 return memory_class;230 return memory_class;
230 }231 const field_size = field_ty.abiSize(mod);
231 }232 const field_class_array = classifySystemV(field_ty, mod, .other);
232 const field_size = field.ty.abiSize(mod);
233 const field_class_array = classifySystemV(field.ty, mod, .other);
234 const field_class = std.mem.sliceTo(&field_class_array, .none);233 const field_class = std.mem.sliceTo(&field_class_array, .none);
235 if (byte_i + field_size <= 8) {234 if (byte_i + field_size <= 8) {
236 // Combine this field with the previous one.235 // Combine this field with the previous one.
...@@ -341,10 +340,11 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {...@@ -341,10 +340,11 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {
341 return memory_class;340 return memory_class;
342341
343 for (union_obj.field_types.get(ip), 0..) |field_ty, field_index| {342 for (union_obj.field_types.get(ip), 0..) |field_ty, field_index| {
344 if (union_obj.fieldAlign(ip, @intCast(field_index)).toByteUnitsOptional()) |a| {343 const field_align = union_obj.fieldAlign(ip, @intCast(field_index));
345 if (a < field_ty.toType().abiAlignment(mod)) {344 if (field_align != .none and
346 return memory_class;345 field_align.compare(.lt, field_ty.toType().abiAlignment(mod)))
347 }346 {
347 return memory_class;
348 }348 }
349 // Combine this field with the previous one.349 // Combine this field with the previous one.
350 const field_class = classifySystemV(field_ty.toType(), mod, .other);350 const field_class = classifySystemV(field_ty.toType(), mod, .other);
...@@ -533,13 +533,3 @@ const Register = @import("bits.zig").Register;...@@ -533,13 +533,3 @@ const Register = @import("bits.zig").Register;
533const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;533const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
534const Type = @import("../../type.zig").Type;534const Type = @import("../../type.zig").Type;
535const Value = @import("../../value.zig").Value;535const Value = @import("../../value.zig").Value;
536
537fn _field(comptime tag: Type.Tag, offset: u32) Module.Struct.Field {
538 return .{
539 .ty = Type.initTag(tag),
540 .default_val = Value.initTag(.unreachable_value),
541 .abi_align = 0,
542 .offset = offset,
543 .is_comptime = false,
544 };
545}
src/codegen.zig+54-47
...@@ -22,6 +22,7 @@ const Type = @import("type.zig").Type;...@@ -22,6 +22,7 @@ const Type = @import("type.zig").Type;
22const TypedValue = @import("TypedValue.zig");22const TypedValue = @import("TypedValue.zig");
23const Value = @import("value.zig").Value;23const Value = @import("value.zig").Value;
24const Zir = @import("Zir.zig");24const Zir = @import("Zir.zig");
25const Alignment = InternPool.Alignment;
2526
26pub const Result = union(enum) {27pub const Result = union(enum) {
27 /// The `code` parameter passed to `generateSymbol` has the value ok.28 /// The `code` parameter passed to `generateSymbol` has the value ok.
...@@ -116,7 +117,8 @@ pub fn generateLazySymbol(...@@ -116,7 +117,8 @@ pub fn generateLazySymbol(
116 bin_file: *link.File,117 bin_file: *link.File,
117 src_loc: Module.SrcLoc,118 src_loc: Module.SrcLoc,
118 lazy_sym: link.File.LazySymbol,119 lazy_sym: link.File.LazySymbol,
119 alignment: *u32,120 // TODO don't use an "out" parameter like this; put it in the result instead
121 alignment: *Alignment,
120 code: *std.ArrayList(u8),122 code: *std.ArrayList(u8),
121 debug_output: DebugInfoOutput,123 debug_output: DebugInfoOutput,
122 reloc_info: RelocInfo,124 reloc_info: RelocInfo,
...@@ -141,7 +143,7 @@ pub fn generateLazySymbol(...@@ -141,7 +143,7 @@ pub fn generateLazySymbol(
141 }143 }
142144
143 if (lazy_sym.ty.isAnyError(mod)) {145 if (lazy_sym.ty.isAnyError(mod)) {
144 alignment.* = 4;146 alignment.* = .@"4";
145 const err_names = mod.global_error_set.keys();147 const err_names = mod.global_error_set.keys();
146 mem.writeInt(u32, try code.addManyAsArray(4), @as(u32, @intCast(err_names.len)), endian);148 mem.writeInt(u32, try code.addManyAsArray(4), @as(u32, @intCast(err_names.len)), endian);
147 var offset = code.items.len;149 var offset = code.items.len;
...@@ -157,7 +159,7 @@ pub fn generateLazySymbol(...@@ -157,7 +159,7 @@ pub fn generateLazySymbol(
157 mem.writeInt(u32, code.items[offset..][0..4], @as(u32, @intCast(code.items.len)), endian);159 mem.writeInt(u32, code.items[offset..][0..4], @as(u32, @intCast(code.items.len)), endian);
158 return Result.ok;160 return Result.ok;
159 } else if (lazy_sym.ty.zigTypeTag(mod) == .Enum) {161 } else if (lazy_sym.ty.zigTypeTag(mod) == .Enum) {
160 alignment.* = 1;162 alignment.* = .@"1";
161 for (lazy_sym.ty.enumFields(mod)) |tag_name_ip| {163 for (lazy_sym.ty.enumFields(mod)) |tag_name_ip| {
162 const tag_name = mod.intern_pool.stringToSlice(tag_name_ip);164 const tag_name = mod.intern_pool.stringToSlice(tag_name_ip);
163 try code.ensureUnusedCapacity(tag_name.len + 1);165 try code.ensureUnusedCapacity(tag_name.len + 1);
...@@ -273,7 +275,7 @@ pub fn generateSymbol(...@@ -273,7 +275,7 @@ pub fn generateSymbol(
273 const abi_align = typed_value.ty.abiAlignment(mod);275 const abi_align = typed_value.ty.abiAlignment(mod);
274276
275 // error value first when its type is larger than the error union's payload277 // error value first when its type is larger than the error union's payload
276 if (error_align > payload_align) {278 if (error_align.order(payload_align) == .gt) {
277 try code.writer().writeInt(u16, err_val, endian);279 try code.writer().writeInt(u16, err_val, endian);
278 }280 }
279281
...@@ -291,7 +293,7 @@ pub fn generateSymbol(...@@ -291,7 +293,7 @@ pub fn generateSymbol(
291 .fail => |em| return .{ .fail = em },293 .fail => |em| return .{ .fail = em },
292 }294 }
293 const unpadded_end = code.items.len - begin;295 const unpadded_end = code.items.len - begin;
294 const padded_end = mem.alignForward(u64, unpadded_end, abi_align);296 const padded_end = abi_align.forward(unpadded_end);
295 const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow;297 const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow;
296298
297 if (padding > 0) {299 if (padding > 0) {
...@@ -300,11 +302,11 @@ pub fn generateSymbol(...@@ -300,11 +302,11 @@ pub fn generateSymbol(
300 }302 }
301303
302 // Payload size is larger than error set, so emit our error set last304 // Payload size is larger than error set, so emit our error set last
303 if (error_align <= payload_align) {305 if (error_align.compare(.lte, payload_align)) {
304 const begin = code.items.len;306 const begin = code.items.len;
305 try code.writer().writeInt(u16, err_val, endian);307 try code.writer().writeInt(u16, err_val, endian);
306 const unpadded_end = code.items.len - begin;308 const unpadded_end = code.items.len - begin;
307 const padded_end = mem.alignForward(u64, unpadded_end, abi_align);309 const padded_end = abi_align.forward(unpadded_end);
308 const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow;310 const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow;
309311
310 if (padding > 0) {312 if (padding > 0) {
...@@ -474,23 +476,18 @@ pub fn generateSymbol(...@@ -474,23 +476,18 @@ pub fn generateSymbol(
474 }476 }
475 }477 }
476 },478 },
477 .struct_type => |struct_type| {479 .struct_type => |struct_type| switch (struct_type.layout) {
478 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;480 .Packed => {
479
480 if (struct_obj.layout == .Packed) {
481 const fields = struct_obj.fields.values();
482 const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse481 const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse
483 return error.Overflow;482 return error.Overflow;
484 const current_pos = code.items.len;483 const current_pos = code.items.len;
485 try code.resize(current_pos + abi_size);484 try code.resize(current_pos + abi_size);
486 var bits: u16 = 0;485 var bits: u16 = 0;
487486
488 for (fields, 0..) |field, index| {487 for (struct_type.field_types.get(ip), 0..) |field_ty, index| {
489 const field_ty = field.ty;
490
491 const field_val = switch (aggregate.storage) {488 const field_val = switch (aggregate.storage) {
492 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{489 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
493 .ty = field_ty.toIntern(),490 .ty = field_ty,
494 .storage = .{ .u64 = bytes[index] },491 .storage = .{ .u64 = bytes[index] },
495 } }),492 } }),
496 .elems => |elems| elems[index],493 .elems => |elems| elems[index],
...@@ -499,48 +496,51 @@ pub fn generateSymbol(...@@ -499,48 +496,51 @@ pub fn generateSymbol(
499496
500 // pointer may point to a decl which must be marked used497 // pointer may point to a decl which must be marked used
501 // but can also result in a relocation. Therefore we handle those separately.498 // but can also result in a relocation. Therefore we handle those separately.
502 if (field_ty.zigTypeTag(mod) == .Pointer) {499 if (field_ty.toType().zigTypeTag(mod) == .Pointer) {
503 const field_size = math.cast(usize, field_ty.abiSize(mod)) orelse500 const field_size = math.cast(usize, field_ty.toType().abiSize(mod)) orelse
504 return error.Overflow;501 return error.Overflow;
505 var tmp_list = try std.ArrayList(u8).initCapacity(code.allocator, field_size);502 var tmp_list = try std.ArrayList(u8).initCapacity(code.allocator, field_size);
506 defer tmp_list.deinit();503 defer tmp_list.deinit();
507 switch (try generateSymbol(bin_file, src_loc, .{504 switch (try generateSymbol(bin_file, src_loc, .{
508 .ty = field_ty,505 .ty = field_ty.toType(),
509 .val = field_val.toValue(),506 .val = field_val.toValue(),
510 }, &tmp_list, debug_output, reloc_info)) {507 }, &tmp_list, debug_output, reloc_info)) {
511 .ok => @memcpy(code.items[current_pos..][0..tmp_list.items.len], tmp_list.items),508 .ok => @memcpy(code.items[current_pos..][0..tmp_list.items.len], tmp_list.items),
512 .fail => |em| return Result{ .fail = em },509 .fail => |em| return Result{ .fail = em },
513 }510 }
514 } else {511 } else {
515 field_val.toValue().writeToPackedMemory(field_ty, mod, code.items[current_pos..], bits) catch unreachable;512 field_val.toValue().writeToPackedMemory(field_ty.toType(), mod, code.items[current_pos..], bits) catch unreachable;
516 }513 }
517 bits += @as(u16, @intCast(field_ty.bitSize(mod)));514 bits += @as(u16, @intCast(field_ty.toType().bitSize(mod)));
518 }515 }
519 } else {516 },
517 .Auto, .Extern => {
520 const struct_begin = code.items.len;518 const struct_begin = code.items.len;
521 const fields = struct_obj.fields.values();519 const field_types = struct_type.field_types.get(ip);
522520 const offsets = struct_type.offsets.get(ip);
523 var it = typed_value.ty.iterateStructOffsets(mod);
524521
525 while (it.next()) |field_offset| {522 var it = struct_type.iterateRuntimeOrder(ip);
526 const field_ty = fields[field_offset.field].ty;523 while (it.next()) |field_index| {
527524 const field_ty = field_types[field_index];
528 if (!field_ty.hasRuntimeBits(mod)) continue;525 if (!field_ty.toType().hasRuntimeBits(mod)) continue;
529526
530 const field_val = switch (ip.indexToKey(typed_value.val.toIntern()).aggregate.storage) {527 const field_val = switch (ip.indexToKey(typed_value.val.toIntern()).aggregate.storage) {
531 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{528 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
532 .ty = field_ty.toIntern(),529 .ty = field_ty,
533 .storage = .{ .u64 = bytes[field_offset.field] },530 .storage = .{ .u64 = bytes[field_index] },
534 } }),531 } }),
535 .elems => |elems| elems[field_offset.field],532 .elems => |elems| elems[field_index],
536 .repeated_elem => |elem| elem,533 .repeated_elem => |elem| elem,
537 };534 };
538535
539 const padding = math.cast(usize, field_offset.offset - (code.items.len - struct_begin)) orelse return error.Overflow;536 const padding = math.cast(
537 usize,
538 offsets[field_index] - (code.items.len - struct_begin),
539 ) orelse return error.Overflow;
540 if (padding > 0) try code.appendNTimes(0, padding);540 if (padding > 0) try code.appendNTimes(0, padding);
541541
542 switch (try generateSymbol(bin_file, src_loc, .{542 switch (try generateSymbol(bin_file, src_loc, .{
543 .ty = field_ty,543 .ty = field_ty.toType(),
544 .val = field_val.toValue(),544 .val = field_val.toValue(),
545 }, code, debug_output, reloc_info)) {545 }, code, debug_output, reloc_info)) {
546 .ok => {},546 .ok => {},
...@@ -548,9 +548,16 @@ pub fn generateSymbol(...@@ -548,9 +548,16 @@ pub fn generateSymbol(
548 }548 }
549 }549 }
550550
551 const padding = math.cast(usize, std.mem.alignForward(u64, it.offset, @max(it.big_align, 1)) - (code.items.len - struct_begin)) orelse return error.Overflow;551 const size = struct_type.size(ip).*;
552 const alignment = struct_type.flagsPtr(ip).alignment.toByteUnitsOptional().?;
553
554 const padding = math.cast(
555 usize,
556 std.mem.alignForward(u64, size, @max(alignment, 1)) -
557 (code.items.len - struct_begin),
558 ) orelse return error.Overflow;
552 if (padding > 0) try code.appendNTimes(0, padding);559 if (padding > 0) try code.appendNTimes(0, padding);
553 }560 },
554 },561 },
555 else => unreachable,562 else => unreachable,
556 },563 },
...@@ -565,7 +572,7 @@ pub fn generateSymbol(...@@ -565,7 +572,7 @@ pub fn generateSymbol(
565 }572 }
566573
567 // Check if we should store the tag first.574 // Check if we should store the tag first.
568 if (layout.tag_size > 0 and layout.tag_align >= layout.payload_align) {575 if (layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align)) {
569 switch (try generateSymbol(bin_file, src_loc, .{576 switch (try generateSymbol(bin_file, src_loc, .{
570 .ty = typed_value.ty.unionTagType(mod).?,577 .ty = typed_value.ty.unionTagType(mod).?,
571 .val = un.tag.toValue(),578 .val = un.tag.toValue(),
...@@ -595,7 +602,7 @@ pub fn generateSymbol(...@@ -595,7 +602,7 @@ pub fn generateSymbol(
595 }602 }
596 }603 }
597604
598 if (layout.tag_size > 0 and layout.tag_align < layout.payload_align) {605 if (layout.tag_size > 0 and layout.tag_align.compare(.lt, layout.payload_align)) {
599 switch (try generateSymbol(bin_file, src_loc, .{606 switch (try generateSymbol(bin_file, src_loc, .{
600 .ty = union_obj.enum_tag_ty.toType(),607 .ty = union_obj.enum_tag_ty.toType(),
601 .val = un.tag.toValue(),608 .val = un.tag.toValue(),
...@@ -695,9 +702,9 @@ fn lowerParentPtr(...@@ -695,9 +702,9 @@ fn lowerParentPtr(
695 @intCast(field.index),702 @intCast(field.index),
696 mod,703 mod,
697 )),704 )),
698 .Packed => if (mod.typeToStruct(base_type.toType())) |struct_obj|705 .Packed => if (mod.typeToStruct(base_type.toType())) |struct_type|
699 math.divExact(u16, struct_obj.packedFieldBitOffset(706 math.divExact(u16, mod.structPackedFieldBitOffset(
700 mod,707 struct_type,
701 @intCast(field.index),708 @intCast(field.index),
702 ), 8) catch |err| switch (err) {709 ), 8) catch |err| switch (err) {
703 error.UnexpectedRemainder => 0,710 error.UnexpectedRemainder => 0,
...@@ -844,12 +851,12 @@ fn genDeclRef(...@@ -844,12 +851,12 @@ fn genDeclRef(
844 // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`?851 // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`?
845 if (tv.ty.castPtrToFn(mod)) |fn_ty| {852 if (tv.ty.castPtrToFn(mod)) |fn_ty| {
846 if (mod.typeToFunc(fn_ty).?.is_generic) {853 if (mod.typeToFunc(fn_ty).?.is_generic) {
847 return GenResult.mcv(.{ .immediate = fn_ty.abiAlignment(mod) });854 return GenResult.mcv(.{ .immediate = fn_ty.abiAlignment(mod).toByteUnitsOptional().? });
848 }855 }
849 } else if (tv.ty.zigTypeTag(mod) == .Pointer) {856 } else if (tv.ty.zigTypeTag(mod) == .Pointer) {
850 const elem_ty = tv.ty.elemType2(mod);857 const elem_ty = tv.ty.elemType2(mod);
851 if (!elem_ty.hasRuntimeBits(mod)) {858 if (!elem_ty.hasRuntimeBits(mod)) {
852 return GenResult.mcv(.{ .immediate = elem_ty.abiAlignment(mod) });859 return GenResult.mcv(.{ .immediate = elem_ty.abiAlignment(mod).toByteUnitsOptional().? });
853 }860 }
854 }861 }
855862
...@@ -1036,10 +1043,10 @@ pub fn errUnionPayloadOffset(payload_ty: Type, mod: *Module) u64 {...@@ -1036,10 +1043,10 @@ pub fn errUnionPayloadOffset(payload_ty: Type, mod: *Module) u64 {
1036 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return 0;1043 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return 0;
1037 const payload_align = payload_ty.abiAlignment(mod);1044 const payload_align = payload_ty.abiAlignment(mod);
1038 const error_align = Type.anyerror.abiAlignment(mod);1045 const error_align = Type.anyerror.abiAlignment(mod);
1039 if (payload_align >= error_align or !payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {1046 if (payload_align.compare(.gte, error_align) or !payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
1040 return 0;1047 return 0;
1041 } else {1048 } else {
1042 return mem.alignForward(u64, Type.anyerror.abiSize(mod), payload_align);1049 return payload_align.forward(Type.anyerror.abiSize(mod));
1043 }1050 }
1044}1051}
10451052
...@@ -1047,8 +1054,8 @@ pub fn errUnionErrorOffset(payload_ty: Type, mod: *Module) u64 {...@@ -1047,8 +1054,8 @@ pub fn errUnionErrorOffset(payload_ty: Type, mod: *Module) u64 {
1047 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return 0;1054 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return 0;
1048 const payload_align = payload_ty.abiAlignment(mod);1055 const payload_align = payload_ty.abiAlignment(mod);
1049 const error_align = Type.anyerror.abiAlignment(mod);1056 const error_align = Type.anyerror.abiAlignment(mod);
1050 if (payload_align >= error_align and payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {1057 if (payload_align.compare(.gte, error_align) and payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
1051 return mem.alignForward(u64, payload_ty.abiSize(mod), error_align);1058 return error_align.forward(payload_ty.abiSize(mod));
1052 } else {1059 } else {
1053 return 0;1060 return 0;
1054 }1061 }
src/codegen/c.zig+138-140
...@@ -17,6 +17,7 @@ const LazySrcLoc = Module.LazySrcLoc;...@@ -17,6 +17,7 @@ const LazySrcLoc = Module.LazySrcLoc;
17const Air = @import("../Air.zig");17const Air = @import("../Air.zig");
18const Liveness = @import("../Liveness.zig");18const Liveness = @import("../Liveness.zig");
19const InternPool = @import("../InternPool.zig");19const InternPool = @import("../InternPool.zig");
20const Alignment = InternPool.Alignment;
2021
21const BigIntLimb = std.math.big.Limb;22const BigIntLimb = std.math.big.Limb;
22const BigInt = std.math.big.int;23const BigInt = std.math.big.int;
...@@ -292,7 +293,7 @@ pub const Function = struct {...@@ -292,7 +293,7 @@ pub const Function = struct {
292293
293 const result: CValue = if (lowersToArray(ty, mod)) result: {294 const result: CValue = if (lowersToArray(ty, mod)) result: {
294 const writer = f.object.code_header.writer();295 const writer = f.object.code_header.writer();
295 const alignment = 0;296 const alignment: Alignment = .none;
296 const decl_c_value = try f.allocLocalValue(ty, alignment);297 const decl_c_value = try f.allocLocalValue(ty, alignment);
297 const gpa = f.object.dg.gpa;298 const gpa = f.object.dg.gpa;
298 try f.allocs.put(gpa, decl_c_value.new_local, false);299 try f.allocs.put(gpa, decl_c_value.new_local, false);
...@@ -318,25 +319,25 @@ pub const Function = struct {...@@ -318,25 +319,25 @@ pub const Function = struct {
318 /// Skips the reuse logic. This function should be used for any persistent allocation, i.e.319 /// Skips the reuse logic. This function should be used for any persistent allocation, i.e.
319 /// those which go into `allocs`. This function does not add the resulting local into `allocs`;320 /// those which go into `allocs`. This function does not add the resulting local into `allocs`;
320 /// that responsibility lies with the caller.321 /// that responsibility lies with the caller.
321 fn allocLocalValue(f: *Function, ty: Type, alignment: u32) !CValue {322 fn allocLocalValue(f: *Function, ty: Type, alignment: Alignment) !CValue {
322 const mod = f.object.dg.module;323 const mod = f.object.dg.module;
323 const gpa = f.object.dg.gpa;324 const gpa = f.object.dg.gpa;
324 try f.locals.append(gpa, .{325 try f.locals.append(gpa, .{
325 .cty_idx = try f.typeToIndex(ty, .complete),326 .cty_idx = try f.typeToIndex(ty, .complete),
326 .alignas = CType.AlignAs.init(alignment, ty.abiAlignment(mod)),327 .alignas = CType.AlignAs.init(alignment, ty.abiAlignment(mod)),
327 });328 });
328 return .{ .new_local = @as(LocalIndex, @intCast(f.locals.items.len - 1)) };329 return .{ .new_local = @intCast(f.locals.items.len - 1) };
329 }330 }
330331
331 fn allocLocal(f: *Function, inst: Air.Inst.Index, ty: Type) !CValue {332 fn allocLocal(f: *Function, inst: Air.Inst.Index, ty: Type) !CValue {
332 const result = try f.allocAlignedLocal(ty, .{}, 0);333 const result = try f.allocAlignedLocal(ty, .{}, .none);
333 log.debug("%{d}: allocating t{d}", .{ inst, result.new_local });334 log.debug("%{d}: allocating t{d}", .{ inst, result.new_local });
334 return result;335 return result;
335 }336 }
336337
337 /// Only allocates the local; does not print anything. Will attempt to re-use locals, so should338 /// Only allocates the local; does not print anything. Will attempt to re-use locals, so should
338 /// not be used for persistent locals (i.e. those in `allocs`).339 /// not be used for persistent locals (i.e. those in `allocs`).
339 fn allocAlignedLocal(f: *Function, ty: Type, _: CQualifiers, alignment: u32) !CValue {340 fn allocAlignedLocal(f: *Function, ty: Type, _: CQualifiers, alignment: Alignment) !CValue {
340 const mod = f.object.dg.module;341 const mod = f.object.dg.module;
341 if (f.free_locals_map.getPtr(.{342 if (f.free_locals_map.getPtr(.{
342 .cty_idx = try f.typeToIndex(ty, .complete),343 .cty_idx = try f.typeToIndex(ty, .complete),
...@@ -1299,139 +1300,134 @@ pub const DeclGen = struct {...@@ -1299,139 +1300,134 @@ pub const DeclGen = struct {
1299 }1300 }
1300 try writer.writeByte('}');1301 try writer.writeByte('}');
1301 },1302 },
1302 .struct_type => |struct_type| {1303 .struct_type => |struct_type| switch (struct_type.layout) {
1303 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;1304 .Auto, .Extern => {
1304 switch (struct_obj.layout) {1305 if (!location.isInitializer()) {
1305 .Auto, .Extern => {1306 try writer.writeByte('(');
1306 if (!location.isInitializer()) {1307 try dg.renderType(writer, ty);
1308 try writer.writeByte(')');
1309 }
1310
1311 try writer.writeByte('{');
1312 var empty = true;
1313 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);
1307 try writer.writeByte('(');1358 try writer.writeByte('(');
1308 try dg.renderType(writer, ty);
1309 try writer.writeByte(')');
1310 }1359 }
13111360
1312 try writer.writeByte('{');1361 var eff_index: usize = 0;
1313 var empty = true;1362 var needs_closing_paren = false;
1314 for (struct_obj.fields.values(), 0..) |field, field_i| {1363 for (field_types, 0..) |field_ty, field_i| {
1315 if (field.is_comptime) continue;1364 if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
1316 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
13171365
1318 if (!empty) try writer.writeByte(',');
1319 const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {1366 const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {
1320 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{1367 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
1321 .ty = field.ty.toIntern(),1368 .ty = field_ty,
1322 .storage = .{ .u64 = bytes[field_i] },1369 .storage = .{ .u64 = bytes[field_i] },
1323 } }),1370 } }),
1324 .elems => |elems| elems[field_i],1371 .elems => |elems| elems[field_i],
1325 .repeated_elem => |elem| elem,1372 .repeated_elem => |elem| elem,
1326 };1373 };
1327 try dg.renderValue(writer, field.ty, field_val.toValue(), initializer_type);1374 const cast_context = IntCastContext{ .value = .{ .value = field_val.toValue() } };
13281375 if (bit_offset != 0) {
1329 empty = false;1376 try writer.writeAll("zig_shl_");
1330 }1377 try dg.renderTypeForBuiltinFnName(writer, ty);
1331 try writer.writeByte('}');1378 try writer.writeByte('(');
1332 },1379 try dg.renderIntCast(writer, ty, cast_context, field_ty.toType(), .FunctionArgument);
1333 .Packed => {1380 try writer.writeAll(", ");
1334 const int_info = ty.intInfo(mod);1381 const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset);
13351382 try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
1336 const bits = Type.smallestUnsignedBits(int_info.bits - 1);1383 try writer.writeByte(')');
1337 const bit_offset_ty = try mod.intType(.unsigned, bits);1384 } else {
13381385 try dg.renderIntCast(writer, ty, cast_context, field_ty.toType(), .FunctionArgument);
1339 var bit_offset: u64 = 0;1386 }
1340 var eff_num_fields: usize = 0;
13411387
1342 for (struct_obj.fields.values()) |field| {1388 if (needs_closing_paren) try writer.writeByte(')');
1343 if (field.is_comptime) continue;1389 if (eff_index != eff_num_fields - 1) try writer.writeAll(", ");
1344 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
13451390
1346 eff_num_fields += 1;1391 bit_offset += field_ty.toType().bitSize(mod);
1392 needs_closing_paren = true;
1393 eff_index += 1;
1347 }1394 }
1395 } else {
1396 try writer.writeByte('(');
1397 // a << a_off | b << b_off | c << c_off
1398 var empty = true;
1399 for (field_types, 0..) |field_ty, field_i| {
1400 if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
13481401
1349 if (eff_num_fields == 0) {1402 if (!empty) try writer.writeAll(" | ");
1350 try writer.writeByte('(');1403 try writer.writeByte('(');
1351 try dg.renderValue(writer, ty, Value.undef, initializer_type);1404 try dg.renderType(writer, ty);
1352 try writer.writeByte(')');1405 try writer.writeByte(')');
1353 } else if (ty.bitSize(mod) > 64) {
1354 // zig_or_u128(zig_or_u128(zig_shl_u128(a, a_off), zig_shl_u128(b, b_off)), zig_shl_u128(c, c_off))
1355 var num_or = eff_num_fields - 1;
1356 while (num_or > 0) : (num_or -= 1) {
1357 try writer.writeAll("zig_or_");
1358 try dg.renderTypeForBuiltinFnName(writer, ty);
1359 try writer.writeByte('(');
1360 }
13611406
1362 var eff_index: usize = 0;1407 const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {
1363 var needs_closing_paren = false;1408 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
1364 for (struct_obj.fields.values(), 0..) |field, field_i| {1409 .ty = field_ty,
1365 if (field.is_comptime) continue;1410 .storage = .{ .u64 = bytes[field_i] },
1366 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;1411 } }),
13671412 .elems => |elems| elems[field_i],
1368 const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {1413 .repeated_elem => |elem| elem,
1369 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{1414 };
1370 .ty = field.ty.toIntern(),
1371 .storage = .{ .u64 = bytes[field_i] },
1372 } }),
1373 .elems => |elems| elems[field_i],
1374 .repeated_elem => |elem| elem,
1375 };
1376 const cast_context = IntCastContext{ .value = .{ .value = field_val.toValue() } };
1377 if (bit_offset != 0) {
1378 try writer.writeAll("zig_shl_");
1379 try dg.renderTypeForBuiltinFnName(writer, ty);
1380 try writer.writeByte('(');
1381 try dg.renderIntCast(writer, ty, cast_context, field.ty, .FunctionArgument);
1382 try writer.writeAll(", ");
1383 const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset);
1384 try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
1385 try writer.writeByte(')');
1386 } else {
1387 try dg.renderIntCast(writer, ty, cast_context, field.ty, .FunctionArgument);
1388 }
1389
1390 if (needs_closing_paren) try writer.writeByte(')');
1391 if (eff_index != eff_num_fields - 1) try writer.writeAll(", ");
1392
1393 bit_offset += field.ty.bitSize(mod);
1394 needs_closing_paren = true;
1395 eff_index += 1;
1396 }
1397 } else {
1398 try writer.writeByte('(');
1399 // a << a_off | b << b_off | c << c_off
1400 var empty = true;
1401 for (struct_obj.fields.values(), 0..) |field, field_i| {
1402 if (field.is_comptime) continue;
1403 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
1404
1405 if (!empty) try writer.writeAll(" | ");
1406 try writer.writeByte('(');
1407 try dg.renderType(writer, ty);
1408 try writer.writeByte(')');
14091415
1410 const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {1416 if (bit_offset != 0) {
1411 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{1417 try dg.renderValue(writer, field_ty.toType(), field_val.toValue(), .Other);
1412 .ty = field.ty.toIntern(),1418 try writer.writeAll(" << ");
1413 .storage = .{ .u64 = bytes[field_i] },1419 const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset);
1414 } }),1420 try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
1415 .elems => |elems| elems[field_i],1421 } else {
1416 .repeated_elem => |elem| elem,1422 try dg.renderValue(writer, field_ty.toType(), field_val.toValue(), .Other);
1417 };
1418
1419 if (bit_offset != 0) {
1420 try dg.renderValue(writer, field.ty, field_val.toValue(), .Other);
1421 try writer.writeAll(" << ");
1422 const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset);
1423 try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
1424 } else {
1425 try dg.renderValue(writer, field.ty, field_val.toValue(), .Other);
1426 }
1427
1428 bit_offset += field.ty.bitSize(mod);
1429 empty = false;
1430 }1423 }
1431 try writer.writeByte(')');1424
1425 bit_offset += field_ty.toType().bitSize(mod);
1426 empty = false;
1432 }1427 }
1433 },1428 try writer.writeByte(')');
1434 }1429 }
1430 },
1435 },1431 },
1436 else => unreachable,1432 else => unreachable,
1437 },1433 },
...@@ -1723,7 +1719,7 @@ pub const DeclGen = struct {...@@ -1723,7 +1719,7 @@ pub const DeclGen = struct {
1723 ty: Type,1719 ty: Type,
1724 name: CValue,1720 name: CValue,
1725 qualifiers: CQualifiers,1721 qualifiers: CQualifiers,
1726 alignment: u64,1722 alignment: Alignment,
1727 kind: CType.Kind,1723 kind: CType.Kind,
1728 ) error{ OutOfMemory, AnalysisFail }!void {1724 ) error{ OutOfMemory, AnalysisFail }!void {
1729 const mod = dg.module;1725 const mod = dg.module;
...@@ -1854,7 +1850,7 @@ pub const DeclGen = struct {...@@ -1854,7 +1850,7 @@ pub const DeclGen = struct {
1854 decl.ty,1850 decl.ty,
1855 .{ .decl = decl_index },1851 .{ .decl = decl_index },
1856 CQualifiers.init(.{ .@"const" = variable.is_const }),1852 CQualifiers.init(.{ .@"const" = variable.is_const }),
1857 @as(u32, @intCast(decl.alignment.toByteUnits(0))),1853 decl.alignment,
1858 .complete,1854 .complete,
1859 );1855 );
1860 try fwd_decl_writer.writeAll(";\n");1856 try fwd_decl_writer.writeAll(";\n");
...@@ -2460,7 +2456,7 @@ pub fn genErrDecls(o: *Object) !void {...@@ -2460,7 +2456,7 @@ pub fn genErrDecls(o: *Object) !void {
2460 } });2456 } });
24612457
2462 try writer.writeAll("static ");2458 try writer.writeAll("static ");
2463 try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, Const, 0, .complete);2459 try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, Const, .none, .complete);
2464 try writer.writeAll(" = ");2460 try writer.writeAll(" = ");
2465 try o.dg.renderValue(writer, name_ty, name_val.toValue(), .StaticInitializer);2461 try o.dg.renderValue(writer, name_ty, name_val.toValue(), .StaticInitializer);
2466 try writer.writeAll(";\n");2462 try writer.writeAll(";\n");
...@@ -2472,7 +2468,7 @@ pub fn genErrDecls(o: *Object) !void {...@@ -2472,7 +2468,7 @@ pub fn genErrDecls(o: *Object) !void {
2472 });2468 });
24732469
2474 try writer.writeAll("static ");2470 try writer.writeAll("static ");
2475 try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = array_identifier }, Const, 0, .complete);2471 try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = array_identifier }, Const, .none, .complete);
2476 try writer.writeAll(" = {");2472 try writer.writeAll(" = {");
2477 for (mod.global_error_set.keys(), 0..) |name_nts, value| {2473 for (mod.global_error_set.keys(), 0..) |name_nts, value| {
2478 const name = mod.intern_pool.stringToSlice(name_nts);2474 const name = mod.intern_pool.stringToSlice(name_nts);
...@@ -2523,7 +2519,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {...@@ -2523,7 +2519,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
2523 try w.writeByte(' ');2519 try w.writeByte(' ');
2524 try w.writeAll(fn_name);2520 try w.writeAll(fn_name);
2525 try w.writeByte('(');2521 try w.writeByte('(');
2526 try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, 0, .complete);2522 try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, .none, .complete);
2527 try w.writeAll(") {\n switch (tag) {\n");2523 try w.writeAll(") {\n switch (tag) {\n");
2528 for (enum_ty.enumFields(mod), 0..) |name_ip, index_usize| {2524 for (enum_ty.enumFields(mod), 0..) |name_ip, index_usize| {
2529 const index = @as(u32, @intCast(index_usize));2525 const index = @as(u32, @intCast(index_usize));
...@@ -2546,7 +2542,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {...@@ -2546,7 +2542,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
2546 try w.print(" case {}: {{\n static ", .{2542 try w.print(" case {}: {{\n static ", .{
2547 try o.dg.fmtIntLiteral(enum_ty, int_val, .Other),2543 try o.dg.fmtIntLiteral(enum_ty, int_val, .Other),
2548 });2544 });
2549 try o.dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, Const, 0, .complete);2545 try o.dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, Const, .none, .complete);
2550 try w.writeAll(" = ");2546 try w.writeAll(" = ");
2551 try o.dg.renderValue(w, name_ty, name_val.toValue(), .Initializer);2547 try o.dg.renderValue(w, name_ty, name_val.toValue(), .Initializer);
2552 try w.writeAll(";\n return (");2548 try w.writeAll(";\n return (");
...@@ -2706,7 +2702,7 @@ pub fn genDecl(o: *Object) !void {...@@ -2706,7 +2702,7 @@ pub fn genDecl(o: *Object) !void {
2706 if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage ");2702 if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage ");
2707 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s|2703 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s|
2708 try w.print("zig_linksection(\"{s}\", ", .{s});2704 try w.print("zig_linksection(\"{s}\", ", .{s});
2709 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .{}, decl.alignment.toByteUnits(0), .complete);2705 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .{}, decl.alignment, .complete);
2710 if (decl.@"linksection" != .none) try w.writeAll(", read, write)");2706 if (decl.@"linksection" != .none) try w.writeAll(", read, write)");
2711 try w.writeAll(" = ");2707 try w.writeAll(" = ");
2712 try o.dg.renderValue(w, tv.ty, variable.init.toValue(), .StaticInitializer);2708 try o.dg.renderValue(w, tv.ty, variable.init.toValue(), .StaticInitializer);
...@@ -2717,14 +2713,14 @@ pub fn genDecl(o: *Object) !void {...@@ -2717,14 +2713,14 @@ pub fn genDecl(o: *Object) !void {
2717 const fwd_decl_writer = o.dg.fwd_decl.writer();2713 const fwd_decl_writer = o.dg.fwd_decl.writer();
27182714
2719 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");2715 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
2720 try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, Const, decl.alignment.toByteUnits(0), .complete);2716 try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, Const, decl.alignment, .complete);
2721 try fwd_decl_writer.writeAll(";\n");2717 try fwd_decl_writer.writeAll(";\n");
27222718
2723 const w = o.writer();2719 const w = o.writer();
2724 if (!is_global) try w.writeAll("static ");2720 if (!is_global) try w.writeAll("static ");
2725 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s|2721 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s|
2726 try w.print("zig_linksection(\"{s}\", ", .{s});2722 try w.print("zig_linksection(\"{s}\", ", .{s});
2727 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, Const, decl.alignment.toByteUnits(0), .complete);2723 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, Const, decl.alignment, .complete);
2728 if (decl.@"linksection" != .none) try w.writeAll(", read)");2724 if (decl.@"linksection" != .none) try w.writeAll(", read)");
2729 try w.writeAll(" = ");2725 try w.writeAll(" = ");
2730 try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer);2726 try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer);
...@@ -3353,8 +3349,8 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3353,8 +3349,8 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
33533349
3354 try reap(f, inst, &.{ty_op.operand});3350 try reap(f, inst, &.{ty_op.operand});
33553351
3356 const is_aligned = if (ptr_info.flags.alignment.toByteUnitsOptional()) |alignment|3352 const is_aligned = if (ptr_info.flags.alignment != .none)
3357 alignment >= src_ty.abiAlignment(mod)3353 ptr_info.flags.alignment.compare(.gte, src_ty.abiAlignment(mod))
3358 else3354 else
3359 true;3355 true;
3360 const is_array = lowersToArray(src_ty, mod);3356 const is_array = lowersToArray(src_ty, mod);
...@@ -3625,8 +3621,8 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {...@@ -3625,8 +3621,8 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
3625 return .none;3621 return .none;
3626 }3622 }
36273623
3628 const is_aligned = if (ptr_info.flags.alignment.toByteUnitsOptional()) |alignment|3624 const is_aligned = if (ptr_info.flags.alignment != .none)
3629 alignment >= src_ty.abiAlignment(mod)3625 ptr_info.flags.alignment.compare(.gte, src_ty.abiAlignment(mod))
3630 else3626 else
3631 true;3627 true;
3632 const is_array = lowersToArray(ptr_info.child.toType(), mod);3628 const is_array = lowersToArray(ptr_info.child.toType(), mod);
...@@ -4847,7 +4843,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4847,7 +4843,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4847 if (is_reg) {4843 if (is_reg) {
4848 const output_ty = if (output == .none) inst_ty else f.typeOf(output).childType(mod);4844 const output_ty = if (output == .none) inst_ty else f.typeOf(output).childType(mod);
4849 try writer.writeAll("register ");4845 try writer.writeAll("register ");
4850 const alignment = 0;4846 const alignment: Alignment = .none;
4851 const local_value = try f.allocLocalValue(output_ty, alignment);4847 const local_value = try f.allocLocalValue(output_ty, alignment);
4852 try f.allocs.put(gpa, local_value.new_local, false);4848 try f.allocs.put(gpa, local_value.new_local, false);
4853 try f.object.dg.renderTypeAndName(writer, output_ty, local_value, .{}, alignment, .complete);4849 try f.object.dg.renderTypeAndName(writer, output_ty, local_value, .{}, alignment, .complete);
...@@ -4880,7 +4876,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4880,7 +4876,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4880 if (asmInputNeedsLocal(f, constraint, input_val)) {4876 if (asmInputNeedsLocal(f, constraint, input_val)) {
4881 const input_ty = f.typeOf(input);4877 const input_ty = f.typeOf(input);
4882 if (is_reg) try writer.writeAll("register ");4878 if (is_reg) try writer.writeAll("register ");
4883 const alignment = 0;4879 const alignment: Alignment = .none;
4884 const local_value = try f.allocLocalValue(input_ty, alignment);4880 const local_value = try f.allocLocalValue(input_ty, alignment);
4885 try f.allocs.put(gpa, local_value.new_local, false);4881 try f.allocs.put(gpa, local_value.new_local, false);
4886 try f.object.dg.renderTypeAndName(writer, input_ty, local_value, Const, alignment, .complete);4882 try f.object.dg.renderTypeAndName(writer, input_ty, local_value, Const, alignment, .complete);
...@@ -5230,7 +5226,8 @@ fn fieldLocation(...@@ -5230,7 +5226,8 @@ fn fieldLocation(
5230 const container_ty = container_ptr_ty.childType(mod);5226 const container_ty = container_ptr_ty.childType(mod);
5231 return switch (container_ty.zigTypeTag(mod)) {5227 return switch (container_ty.zigTypeTag(mod)) {
5232 .Struct => switch (container_ty.containerLayout(mod)) {5228 .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);
5234 if (container_ty.structFieldIsComptime(next_field_index, mod)) continue;5231 if (container_ty.structFieldIsComptime(next_field_index, mod)) continue;
5235 const field_ty = container_ty.structFieldType(next_field_index, mod);5232 const field_ty = container_ty.structFieldType(next_field_index, mod);
5236 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;5233 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
...@@ -5238,7 +5235,7 @@ fn fieldLocation(...@@ -5238,7 +5235,7 @@ fn fieldLocation(
5238 break .{ .field = if (container_ty.isSimpleTuple(mod))5235 break .{ .field = if (container_ty.isSimpleTuple(mod))
5239 .{ .field = next_field_index }5236 .{ .field = next_field_index }
5240 else5237 else
5241 .{ .identifier = ip.stringToSlice(container_ty.structFieldName(next_field_index, mod)) } };5238 .{ .identifier = ip.stringToSlice(container_ty.legacyStructFieldName(next_field_index, mod)) } };
5242 } else if (container_ty.hasRuntimeBitsIgnoreComptime(mod)) .end else .begin,5239 } else if (container_ty.hasRuntimeBitsIgnoreComptime(mod)) .end else .begin,
5243 .Packed => if (field_ptr_ty.ptrInfo(mod).packed_offset.host_size == 0)5240 .Packed => if (field_ptr_ty.ptrInfo(mod).packed_offset.host_size == 0)
5244 .{ .byte_offset = container_ty.packedStructFieldByteOffset(field_index, mod) + @divExact(container_ptr_ty.ptrInfo(mod).packed_offset.bit_offset, 8) }5241 .{ .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 {...@@ -5425,14 +5422,14 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5425 .Auto, .Extern => if (struct_ty.isSimpleTuple(mod))5422 .Auto, .Extern => if (struct_ty.isSimpleTuple(mod))
5426 .{ .field = extra.field_index }5423 .{ .field = extra.field_index }
5427 else5424 else
5428 .{ .identifier = ip.stringToSlice(struct_ty.structFieldName(extra.field_index, mod)) },5425 .{ .identifier = ip.stringToSlice(struct_ty.legacyStructFieldName(extra.field_index, mod)) },
5429 .Packed => {5426 .Packed => {
5430 const struct_obj = mod.typeToStruct(struct_ty).?;5427 const struct_type = mod.typeToStruct(struct_ty).?;
5431 const int_info = struct_ty.intInfo(mod);5428 const int_info = struct_ty.intInfo(mod);
54325429
5433 const bit_offset_ty = try mod.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1));5430 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);
5436 const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset);5433 const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset);
54375434
5438 const field_int_signedness = if (inst_ty.isAbiInt(mod))5435 const field_int_signedness = if (inst_ty.isAbiInt(mod))
...@@ -5487,7 +5484,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5487,7 +5484,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5487 .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len == 0)5484 .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len == 0)
5488 .{ .field = extra.field_index }5485 .{ .field = extra.field_index }
5489 else5486 else
5490 .{ .identifier = ip.stringToSlice(struct_ty.structFieldName(extra.field_index, mod)) },5487 .{ .identifier = ip.stringToSlice(struct_ty.legacyStructFieldName(extra.field_index, mod)) },
54915488
5492 .union_type => |union_type| field_name: {5489 .union_type => |union_type| field_name: {
5493 const union_obj = ip.loadUnionType(union_type);5490 const union_obj = ip.loadUnionType(union_type);
...@@ -6820,7 +6817,8 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6820,7 +6817,8 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
6820 }6817 }
6821 },6818 },
6822 .Struct => switch (inst_ty.containerLayout(mod)) {6819 .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);
6824 if (inst_ty.structFieldIsComptime(field_i, mod)) continue;6822 if (inst_ty.structFieldIsComptime(field_i, mod)) continue;
6825 const field_ty = inst_ty.structFieldType(field_i, mod);6823 const field_ty = inst_ty.structFieldType(field_i, mod);
6826 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;6824 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
...@@ -6829,7 +6827,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6829,7 +6827,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
6829 try f.writeCValueMember(writer, local, if (inst_ty.isSimpleTuple(mod))6827 try f.writeCValueMember(writer, local, if (inst_ty.isSimpleTuple(mod))
6830 .{ .field = field_i }6828 .{ .field = field_i }
6831 else6829 else
6832 .{ .identifier = ip.stringToSlice(inst_ty.structFieldName(field_i, mod)) });6830 .{ .identifier = ip.stringToSlice(inst_ty.legacyStructFieldName(field_i, mod)) });
6833 try a.assign(f, writer);6831 try a.assign(f, writer);
6834 try f.writeCValue(writer, element, .Other);6832 try f.writeCValue(writer, element, .Other);
6835 try a.end(f, writer);6833 try a.end(f, writer);
src/codegen/c/type.zig+24-15
...@@ -283,14 +283,20 @@ pub const CType = extern union {...@@ -283,14 +283,20 @@ pub const CType = extern union {
283 @"align": Alignment,283 @"align": Alignment,
284 abi: Alignment,284 abi: Alignment,
285285
286 pub fn init(alignment: u64, abi_alignment: u32) AlignAs {286 pub fn init(@"align": Alignment, abi_align: Alignment) AlignAs {
287 const @"align" = Alignment.fromByteUnits(alignment);287 assert(abi_align != .none);
288 const abi_align = Alignment.fromNonzeroByteUnits(abi_alignment);
289 return .{288 return .{
290 .@"align" = if (@"align" != .none) @"align" else abi_align,289 .@"align" = if (@"align" != .none) @"align" else abi_align,
291 .abi = abi_align,290 .abi = abi_align,
292 };291 };
293 }292 }
293
294 pub fn initByteUnits(alignment: u64, abi_alignment: u32) AlignAs {
295 return init(
296 Alignment.fromByteUnits(alignment),
297 Alignment.fromNonzeroByteUnits(abi_alignment),
298 );
299 }
294 pub fn abiAlign(ty: Type, mod: *Module) AlignAs {300 pub fn abiAlign(ty: Type, mod: *Module) AlignAs {
295 const abi_align = ty.abiAlignment(mod);301 const abi_align = ty.abiAlignment(mod);
296 return init(abi_align, abi_align);302 return init(abi_align, abi_align);
...@@ -1360,6 +1366,7 @@ pub const CType = extern union {...@@ -1360,6 +1366,7 @@ pub const CType = extern union {
13601366
1361 pub fn initType(self: *@This(), ty: Type, kind: Kind, lookup: Lookup) !void {1367 pub fn initType(self: *@This(), ty: Type, kind: Kind, lookup: Lookup) !void {
1362 const mod = lookup.getModule();1368 const mod = lookup.getModule();
1369 const ip = &mod.intern_pool;
13631370
1364 self.* = undefined;1371 self.* = undefined;
1365 if (!ty.isFnOrHasRuntimeBitsIgnoreComptime(mod))1372 if (!ty.isFnOrHasRuntimeBitsIgnoreComptime(mod))
...@@ -1382,12 +1389,12 @@ pub const CType = extern union {...@@ -1382,12 +1389,12 @@ pub const CType = extern union {
1382 .array => switch (kind) {1389 .array => switch (kind) {
1383 .forward, .complete, .global => {1390 .forward, .complete, .global => {
1384 const abi_size = ty.abiSize(mod);1391 const abi_size = ty.abiSize(mod);
1385 const abi_align = ty.abiAlignment(mod);1392 const abi_align = ty.abiAlignment(mod).toByteUnits(0);
1386 self.storage = .{ .seq = .{ .base = .{ .tag = .array }, .data = .{1393 self.storage = .{ .seq = .{ .base = .{ .tag = .array }, .data = .{
1387 .len = @divExact(abi_size, abi_align),1394 .len = @divExact(abi_size, abi_align),
1388 .elem_type = tagFromIntInfo(.{1395 .elem_type = tagFromIntInfo(.{
1389 .signedness = .unsigned,1396 .signedness = .unsigned,
1390 .bits = @as(u16, @intCast(abi_align * 8)),1397 .bits = @intCast(abi_align * 8),
1391 }).toIndex(),1398 }).toIndex(),
1392 } } };1399 } } };
1393 self.value = .{ .cty = initPayload(&self.storage.seq) };1400 self.value = .{ .cty = initPayload(&self.storage.seq) };
...@@ -1488,10 +1495,10 @@ pub const CType = extern union {...@@ -1488,10 +1495,10 @@ pub const CType = extern union {
1488 },1495 },
14891496
1490 .Struct, .Union => |zig_ty_tag| if (ty.containerLayout(mod) == .Packed) {1497 .Struct, .Union => |zig_ty_tag| if (ty.containerLayout(mod) == .Packed) {
1491 if (mod.typeToStruct(ty)) |struct_obj| {1498 if (mod.typeToPackedStruct(ty)) |packed_struct| {
1492 try self.initType(struct_obj.backing_int_ty, kind, lookup);1499 try self.initType(packed_struct.backingIntType(ip).toType(), kind, lookup);
1493 } else {1500 } else {
1494 const bits = @as(u16, @intCast(ty.bitSize(mod)));1501 const bits: u16 = @intCast(ty.bitSize(mod));
1495 const int_ty = try mod.intType(.unsigned, bits);1502 const int_ty = try mod.intType(.unsigned, bits);
1496 try self.initType(int_ty, kind, lookup);1503 try self.initType(int_ty, kind, lookup);
1497 }1504 }
...@@ -1722,7 +1729,6 @@ pub const CType = extern union {...@@ -1722,7 +1729,6 @@ pub const CType = extern union {
17221729
1723 .Fn => {1730 .Fn => {
1724 const info = mod.typeToFunc(ty).?;1731 const info = mod.typeToFunc(ty).?;
1725 const ip = &mod.intern_pool;
1726 if (!info.is_generic) {1732 if (!info.is_generic) {
1727 if (lookup.isMutable()) {1733 if (lookup.isMutable()) {
1728 const param_kind: Kind = switch (kind) {1734 const param_kind: Kind = switch (kind) {
...@@ -1947,7 +1953,8 @@ pub const CType = extern union {...@@ -1947,7 +1953,8 @@ pub const CType = extern union {
19471953
1948 const fields_pl = try arena.alloc(Payload.Fields.Field, c_fields_len);1954 const fields_pl = try arena.alloc(Payload.Fields.Field, c_fields_len);
1949 var c_field_i: usize = 0;1955 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);
1951 const field_ty = ty.structFieldType(field_i, mod);1958 const field_ty = ty.structFieldType(field_i, mod);
1952 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or1959 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or
1953 !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;1960 !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
...@@ -1958,7 +1965,7 @@ pub const CType = extern union {...@@ -1958,7 +1965,7 @@ pub const CType = extern union {
1958 std.fmt.allocPrintZ(arena, "f{}", .{field_i})1965 std.fmt.allocPrintZ(arena, "f{}", .{field_i})
1959 else1966 else
1960 arena.dupeZ(u8, ip.stringToSlice(switch (zig_ty_tag) {1967 arena.dupeZ(u8, ip.stringToSlice(switch (zig_ty_tag) {
1961 .Struct => ty.structFieldName(field_i, mod),1968 .Struct => ty.legacyStructFieldName(field_i, mod),
1962 .Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i],1969 .Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i],
1963 else => unreachable,1970 else => unreachable,
1964 })),1971 })),
...@@ -2091,7 +2098,8 @@ pub const CType = extern union {...@@ -2091,7 +2098,8 @@ pub const CType = extern union {
2091 .Struct => ty.structFieldCount(mod),2098 .Struct => ty.structFieldCount(mod),
2092 .Union => mod.typeToUnion(ty).?.field_names.len,2099 .Union => mod.typeToUnion(ty).?.field_names.len,
2093 else => unreachable,2100 else => unreachable,
2094 }) |field_i| {2101 }) |field_i_usize| {
2102 const field_i: u32 = @intCast(field_i_usize);
2095 const field_ty = ty.structFieldType(field_i, mod);2103 const field_ty = ty.structFieldType(field_i, mod);
2096 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or2104 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or
2097 !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;2105 !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
...@@ -2110,7 +2118,7 @@ pub const CType = extern union {...@@ -2110,7 +2118,7 @@ pub const CType = extern union {
2110 std.fmt.bufPrintZ(&name_buf, "f{}", .{field_i}) catch unreachable2118 std.fmt.bufPrintZ(&name_buf, "f{}", .{field_i}) catch unreachable
2111 else2119 else
2112 ip.stringToSlice(switch (zig_ty_tag) {2120 ip.stringToSlice(switch (zig_ty_tag) {
2113 .Struct => ty.structFieldName(field_i, mod),2121 .Struct => ty.legacyStructFieldName(field_i, mod),
2114 .Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i],2122 .Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i],
2115 else => unreachable,2123 else => unreachable,
2116 }),2124 }),
...@@ -2219,7 +2227,8 @@ pub const CType = extern union {...@@ -2219,7 +2227,8 @@ pub const CType = extern union {
2219 .Struct => ty.structFieldCount(mod),2227 .Struct => ty.structFieldCount(mod),
2220 .Union => mod.typeToUnion(ty).?.field_names.len,2228 .Union => mod.typeToUnion(ty).?.field_names.len,
2221 else => unreachable,2229 else => unreachable,
2222 }) |field_i| {2230 }) |field_i_usize| {
2231 const field_i: u32 = @intCast(field_i_usize);
2223 const field_ty = ty.structFieldType(field_i, mod);2232 const field_ty = ty.structFieldType(field_i, mod);
2224 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or2233 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or
2225 !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;2234 !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
...@@ -2234,7 +2243,7 @@ pub const CType = extern union {...@@ -2234,7 +2243,7 @@ pub const CType = extern union {
2234 std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable2243 std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable
2235 else2244 else
2236 mod.intern_pool.stringToSlice(switch (zig_ty_tag) {2245 mod.intern_pool.stringToSlice(switch (zig_ty_tag) {
2237 .Struct => ty.structFieldName(field_i, mod),2246 .Struct => ty.legacyStructFieldName(field_i, mod),
2238 .Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i],2247 .Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i],
2239 else => unreachable,2248 else => unreachable,
2240 }));2249 }));
src/codegen/llvm.zig+341-295
...@@ -833,7 +833,10 @@ pub const Object = struct {...@@ -833,7 +833,10 @@ pub const Object = struct {
833833
834 /// When an LLVM struct type is created, an entry is inserted into this834 /// When an LLVM struct type is created, an entry is inserted into this
835 /// table for every zig source field of the struct that has a corresponding835 /// 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.
837 /// The value is the LLVM struct field index.840 /// The value is the LLVM struct field index.
838 /// This is denormalized data.841 /// This is denormalized data.
839 struct_field_map: std.AutoHashMapUnmanaged(ZigStructField, c_uint),842 struct_field_map: std.AutoHashMapUnmanaged(ZigStructField, c_uint),
...@@ -1076,7 +1079,7 @@ pub const Object = struct {...@@ -1076,7 +1079,7 @@ pub const Object = struct {
1076 table_variable_index.setMutability(.constant, &o.builder);1079 table_variable_index.setMutability(.constant, &o.builder);
1077 table_variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);1080 table_variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
1078 table_variable_index.setAlignment(1081 table_variable_index.setAlignment(
1079 Builder.Alignment.fromByteUnits(slice_ty.abiAlignment(mod)),1082 slice_ty.abiAlignment(mod).toLlvm(),
1080 &o.builder,1083 &o.builder,
1081 );1084 );
10821085
...@@ -1318,8 +1321,9 @@ pub const Object = struct {...@@ -1318,8 +1321,9 @@ pub const Object = struct {
1318 _ = try attributes.removeFnAttr(.@"noinline");1321 _ = try attributes.removeFnAttr(.@"noinline");
1319 }1322 }
13201323
1321 if (func.analysis(ip).stack_alignment.toByteUnitsOptional()) |alignment| {1324 const stack_alignment = func.analysis(ip).stack_alignment;
1322 try attributes.addFnAttr(.{ .alignstack = Builder.Alignment.fromByteUnits(alignment) }, &o.builder);1325 if (stack_alignment != .none) {
1326 try attributes.addFnAttr(.{ .alignstack = stack_alignment.toLlvm() }, &o.builder);
1323 try attributes.addFnAttr(.@"noinline", &o.builder);1327 try attributes.addFnAttr(.@"noinline", &o.builder);
1324 } else {1328 } else {
1325 _ = try attributes.removeFnAttr(.alignstack);1329 _ = try attributes.removeFnAttr(.alignstack);
...@@ -1407,7 +1411,7 @@ pub const Object = struct {...@@ -1407,7 +1411,7 @@ pub const Object = struct {
1407 const param = wip.arg(llvm_arg_i);1411 const param = wip.arg(llvm_arg_i);
14081412
1409 if (isByRef(param_ty, mod)) {1413 if (isByRef(param_ty, mod)) {
1410 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));1414 const alignment = param_ty.abiAlignment(mod).toLlvm();
1411 const param_llvm_ty = param.typeOfWip(&wip);1415 const param_llvm_ty = param.typeOfWip(&wip);
1412 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);1416 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
1413 _ = try wip.store(.normal, param, arg_ptr, alignment);1417 _ = try wip.store(.normal, param, arg_ptr, alignment);
...@@ -1423,7 +1427,7 @@ pub const Object = struct {...@@ -1423,7 +1427,7 @@ pub const Object = struct {
1423 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();1427 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1424 const param_llvm_ty = try o.lowerType(param_ty);1428 const param_llvm_ty = try o.lowerType(param_ty);
1425 const param = wip.arg(llvm_arg_i);1429 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
1428 try o.addByRefParamAttrs(&attributes, llvm_arg_i, alignment, it.byval_attr, param_llvm_ty);1432 try o.addByRefParamAttrs(&attributes, llvm_arg_i, alignment, it.byval_attr, param_llvm_ty);
1429 llvm_arg_i += 1;1433 llvm_arg_i += 1;
...@@ -1438,7 +1442,7 @@ pub const Object = struct {...@@ -1438,7 +1442,7 @@ pub const Object = struct {
1438 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();1442 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1439 const param_llvm_ty = try o.lowerType(param_ty);1443 const param_llvm_ty = try o.lowerType(param_ty);
1440 const param = wip.arg(llvm_arg_i);1444 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
1443 try attributes.addParamAttr(llvm_arg_i, .noundef, &o.builder);1447 try attributes.addParamAttr(llvm_arg_i, .noundef, &o.builder);
1444 llvm_arg_i += 1;1448 llvm_arg_i += 1;
...@@ -1456,7 +1460,7 @@ pub const Object = struct {...@@ -1456,7 +1460,7 @@ pub const Object = struct {
1456 llvm_arg_i += 1;1460 llvm_arg_i += 1;
14571461
1458 const param_llvm_ty = try o.lowerType(param_ty);1462 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();
1460 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);1464 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
1461 _ = try wip.store(.normal, param, arg_ptr, alignment);1465 _ = try wip.store(.normal, param, arg_ptr, alignment);
14621466
...@@ -1481,10 +1485,10 @@ pub const Object = struct {...@@ -1481,10 +1485,10 @@ pub const Object = struct {
1481 if (ptr_info.flags.is_const) {1485 if (ptr_info.flags.is_const) {
1482 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);1486 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
1483 }1487 }
1484 const elem_align = Builder.Alignment.fromByteUnits(1488 const elem_align = (if (ptr_info.flags.alignment != .none)
1485 ptr_info.flags.alignment.toByteUnitsOptional() orelse1489 @as(InternPool.Alignment, ptr_info.flags.alignment)
1486 @max(ptr_info.child.toType().abiAlignment(mod), 1),1490 else
1487 );1491 ptr_info.child.toType().abiAlignment(mod).max(.@"1")).toLlvm();
1488 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);1492 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
1489 const ptr_param = wip.arg(llvm_arg_i);1493 const ptr_param = wip.arg(llvm_arg_i);
1490 llvm_arg_i += 1;1494 llvm_arg_i += 1;
...@@ -1501,7 +1505,7 @@ pub const Object = struct {...@@ -1501,7 +1505,7 @@ pub const Object = struct {
1501 const field_types = it.types_buffer[0..it.types_len];1505 const field_types = it.types_buffer[0..it.types_len];
1502 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();1506 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
1503 const param_llvm_ty = try o.lowerType(param_ty);1507 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();
1505 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, param_alignment, target);1509 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, param_alignment, target);
1506 const llvm_ty = try o.builder.structType(.normal, field_types);1510 const llvm_ty = try o.builder.structType(.normal, field_types);
1507 for (0..field_types.len) |field_i| {1511 for (0..field_types.len) |field_i| {
...@@ -1531,7 +1535,7 @@ pub const Object = struct {...@@ -1531,7 +1535,7 @@ pub const Object = struct {
1531 const param = wip.arg(llvm_arg_i);1535 const param = wip.arg(llvm_arg_i);
1532 llvm_arg_i += 1;1536 llvm_arg_i += 1;
15331537
1534 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));1538 const alignment = param_ty.abiAlignment(mod).toLlvm();
1535 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);1539 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
1536 _ = try wip.store(.normal, param, arg_ptr, alignment);1540 _ = try wip.store(.normal, param, arg_ptr, alignment);
15371541
...@@ -1546,7 +1550,7 @@ pub const Object = struct {...@@ -1546,7 +1550,7 @@ pub const Object = struct {
1546 const param = wip.arg(llvm_arg_i);1550 const param = wip.arg(llvm_arg_i);
1547 llvm_arg_i += 1;1551 llvm_arg_i += 1;
15481552
1549 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));1553 const alignment = param_ty.abiAlignment(mod).toLlvm();
1550 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);1554 const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
1551 _ = try wip.store(.normal, param, arg_ptr, alignment);1555 _ = try wip.store(.normal, param, arg_ptr, alignment);
15521556
...@@ -1967,7 +1971,7 @@ pub const Object = struct {...@@ -1967,7 +1971,7 @@ pub const Object = struct {
1967 di_file,1971 di_file,
1968 owner_decl.src_node + 1,1972 owner_decl.src_node + 1,
1969 ty.abiSize(mod) * 8,1973 ty.abiSize(mod) * 8,
1970 ty.abiAlignment(mod) * 8,1974 ty.abiAlignment(mod).toByteUnits(0) * 8,
1971 enumerators.ptr,1975 enumerators.ptr,
1972 @intCast(enumerators.len),1976 @intCast(enumerators.len),
1973 try o.lowerDebugType(int_ty, .full),1977 try o.lowerDebugType(int_ty, .full),
...@@ -2055,7 +2059,7 @@ pub const Object = struct {...@@ -2055,7 +2059,7 @@ pub const Object = struct {
20552059
2056 var offset: u64 = 0;2060 var offset: u64 = 0;
2057 offset += ptr_size;2061 offset += ptr_size;
2058 offset = std.mem.alignForward(u64, offset, len_align);2062 offset = len_align.forward(offset);
2059 const len_offset = offset;2063 const len_offset = offset;
20602064
2061 const fields: [2]*llvm.DIType = .{2065 const fields: [2]*llvm.DIType = .{
...@@ -2065,7 +2069,7 @@ pub const Object = struct {...@@ -2065,7 +2069,7 @@ pub const Object = struct {
2065 di_file,2069 di_file,
2066 line,2070 line,
2067 ptr_size * 8, // size in bits2071 ptr_size * 8, // size in bits
2068 ptr_align * 8, // align in bits2072 ptr_align.toByteUnits(0) * 8, // align in bits
2069 0, // offset in bits2073 0, // offset in bits
2070 0, // flags2074 0, // flags
2071 try o.lowerDebugType(ptr_ty, .full),2075 try o.lowerDebugType(ptr_ty, .full),
...@@ -2076,7 +2080,7 @@ pub const Object = struct {...@@ -2076,7 +2080,7 @@ pub const Object = struct {
2076 di_file,2080 di_file,
2077 line,2081 line,
2078 len_size * 8, // size in bits2082 len_size * 8, // size in bits
2079 len_align * 8, // align in bits2083 len_align.toByteUnits(0) * 8, // align in bits
2080 len_offset * 8, // offset in bits2084 len_offset * 8, // offset in bits
2081 0, // flags2085 0, // flags
2082 try o.lowerDebugType(len_ty, .full),2086 try o.lowerDebugType(len_ty, .full),
...@@ -2089,7 +2093,7 @@ pub const Object = struct {...@@ -2089,7 +2093,7 @@ pub const Object = struct {
2089 di_file,2093 di_file,
2090 line,2094 line,
2091 ty.abiSize(mod) * 8, // size in bits2095 ty.abiSize(mod) * 8, // size in bits
2092 ty.abiAlignment(mod) * 8, // align in bits2096 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
2093 0, // flags2097 0, // flags
2094 null, // derived from2098 null, // derived from
2095 &fields,2099 &fields,
...@@ -2110,7 +2114,7 @@ pub const Object = struct {...@@ -2110,7 +2114,7 @@ pub const Object = struct {
2110 const ptr_di_ty = dib.createPointerType(2114 const ptr_di_ty = dib.createPointerType(
2111 elem_di_ty,2115 elem_di_ty,
2112 target.ptrBitWidth(),2116 target.ptrBitWidth(),
2113 ty.ptrAlignment(mod) * 8,2117 ty.ptrAlignment(mod).toByteUnits(0) * 8,
2114 name,2118 name,
2115 );2119 );
2116 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.2120 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
...@@ -2142,7 +2146,7 @@ pub const Object = struct {...@@ -2142,7 +2146,7 @@ pub const Object = struct {
2142 .Array => {2146 .Array => {
2143 const array_di_ty = dib.createArrayType(2147 const array_di_ty = dib.createArrayType(
2144 ty.abiSize(mod) * 8,2148 ty.abiSize(mod) * 8,
2145 ty.abiAlignment(mod) * 8,2149 ty.abiAlignment(mod).toByteUnits(0) * 8,
2146 try o.lowerDebugType(ty.childType(mod), .full),2150 try o.lowerDebugType(ty.childType(mod), .full),
2147 @intCast(ty.arrayLen(mod)),2151 @intCast(ty.arrayLen(mod)),
2148 );2152 );
...@@ -2174,7 +2178,7 @@ pub const Object = struct {...@@ -2174,7 +2178,7 @@ pub const Object = struct {
21742178
2175 const vector_di_ty = dib.createVectorType(2179 const vector_di_ty = dib.createVectorType(
2176 ty.abiSize(mod) * 8,2180 ty.abiSize(mod) * 8,
2177 ty.abiAlignment(mod) * 8,2181 @intCast(ty.abiAlignment(mod).toByteUnits(0) * 8),
2178 elem_di_type,2182 elem_di_type,
2179 ty.vectorLen(mod),2183 ty.vectorLen(mod),
2180 );2184 );
...@@ -2223,7 +2227,7 @@ pub const Object = struct {...@@ -2223,7 +2227,7 @@ pub const Object = struct {
22232227
2224 var offset: u64 = 0;2228 var offset: u64 = 0;
2225 offset += payload_size;2229 offset += payload_size;
2226 offset = std.mem.alignForward(u64, offset, non_null_align);2230 offset = non_null_align.forward(offset);
2227 const non_null_offset = offset;2231 const non_null_offset = offset;
22282232
2229 const fields: [2]*llvm.DIType = .{2233 const fields: [2]*llvm.DIType = .{
...@@ -2233,7 +2237,7 @@ pub const Object = struct {...@@ -2233,7 +2237,7 @@ pub const Object = struct {
2233 di_file,2237 di_file,
2234 line,2238 line,
2235 payload_size * 8, // size in bits2239 payload_size * 8, // size in bits
2236 payload_align * 8, // align in bits2240 payload_align.toByteUnits(0) * 8, // align in bits
2237 0, // offset in bits2241 0, // offset in bits
2238 0, // flags2242 0, // flags
2239 try o.lowerDebugType(child_ty, .full),2243 try o.lowerDebugType(child_ty, .full),
...@@ -2244,7 +2248,7 @@ pub const Object = struct {...@@ -2244,7 +2248,7 @@ pub const Object = struct {
2244 di_file,2248 di_file,
2245 line,2249 line,
2246 non_null_size * 8, // size in bits2250 non_null_size * 8, // size in bits
2247 non_null_align * 8, // align in bits2251 non_null_align.toByteUnits(0) * 8, // align in bits
2248 non_null_offset * 8, // offset in bits2252 non_null_offset * 8, // offset in bits
2249 0, // flags2253 0, // flags
2250 try o.lowerDebugType(non_null_ty, .full),2254 try o.lowerDebugType(non_null_ty, .full),
...@@ -2257,7 +2261,7 @@ pub const Object = struct {...@@ -2257,7 +2261,7 @@ pub const Object = struct {
2257 di_file,2261 di_file,
2258 line,2262 line,
2259 ty.abiSize(mod) * 8, // size in bits2263 ty.abiSize(mod) * 8, // size in bits
2260 ty.abiAlignment(mod) * 8, // align in bits2264 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
2261 0, // flags2265 0, // flags
2262 null, // derived from2266 null, // derived from
2263 &fields,2267 &fields,
...@@ -2306,16 +2310,16 @@ pub const Object = struct {...@@ -2306,16 +2310,16 @@ pub const Object = struct {
2306 var payload_index: u32 = undefined;2310 var payload_index: u32 = undefined;
2307 var error_offset: u64 = undefined;2311 var error_offset: u64 = undefined;
2308 var payload_offset: u64 = undefined;2312 var payload_offset: u64 = undefined;
2309 if (error_align > payload_align) {2313 if (error_align.compare(.gt, payload_align)) {
2310 error_index = 0;2314 error_index = 0;
2311 payload_index = 1;2315 payload_index = 1;
2312 error_offset = 0;2316 error_offset = 0;
2313 payload_offset = std.mem.alignForward(u64, error_size, payload_align);2317 payload_offset = payload_align.forward(error_size);
2314 } else {2318 } else {
2315 payload_index = 0;2319 payload_index = 0;
2316 error_index = 1;2320 error_index = 1;
2317 payload_offset = 0;2321 payload_offset = 0;
2318 error_offset = std.mem.alignForward(u64, payload_size, error_align);2322 error_offset = error_align.forward(payload_size);
2319 }2323 }
23202324
2321 var fields: [2]*llvm.DIType = undefined;2325 var fields: [2]*llvm.DIType = undefined;
...@@ -2325,7 +2329,7 @@ pub const Object = struct {...@@ -2325,7 +2329,7 @@ pub const Object = struct {
2325 di_file,2329 di_file,
2326 line,2330 line,
2327 error_size * 8, // size in bits2331 error_size * 8, // size in bits
2328 error_align * 8, // align in bits2332 error_align.toByteUnits(0) * 8, // align in bits
2329 error_offset * 8, // offset in bits2333 error_offset * 8, // offset in bits
2330 0, // flags2334 0, // flags
2331 try o.lowerDebugType(Type.anyerror, .full),2335 try o.lowerDebugType(Type.anyerror, .full),
...@@ -2336,7 +2340,7 @@ pub const Object = struct {...@@ -2336,7 +2340,7 @@ pub const Object = struct {
2336 di_file,2340 di_file,
2337 line,2341 line,
2338 payload_size * 8, // size in bits2342 payload_size * 8, // size in bits
2339 payload_align * 8, // align in bits2343 payload_align.toByteUnits(0) * 8, // align in bits
2340 payload_offset * 8, // offset in bits2344 payload_offset * 8, // offset in bits
2341 0, // flags2345 0, // flags
2342 try o.lowerDebugType(payload_ty, .full),2346 try o.lowerDebugType(payload_ty, .full),
...@@ -2348,7 +2352,7 @@ pub const Object = struct {...@@ -2348,7 +2352,7 @@ pub const Object = struct {
2348 di_file,2352 di_file,
2349 line,2353 line,
2350 ty.abiSize(mod) * 8, // size in bits2354 ty.abiSize(mod) * 8, // size in bits
2351 ty.abiAlignment(mod) * 8, // align in bits2355 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
2352 0, // flags2356 0, // flags
2353 null, // derived from2357 null, // derived from
2354 &fields,2358 &fields,
...@@ -2374,10 +2378,10 @@ pub const Object = struct {...@@ -2374,10 +2378,10 @@ pub const Object = struct {
2374 const name = try o.allocTypeName(ty);2378 const name = try o.allocTypeName(ty);
2375 defer gpa.free(name);2379 defer gpa.free(name);
23762380
2377 if (mod.typeToStruct(ty)) |struct_obj| {2381 if (mod.typeToPackedStruct(ty)) |struct_type| {
2378 if (struct_obj.layout == .Packed and struct_obj.haveFieldTypes()) {2382 const backing_int_ty = struct_type.backingIntType(ip).*;
2379 assert(struct_obj.haveLayout());2383 if (backing_int_ty != .none) {
2380 const info = struct_obj.backing_int_ty.intInfo(mod);2384 const info = backing_int_ty.toType().intInfo(mod);
2381 const dwarf_encoding: c_uint = switch (info.signedness) {2385 const dwarf_encoding: c_uint = switch (info.signedness) {
2382 .signed => DW.ATE.signed,2386 .signed => DW.ATE.signed,
2383 .unsigned => DW.ATE.unsigned,2387 .unsigned => DW.ATE.unsigned,
...@@ -2417,7 +2421,7 @@ pub const Object = struct {...@@ -2417,7 +2421,7 @@ pub const Object = struct {
24172421
2418 const field_size = field_ty.toType().abiSize(mod);2422 const field_size = field_ty.toType().abiSize(mod);
2419 const field_align = field_ty.toType().abiAlignment(mod);2423 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);
2421 offset = field_offset + field_size;2425 offset = field_offset + field_size;
24222426
2423 const field_name = if (tuple.names.len != 0)2427 const field_name = if (tuple.names.len != 0)
...@@ -2432,7 +2436,7 @@ pub const Object = struct {...@@ -2432,7 +2436,7 @@ pub const Object = struct {
2432 null, // file2436 null, // file
2433 0, // line2437 0, // line
2434 field_size * 8, // size in bits2438 field_size * 8, // size in bits
2435 field_align * 8, // align in bits2439 field_align.toByteUnits(0) * 8, // align in bits
2436 field_offset * 8, // offset in bits2440 field_offset * 8, // offset in bits
2437 0, // flags2441 0, // flags
2438 try o.lowerDebugType(field_ty.toType(), .full),2442 try o.lowerDebugType(field_ty.toType(), .full),
...@@ -2445,7 +2449,7 @@ pub const Object = struct {...@@ -2445,7 +2449,7 @@ pub const Object = struct {
2445 null, // file2449 null, // file
2446 0, // line2450 0, // line
2447 ty.abiSize(mod) * 8, // size in bits2451 ty.abiSize(mod) * 8, // size in bits
2448 ty.abiAlignment(mod) * 8, // align in bits2452 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
2449 0, // flags2453 0, // flags
2450 null, // derived from2454 null, // derived from
2451 di_fields.items.ptr,2455 di_fields.items.ptr,
...@@ -2459,10 +2463,8 @@ pub const Object = struct {...@@ -2459,10 +2463,8 @@ pub const Object = struct {
2459 try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(full_di_ty));2463 try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(full_di_ty));
2460 return full_di_ty;2464 return full_di_ty;
2461 },2465 },
2462 .struct_type => |struct_type| s: {2466 .struct_type => |struct_type| {
2463 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :s;2467 if (!struct_type.haveFieldTypes(ip)) {
2464
2465 if (!struct_obj.haveFieldTypes()) {
2466 // This can happen if a struct type makes it all the way to2468 // This can happen if a struct type makes it all the way to
2467 // flush() without ever being instantiated or referenced (even2469 // flush() without ever being instantiated or referenced (even
2468 // via pointer). The only reason we are hearing about it now is2470 // via pointer). The only reason we are hearing about it now is
...@@ -2492,37 +2494,41 @@ pub const Object = struct {...@@ -2492,37 +2494,41 @@ pub const Object = struct {
2492 return struct_di_ty;2494 return struct_di_ty;
2493 }2495 }
24942496
2495 const fields = ty.structFields(mod);2497 const struct_type = mod.typeToStruct(ty).?;
2496 const layout = ty.containerLayout(mod);
24972498
2498 var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};2499 var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
2499 defer di_fields.deinit(gpa);2500 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
2503 comptime assert(struct_layout_version == 2);2504 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);2517 const field_name = struct_type.fieldName(ip, field_index).unwrap() orelse
2507 while (it.next()) |field_and_index| {2518 try ip.getOrPutStringFmt(gpa, "{d}", .{field_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;
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
2516 try di_fields.append(gpa, dib.createMemberType(2522 try di_fields.append(gpa, dib.createMemberType(
2517 fwd_decl.toScope(),2523 fwd_decl.toScope(),
2518 field_name,2524 ip.stringToSlice(field_name),
2519 null, // file2525 null, // file
2520 0, // line2526 0, // line
2521 field_size * 8, // size in bits2527 field_size * 8, // size in bits
2522 field_align * 8, // align in bits2528 field_align.toByteUnits(0) * 8, // align in bits
2523 field_offset * 8, // offset in bits2529 field_offset * 8, // offset in bits
2524 0, // flags2530 0, // flags
2525 try o.lowerDebugType(field.ty, .full),2531 field_di_ty,
2526 ));2532 ));
2527 }2533 }
25282534
...@@ -2532,7 +2538,7 @@ pub const Object = struct {...@@ -2532,7 +2538,7 @@ pub const Object = struct {
2532 null, // file2538 null, // file
2533 0, // line2539 0, // line
2534 ty.abiSize(mod) * 8, // size in bits2540 ty.abiSize(mod) * 8, // size in bits
2535 ty.abiAlignment(mod) * 8, // align in bits2541 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
2536 0, // flags2542 0, // flags
2537 null, // derived from2543 null, // derived from
2538 di_fields.items.ptr,2544 di_fields.items.ptr,
...@@ -2588,7 +2594,7 @@ pub const Object = struct {...@@ -2588,7 +2594,7 @@ pub const Object = struct {
2588 null, // file2594 null, // file
2589 0, // line2595 0, // line
2590 ty.abiSize(mod) * 8, // size in bits2596 ty.abiSize(mod) * 8, // size in bits
2591 ty.abiAlignment(mod) * 8, // align in bits2597 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
2592 0, // flags2598 0, // flags
2593 null, // derived from2599 null, // derived from
2594 &di_fields,2600 &di_fields,
...@@ -2624,7 +2630,7 @@ pub const Object = struct {...@@ -2624,7 +2630,7 @@ pub const Object = struct {
2624 null, // file2630 null, // file
2625 0, // line2631 0, // line
2626 field_size * 8, // size in bits2632 field_size * 8, // size in bits
2627 field_align * 8, // align in bits2633 field_align.toByteUnits(0) * 8, // align in bits
2628 0, // offset in bits2634 0, // offset in bits
2629 0, // flags2635 0, // flags
2630 field_di_ty,2636 field_di_ty,
...@@ -2644,7 +2650,7 @@ pub const Object = struct {...@@ -2644,7 +2650,7 @@ pub const Object = struct {
2644 null, // file2650 null, // file
2645 0, // line2651 0, // line
2646 ty.abiSize(mod) * 8, // size in bits2652 ty.abiSize(mod) * 8, // size in bits
2647 ty.abiAlignment(mod) * 8, // align in bits2653 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
2648 0, // flags2654 0, // flags
2649 di_fields.items.ptr,2655 di_fields.items.ptr,
2650 @intCast(di_fields.items.len),2656 @intCast(di_fields.items.len),
...@@ -2661,12 +2667,12 @@ pub const Object = struct {...@@ -2661,12 +2667,12 @@ pub const Object = struct {
26612667
2662 var tag_offset: u64 = undefined;2668 var tag_offset: u64 = undefined;
2663 var payload_offset: u64 = undefined;2669 var payload_offset: u64 = undefined;
2664 if (layout.tag_align >= layout.payload_align) {2670 if (layout.tag_align.compare(.gte, layout.payload_align)) {
2665 tag_offset = 0;2671 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);
2667 } else {2673 } else {
2668 payload_offset = 0;2674 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);
2670 }2676 }
26712677
2672 const tag_di = dib.createMemberType(2678 const tag_di = dib.createMemberType(
...@@ -2675,7 +2681,7 @@ pub const Object = struct {...@@ -2675,7 +2681,7 @@ pub const Object = struct {
2675 null, // file2681 null, // file
2676 0, // line2682 0, // line
2677 layout.tag_size * 8,2683 layout.tag_size * 8,
2678 layout.tag_align * 8, // align in bits2684 layout.tag_align.toByteUnits(0) * 8,
2679 tag_offset * 8, // offset in bits2685 tag_offset * 8, // offset in bits
2680 0, // flags2686 0, // flags
2681 try o.lowerDebugType(union_obj.enum_tag_ty.toType(), .full),2687 try o.lowerDebugType(union_obj.enum_tag_ty.toType(), .full),
...@@ -2687,14 +2693,14 @@ pub const Object = struct {...@@ -2687,14 +2693,14 @@ pub const Object = struct {
2687 null, // file2693 null, // file
2688 0, // line2694 0, // line
2689 layout.payload_size * 8, // size in bits2695 layout.payload_size * 8, // size in bits
2690 layout.payload_align * 8, // align in bits2696 layout.payload_align.toByteUnits(0) * 8,
2691 payload_offset * 8, // offset in bits2697 payload_offset * 8, // offset in bits
2692 0, // flags2698 0, // flags
2693 union_di_ty,2699 union_di_ty,
2694 );2700 );
26952701
2696 const full_di_fields: [2]*llvm.DIType =2702 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))
2698 .{ tag_di, payload_di }2704 .{ tag_di, payload_di }
2699 else2705 else
2700 .{ payload_di, tag_di };2706 .{ payload_di, tag_di };
...@@ -2705,7 +2711,7 @@ pub const Object = struct {...@@ -2705,7 +2711,7 @@ pub const Object = struct {
2705 null, // file2711 null, // file
2706 0, // line2712 0, // line
2707 ty.abiSize(mod) * 8, // size in bits2713 ty.abiSize(mod) * 8, // size in bits
2708 ty.abiAlignment(mod) * 8, // align in bits2714 ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
2709 0, // flags2715 0, // flags
2710 null, // derived from2716 null, // derived from
2711 &full_di_fields,2717 &full_di_fields,
...@@ -2925,8 +2931,8 @@ pub const Object = struct {...@@ -2925,8 +2931,8 @@ pub const Object = struct {
2925 else => function_index.setCallConv(toLlvmCallConv(fn_info.cc, target), &o.builder),2931 else => function_index.setCallConv(toLlvmCallConv(fn_info.cc, target), &o.builder),
2926 }2932 }
29272933
2928 if (fn_info.alignment.toByteUnitsOptional()) |alignment|2934 if (fn_info.alignment != .none)
2929 function_index.setAlignment(Builder.Alignment.fromByteUnits(alignment), &o.builder);2935 function_index.setAlignment(fn_info.alignment.toLlvm(), &o.builder);
29302936
2931 // Function attributes that are independent of analysis results of the function body.2937 // Function attributes that are independent of analysis results of the function body.
2932 try o.addCommonFnAttributes(&attributes);2938 try o.addCommonFnAttributes(&attributes);
...@@ -2949,9 +2955,8 @@ pub const Object = struct {...@@ -2949,9 +2955,8 @@ pub const Object = struct {
2949 .byref => {2955 .byref => {
2950 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1];2956 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1];
2951 const param_llvm_ty = try o.lowerType(param_ty.toType());2957 const param_llvm_ty = try o.lowerType(param_ty.toType());
2952 const alignment =2958 const alignment = param_ty.toType().abiAlignment(mod);
2953 Builder.Alignment.fromByteUnits(param_ty.toType().abiAlignment(mod));2959 try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment.toLlvm(), it.byval_attr, param_llvm_ty);
2954 try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
2955 },2960 },
2956 .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder),2961 .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder),
2957 // No attributes needed for these.2962 // No attributes needed for these.
...@@ -3248,21 +3253,21 @@ pub const Object = struct {...@@ -3248,21 +3253,21 @@ pub const Object = struct {
32483253
3249 var fields: [3]Builder.Type = undefined;3254 var fields: [3]Builder.Type = undefined;
3250 var fields_len: usize = 2;3255 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: {
3252 fields[0] = error_type;3257 fields[0] = error_type;
3253 fields[1] = payload_type;3258 fields[1] = payload_type;
3254 const payload_end =3259 const payload_end =
3255 std.mem.alignForward(u64, error_size, payload_align) +3260 payload_align.forward(error_size) +
3256 payload_size;3261 payload_size;
3257 const abi_size = std.mem.alignForward(u64, payload_end, error_align);3262 const abi_size = error_align.forward(payload_end);
3258 break :pad abi_size - payload_end;3263 break :pad abi_size - payload_end;
3259 } else pad: {3264 } else pad: {
3260 fields[0] = payload_type;3265 fields[0] = payload_type;
3261 fields[1] = error_type;3266 fields[1] = error_type;
3262 const error_end =3267 const error_end =
3263 std.mem.alignForward(u64, payload_size, error_align) +3268 error_align.forward(payload_size) +
3264 error_size;3269 error_size;
3265 const abi_size = std.mem.alignForward(u64, error_end, payload_align);3270 const abi_size = payload_align.forward(error_end);
3266 break :pad abi_size - error_end;3271 break :pad abi_size - error_end;
3267 };3272 };
3268 if (padding_len > 0) {3273 if (padding_len > 0) {
...@@ -3276,60 +3281,74 @@ pub const Object = struct {...@@ -3276,60 +3281,74 @@ pub const Object = struct {
3276 const gop = try o.type_map.getOrPut(o.gpa, t.toIntern());3281 const gop = try o.type_map.getOrPut(o.gpa, t.toIntern());
3277 if (gop.found_existing) return gop.value_ptr.*;3282 if (gop.found_existing) return gop.value_ptr.*;
32783283
3279 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;3284 if (struct_type.layout == .Packed) {
3280 if (struct_obj.layout == .Packed) {3285 const int_ty = try o.lowerType(struct_type.backingIntType(ip).toType());
3281 assert(struct_obj.haveLayout());
3282 const int_ty = try o.lowerType(struct_obj.backing_int_ty);
3283 gop.value_ptr.* = int_ty;3286 gop.value_ptr.* = int_ty;
3284 return int_ty;3287 return int_ty;
3285 }3288 }
32863289
3287 const name = try o.builder.string(ip.stringToSlice(3290 const name = try o.builder.string(ip.stringToSlice(
3288 try struct_obj.getFullyQualifiedName(mod),3291 try mod.declPtr(struct_type.decl.unwrap().?).getFullyQualifiedName(mod),
3289 ));3292 ));
3290 const ty = try o.builder.opaqueType(name);3293 const ty = try o.builder.opaqueType(name);
3291 gop.value_ptr.* = ty; // must be done before any recursive calls3294 gop.value_ptr.* = ty; // must be done before any recursive calls
32923295
3293 assert(struct_obj.haveFieldTypes());
3294
3295 var llvm_field_types = std.ArrayListUnmanaged(Builder.Type){};3296 var llvm_field_types = std.ArrayListUnmanaged(Builder.Type){};
3296 defer llvm_field_types.deinit(o.gpa);3297 defer llvm_field_types.deinit(o.gpa);
3297 // Although we can estimate how much capacity to add, these cannot be3298 // Although we can estimate how much capacity to add, these cannot be
3298 // relied upon because of the recursive calls to lowerType below.3299 // relied upon because of the recursive calls to lowerType below.
3299 try llvm_field_types.ensureUnusedCapacity(o.gpa, struct_obj.fields.count());3300 try llvm_field_types.ensureUnusedCapacity(o.gpa, struct_type.field_types.len);
3300 try o.struct_field_map.ensureUnusedCapacity(o.gpa, @intCast(struct_obj.fields.count()));3301 try o.struct_field_map.ensureUnusedCapacity(o.gpa, struct_type.field_types.len);
33013302
3302 comptime assert(struct_layout_version == 2);3303 comptime assert(struct_layout_version == 2);
3303 var offset: u64 = 0;3304 var offset: u64 = 0;
3304 var big_align: u32 = 1;3305 var big_align: InternPool.Alignment = .@"1";
3305 var struct_kind: Builder.Type.Structure.Kind = .normal;3306 var struct_kind: Builder.Type.Structure.Kind = .normal;
33063307 // 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).
3307 var it = struct_obj.runtimeFieldIterator(mod);3308 var it = struct_type.iterateRuntimeOrder(ip);
3308 while (it.next()) |field_and_index| {3309 while (it.next()) |field_index| {
3309 const field = field_and_index.field;3310 const field_ty = struct_type.field_types.get(ip)[field_index].toType();
3310 const field_align = field.alignment(mod, struct_obj.layout);3311 const field_align = mod.structFieldAlignment(
3311 const field_ty_align = field.ty.abiAlignment(mod);3312 struct_type.fieldAlign(ip, field_index),
3312 if (field_align < field_ty_align) struct_kind = .@"packed";3313 field_ty,
3313 big_align = @max(big_align, field_align);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);
3314 const prev_offset = offset;3319 const prev_offset = offset;
3315 offset = std.mem.alignForward(u64, offset, field_align);3320 offset = field_align.forward(offset);
33163321
3317 const padding_len = offset - prev_offset;3322 const padding_len = offset - prev_offset;
3318 if (padding_len > 0) try llvm_field_types.append(3323 if (padding_len > 0) try llvm_field_types.append(
3319 o.gpa,3324 o.gpa,
3320 try o.builder.arrayType(padding_len, .i8),3325 try o.builder.arrayType(padding_len, .i8),
3321 );3326 );
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
3322 try o.struct_field_map.put(o.gpa, .{3341 try o.struct_field_map.put(o.gpa, .{
3323 .struct_ty = t.toIntern(),3342 .struct_ty = t.toIntern(),
3324 .field_index = field_and_index.index,3343 .field_index = field_index,
3325 }, @intCast(llvm_field_types.items.len));3344 }, @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);
3329 }3348 }
3330 {3349 {
3331 const prev_offset = offset;3350 const prev_offset = offset;
3332 offset = std.mem.alignForward(u64, offset, big_align);3351 offset = big_align.forward(offset);
3333 const padding_len = offset - prev_offset;3352 const padding_len = offset - prev_offset;
3334 if (padding_len > 0) try llvm_field_types.append(3353 if (padding_len > 0) try llvm_field_types.append(
3335 o.gpa,3354 o.gpa,
...@@ -3353,25 +3372,39 @@ pub const Object = struct {...@@ -3353,25 +3372,39 @@ pub const Object = struct {
33533372
3354 comptime assert(struct_layout_version == 2);3373 comptime assert(struct_layout_version == 2);
3355 var offset: u64 = 0;3374 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
3358 for (3379 for (
3359 anon_struct_type.types.get(ip),3380 anon_struct_type.types.get(ip),
3360 anon_struct_type.values.get(ip),3381 anon_struct_type.values.get(ip),
3361 0..,3382 0..,
3362 ) |field_ty, field_val, field_index| {3383 ) |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
3365 const field_align = field_ty.toType().abiAlignment(mod);3386 const field_align = field_ty.toType().abiAlignment(mod);
3366 big_align = @max(big_align, field_align);3387 big_align = big_align.max(field_align);
3367 const prev_offset = offset;3388 const prev_offset = offset;
3368 offset = std.mem.alignForward(u64, offset, field_align);3389 offset = field_align.forward(offset);
33693390
3370 const padding_len = offset - prev_offset;3391 const padding_len = offset - prev_offset;
3371 if (padding_len > 0) try llvm_field_types.append(3392 if (padding_len > 0) try llvm_field_types.append(
3372 o.gpa,3393 o.gpa,
3373 try o.builder.arrayType(padding_len, .i8),3394 try o.builder.arrayType(padding_len, .i8),
3374 );3395 );
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 }
3375 try o.struct_field_map.put(o.gpa, .{3408 try o.struct_field_map.put(o.gpa, .{
3376 .struct_ty = t.toIntern(),3409 .struct_ty = t.toIntern(),
3377 .field_index = @intCast(field_index),3410 .field_index = @intCast(field_index),
...@@ -3382,7 +3415,7 @@ pub const Object = struct {...@@ -3382,7 +3415,7 @@ pub const Object = struct {
3382 }3415 }
3383 {3416 {
3384 const prev_offset = offset;3417 const prev_offset = offset;
3385 offset = std.mem.alignForward(u64, offset, big_align);3418 offset = big_align.forward(offset);
3386 const padding_len = offset - prev_offset;3419 const padding_len = offset - prev_offset;
3387 if (padding_len > 0) try llvm_field_types.append(3420 if (padding_len > 0) try llvm_field_types.append(
3388 o.gpa,3421 o.gpa,
...@@ -3447,7 +3480,7 @@ pub const Object = struct {...@@ -3447,7 +3480,7 @@ pub const Object = struct {
3447 var llvm_fields: [3]Builder.Type = undefined;3480 var llvm_fields: [3]Builder.Type = undefined;
3448 var llvm_fields_len: usize = 2;3481 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)) {
3451 llvm_fields = .{ enum_tag_ty, payload_ty, .none };3484 llvm_fields = .{ enum_tag_ty, payload_ty, .none };
3452 } else {3485 } else {
3453 llvm_fields = .{ payload_ty, enum_tag_ty, .none };3486 llvm_fields = .{ payload_ty, enum_tag_ty, .none };
...@@ -3687,7 +3720,7 @@ pub const Object = struct {...@@ -3687,7 +3720,7 @@ pub const Object = struct {
36873720
3688 var fields: [3]Builder.Type = undefined;3721 var fields: [3]Builder.Type = undefined;
3689 var vals: [3]Builder.Constant = undefined;3722 var vals: [3]Builder.Constant = undefined;
3690 if (error_align > payload_align) {3723 if (error_align.compare(.gt, payload_align)) {
3691 vals[0] = llvm_error_value;3724 vals[0] = llvm_error_value;
3692 vals[1] = llvm_payload_value;3725 vals[1] = llvm_payload_value;
3693 } else {3726 } else {
...@@ -3910,7 +3943,7 @@ pub const Object = struct {...@@ -3910,7 +3943,7 @@ pub const Object = struct {
3910 comptime assert(struct_layout_version == 2);3943 comptime assert(struct_layout_version == 2);
3911 var llvm_index: usize = 0;3944 var llvm_index: usize = 0;
3912 var offset: u64 = 0;3945 var offset: u64 = 0;
3913 var big_align: u32 = 0;3946 var big_align: InternPool.Alignment = .none;
3914 var need_unnamed = false;3947 var need_unnamed = false;
3915 for (3948 for (
3916 tuple.types.get(ip),3949 tuple.types.get(ip),
...@@ -3921,9 +3954,9 @@ pub const Object = struct {...@@ -3921,9 +3954,9 @@ pub const Object = struct {
3921 if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;3954 if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
39223955
3923 const field_align = field_ty.toType().abiAlignment(mod);3956 const field_align = field_ty.toType().abiAlignment(mod);
3924 big_align = @max(big_align, field_align);3957 big_align = big_align.max(field_align);
3925 const prev_offset = offset;3958 const prev_offset = offset;
3926 offset = std.mem.alignForward(u64, offset, field_align);3959 offset = field_align.forward(offset);
39273960
3928 const padding_len = offset - prev_offset;3961 const padding_len = offset - prev_offset;
3929 if (padding_len > 0) {3962 if (padding_len > 0) {
...@@ -3946,7 +3979,7 @@ pub const Object = struct {...@@ -3946,7 +3979,7 @@ pub const Object = struct {
3946 }3979 }
3947 {3980 {
3948 const prev_offset = offset;3981 const prev_offset = offset;
3949 offset = std.mem.alignForward(u64, offset, big_align);3982 offset = big_align.forward(offset);
3950 const padding_len = offset - prev_offset;3983 const padding_len = offset - prev_offset;
3951 if (padding_len > 0) {3984 if (padding_len > 0) {
3952 fields[llvm_index] = try o.builder.arrayType(padding_len, .i8);3985 fields[llvm_index] = try o.builder.arrayType(padding_len, .i8);
...@@ -3963,22 +3996,21 @@ pub const Object = struct {...@@ -3963,22 +3996,21 @@ pub const Object = struct {
3963 struct_ty, vals);3996 struct_ty, vals);
3964 },3997 },
3965 .struct_type => |struct_type| {3998 .struct_type => |struct_type| {
3966 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;3999 assert(struct_type.haveLayout(ip));
3967 assert(struct_obj.haveLayout());
3968 const struct_ty = try o.lowerType(ty);4000 const struct_ty = try o.lowerType(ty);
3969 if (struct_obj.layout == .Packed) {4001 if (struct_type.layout == .Packed) {
3970 comptime assert(Type.packed_struct_layout_version == 2);4002 comptime assert(Type.packed_struct_layout_version == 2);
3971 var running_int = try o.builder.intConst(struct_ty, 0);4003 var running_int = try o.builder.intConst(struct_ty, 0);
3972 var running_bits: u16 = 0;4004 var running_bits: u16 = 0;
3973 for (struct_obj.fields.values(), 0..) |field, field_index| {4005 for (struct_type.field_types.get(ip), 0..) |field_ty, field_index| {
3974 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;4006 if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
39754007
3976 const non_int_val =4008 const non_int_val =
3977 try o.lowerValue((try val.fieldValue(mod, field_index)).toIntern());4009 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));
3979 const small_int_ty = try o.builder.intType(ty_bit_size);4011 const small_int_ty = try o.builder.intType(ty_bit_size);
3980 const small_int_val = try o.builder.castConst(4012 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,
3982 non_int_val,4014 non_int_val,
3983 small_int_ty,4015 small_int_ty,
3984 );4016 );
...@@ -4010,15 +4042,19 @@ pub const Object = struct {...@@ -4010,15 +4042,19 @@ pub const Object = struct {
4010 comptime assert(struct_layout_version == 2);4042 comptime assert(struct_layout_version == 2);
4011 var llvm_index: usize = 0;4043 var llvm_index: usize = 0;
4012 var offset: u64 = 0;4044 var offset: u64 = 0;
4013 var big_align: u32 = 0;4045 var big_align: InternPool.Alignment = .@"1";
4014 var need_unnamed = false;4046 var need_unnamed = false;
4015 var field_it = struct_obj.runtimeFieldIterator(mod);4047 var field_it = struct_type.iterateRuntimeOrder(ip);
4016 while (field_it.next()) |field_and_index| {4048 while (field_it.next()) |field_index| {
4017 const field = field_and_index.field;4049 const field_ty = struct_type.field_types.get(ip)[field_index].toType();
4018 const field_align = field.alignment(mod, struct_obj.layout);4050 const field_align = mod.structFieldAlignment(
4019 big_align = @max(big_align, field_align);4051 struct_type.fieldAlign(ip, field_index),
4052 field_ty,
4053 struct_type.layout,
4054 );
4055 big_align = big_align.max(field_align);
4020 const prev_offset = offset;4056 const prev_offset = offset;
4021 offset = std.mem.alignForward(u64, offset, field_align);4057 offset = field_align.forward(offset);
40224058
4023 const padding_len = offset - prev_offset;4059 const padding_len = offset - prev_offset;
4024 if (padding_len > 0) {4060 if (padding_len > 0) {
...@@ -4031,19 +4067,24 @@ pub const Object = struct {...@@ -4031,19 +4067,24 @@ pub const Object = struct {
4031 llvm_index += 1;4067 llvm_index += 1;
4032 }4068 }
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
4034 vals[llvm_index] = try o.lowerValue(4075 vals[llvm_index] = try o.lowerValue(
4035 (try val.fieldValue(mod, field_and_index.index)).toIntern(),4076 (try val.fieldValue(mod, field_index)).toIntern(),
4036 );4077 );
4037 fields[llvm_index] = vals[llvm_index].typeOf(&o.builder);4078 fields[llvm_index] = vals[llvm_index].typeOf(&o.builder);
4038 if (fields[llvm_index] != struct_ty.structFields(&o.builder)[llvm_index])4079 if (fields[llvm_index] != struct_ty.structFields(&o.builder)[llvm_index])
4039 need_unnamed = true;4080 need_unnamed = true;
4040 llvm_index += 1;4081 llvm_index += 1;
40414082
4042 offset += field.ty.abiSize(mod);4083 offset += field_ty.abiSize(mod);
4043 }4084 }
4044 {4085 {
4045 const prev_offset = offset;4086 const prev_offset = offset;
4046 offset = std.mem.alignForward(u64, offset, big_align);4087 offset = big_align.forward(offset);
4047 const padding_len = offset - prev_offset;4088 const padding_len = offset - prev_offset;
4048 if (padding_len > 0) {4089 if (padding_len > 0) {
4049 fields[llvm_index] = try o.builder.arrayType(padding_len, .i8);4090 fields[llvm_index] = try o.builder.arrayType(padding_len, .i8);
...@@ -4093,7 +4134,7 @@ pub const Object = struct {...@@ -4093,7 +4134,7 @@ pub const Object = struct {
4093 const payload = try o.lowerValue(un.val);4134 const payload = try o.lowerValue(un.val);
4094 const payload_ty = payload.typeOf(&o.builder);4135 const payload_ty = payload.typeOf(&o.builder);
4095 if (payload_ty != union_ty.structFields(&o.builder)[4136 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))
4097 ]) need_unnamed = true;4138 ]) need_unnamed = true;
4098 const field_size = field_ty.abiSize(mod);4139 const field_size = field_ty.abiSize(mod);
4099 if (field_size == layout.payload_size) break :p payload;4140 if (field_size == layout.payload_size) break :p payload;
...@@ -4115,7 +4156,7 @@ pub const Object = struct {...@@ -4115,7 +4156,7 @@ pub const Object = struct {
4115 var fields: [3]Builder.Type = undefined;4156 var fields: [3]Builder.Type = undefined;
4116 var vals: [3]Builder.Constant = undefined;4157 var vals: [3]Builder.Constant = undefined;
4117 var len: usize = 2;4158 var len: usize = 2;
4118 if (layout.tag_align >= layout.payload_align) {4159 if (layout.tag_align.compare(.gte, layout.payload_align)) {
4119 fields = .{ tag_ty, payload_ty, undefined };4160 fields = .{ tag_ty, payload_ty, undefined };
4120 vals = .{ tag, payload, undefined };4161 vals = .{ tag, payload, undefined };
4121 } else {4162 } else {
...@@ -4174,14 +4215,15 @@ pub const Object = struct {...@@ -4174,14 +4215,15 @@ pub const Object = struct {
41744215
4175 fn lowerParentPtr(o: *Object, ptr_val: Value, byte_aligned: bool) Allocator.Error!Builder.Constant {4216 fn lowerParentPtr(o: *Object, ptr_val: Value, byte_aligned: bool) Allocator.Error!Builder.Constant {
4176 const mod = o.module;4217 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) {
4178 .decl => |decl| o.lowerParentPtrDecl(decl),4220 .decl => |decl| o.lowerParentPtrDecl(decl),
4179 .mut_decl => |mut_decl| o.lowerParentPtrDecl(mut_decl.decl),4221 .mut_decl => |mut_decl| o.lowerParentPtrDecl(mut_decl.decl),
4180 .int => |int| try o.lowerIntAsPtr(int),4222 .int => |int| try o.lowerIntAsPtr(int),
4181 .eu_payload => |eu_ptr| {4223 .eu_payload => |eu_ptr| {
4182 const parent_ptr = try o.lowerParentPtr(eu_ptr.toValue(), true);4224 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);
4185 const payload_ty = eu_ty.errorUnionPayload(mod);4227 const payload_ty = eu_ty.errorUnionPayload(mod);
4186 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {4228 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
4187 // In this case, we represent pointer to error union the same as pointer4229 // In this case, we represent pointer to error union the same as pointer
...@@ -4189,8 +4231,9 @@ pub const Object = struct {...@@ -4189,8 +4231,9 @@ pub const Object = struct {
4189 return parent_ptr;4231 return parent_ptr;
4190 }4232 }
41914233
4192 const index: u32 =4234 const payload_align = payload_ty.abiAlignment(mod);
4193 if (payload_ty.abiAlignment(mod) > Type.err_int.abiSize(mod)) 2 else 1;4235 const err_align = Type.err_int.abiAlignment(mod);
4236 const index: u32 = if (payload_align.compare(.gt, err_align)) 2 else 1;
4194 return o.builder.gepConst(.inbounds, try o.lowerType(eu_ty), parent_ptr, null, &.{4237 return o.builder.gepConst(.inbounds, try o.lowerType(eu_ty), parent_ptr, null, &.{
4195 try o.builder.intConst(.i32, 0), try o.builder.intConst(.i32, index),4238 try o.builder.intConst(.i32, 0), try o.builder.intConst(.i32, index),
4196 });4239 });
...@@ -4198,7 +4241,7 @@ pub const Object = struct {...@@ -4198,7 +4241,7 @@ pub const Object = struct {
4198 .opt_payload => |opt_ptr| {4241 .opt_payload => |opt_ptr| {
4199 const parent_ptr = try o.lowerParentPtr(opt_ptr.toValue(), true);4242 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);
4202 const payload_ty = opt_ty.optionalChild(mod);4245 const payload_ty = opt_ty.optionalChild(mod);
4203 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod) or4246 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod) or
4204 payload_ty.optionalReprIsPayload(mod))4247 payload_ty.optionalReprIsPayload(mod))
...@@ -4215,7 +4258,7 @@ pub const Object = struct {...@@ -4215,7 +4258,7 @@ pub const Object = struct {
4215 .comptime_field => unreachable,4258 .comptime_field => unreachable,
4216 .elem => |elem_ptr| {4259 .elem => |elem_ptr| {
4217 const parent_ptr = try o.lowerParentPtr(elem_ptr.base.toValue(), true);4260 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
4220 return o.builder.gepConst(.inbounds, try o.lowerType(elem_ty), parent_ptr, null, &.{4263 return o.builder.gepConst(.inbounds, try o.lowerType(elem_ty), parent_ptr, null, &.{
4221 try o.builder.intConst(try o.lowerType(Type.usize), elem_ptr.index),4264 try o.builder.intConst(try o.lowerType(Type.usize), elem_ptr.index),
...@@ -4223,7 +4266,7 @@ pub const Object = struct {...@@ -4223,7 +4266,7 @@ pub const Object = struct {
4223 },4266 },
4224 .field => |field_ptr| {4267 .field => |field_ptr| {
4225 const parent_ptr = try o.lowerParentPtr(field_ptr.base.toValue(), byte_aligned);4268 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
4228 const field_index: u32 = @intCast(field_ptr.index);4271 const field_index: u32 = @intCast(field_ptr.index);
4229 switch (parent_ty.zigTypeTag(mod)) {4272 switch (parent_ty.zigTypeTag(mod)) {
...@@ -4241,24 +4284,26 @@ pub const Object = struct {...@@ -4241,24 +4284,26 @@ pub const Object = struct {
42414284
4242 const parent_llvm_ty = try o.lowerType(parent_ty);4285 const parent_llvm_ty = try o.lowerType(parent_ty);
4243 return o.builder.gepConst(.inbounds, parent_llvm_ty, parent_ptr, null, &.{4286 return o.builder.gepConst(.inbounds, parent_llvm_ty, parent_ptr, null, &.{
4244 try o.builder.intConst(.i32, 0), try o.builder.intConst(.i32, @intFromBool(4287 try o.builder.intConst(.i32, 0),
4245 layout.tag_size > 0 and layout.tag_align >= layout.payload_align,4288 try o.builder.intConst(.i32, @intFromBool(
4289 layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align),
4246 )),4290 )),
4247 });4291 });
4248 },4292 },
4249 .Struct => {4293 .Struct => {
4250 if (parent_ty.containerLayout(mod) == .Packed) {4294 if (mod.typeToPackedStruct(parent_ty)) |struct_type| {
4251 if (!byte_aligned) return parent_ptr;4295 if (!byte_aligned) return parent_ptr;
4252 const llvm_usize = try o.lowerType(Type.usize);4296 const llvm_usize = try o.lowerType(Type.usize);
4253 const base_addr =4297 const base_addr =
4254 try o.builder.castConst(.ptrtoint, parent_ptr, llvm_usize);4298 try o.builder.castConst(.ptrtoint, parent_ptr, llvm_usize);
4255 // count bits of fields before this one4299 // count bits of fields before this one
4300 // TODO https://github.com/ziglang/zig/issues/17178
4256 const prev_bits = b: {4301 const prev_bits = b: {
4257 var b: usize = 0;4302 var b: usize = 0;
4258 for (parent_ty.structFields(mod).values()[0..field_index]) |field| {4303 for (0..field_index) |i| {
4259 if (field.is_comptime) continue;4304 const field_ty = struct_type.field_types.get(ip)[i].toType();
4260 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;4305 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
4261 b += @intCast(field.ty.bitSize(mod));4306 b += @intCast(field_ty.bitSize(mod));
4262 }4307 }
4263 break :b b;4308 break :b b;
4264 };4309 };
...@@ -4407,11 +4452,11 @@ pub const Object = struct {...@@ -4407,11 +4452,11 @@ pub const Object = struct {
4407 if (ptr_info.flags.is_const) {4452 if (ptr_info.flags.is_const) {
4408 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);4453 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
4409 }4454 }
4410 const elem_align = Builder.Alignment.fromByteUnits(4455 const elem_align = if (ptr_info.flags.alignment != .none)
4411 ptr_info.flags.alignment.toByteUnitsOptional() orelse4456 ptr_info.flags.alignment
4412 @max(ptr_info.child.toType().abiAlignment(mod), 1),4457 else
4413 );4458 ptr_info.child.toType().abiAlignment(mod).max(.@"1");
4414 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);4459 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align.toLlvm() }, &o.builder);
4415 } else if (ccAbiPromoteInt(fn_info.cc, mod, param_ty)) |s| switch (s) {4460 } else if (ccAbiPromoteInt(fn_info.cc, mod, param_ty)) |s| switch (s) {
4416 .signed => try attributes.addParamAttr(llvm_arg_i, .signext, &o.builder),4461 .signed => try attributes.addParamAttr(llvm_arg_i, .signext, &o.builder),
4417 .unsigned => try attributes.addParamAttr(llvm_arg_i, .zeroext, &o.builder),4462 .unsigned => try attributes.addParamAttr(llvm_arg_i, .zeroext, &o.builder),
...@@ -4469,7 +4514,7 @@ pub const DeclGen = struct {...@@ -4469,7 +4514,7 @@ pub const DeclGen = struct {
4469 } else {4514 } else {
4470 const variable_index = try o.resolveGlobalDecl(decl_index);4515 const variable_index = try o.resolveGlobalDecl(decl_index);
4471 variable_index.setAlignment(4516 variable_index.setAlignment(
4472 Builder.Alignment.fromByteUnits(decl.getAlignment(mod)),4517 decl.getAlignment(mod).toLlvm(),
4473 &o.builder,4518 &o.builder,
4474 );4519 );
4475 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |section|4520 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |section|
...@@ -4611,9 +4656,7 @@ pub const FuncGen = struct {...@@ -4611,9 +4656,7 @@ pub const FuncGen = struct {
4611 variable_index.setLinkage(.private, &o.builder);4656 variable_index.setLinkage(.private, &o.builder);
4612 variable_index.setMutability(.constant, &o.builder);4657 variable_index.setMutability(.constant, &o.builder);
4613 variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);4658 variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
4614 variable_index.setAlignment(Builder.Alignment.fromByteUnits(4659 variable_index.setAlignment(tv.ty.abiAlignment(mod).toLlvm(), &o.builder);
4615 tv.ty.abiAlignment(mod),
4616 ), &o.builder);
4617 return o.builder.convConst(4660 return o.builder.convConst(
4618 .unneeded,4661 .unneeded,
4619 variable_index.toConst(&o.builder),4662 variable_index.toConst(&o.builder),
...@@ -4929,7 +4972,7 @@ pub const FuncGen = struct {...@@ -4929,7 +4972,7 @@ pub const FuncGen = struct {
4929 const llvm_ret_ty = try o.lowerType(return_type);4972 const llvm_ret_ty = try o.lowerType(return_type);
4930 try attributes.addParamAttr(0, .{ .sret = llvm_ret_ty }, &o.builder);4973 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();
4933 const ret_ptr = try self.buildAlloca(llvm_ret_ty, alignment);4976 const ret_ptr = try self.buildAlloca(llvm_ret_ty, alignment);
4934 try llvm_args.append(ret_ptr);4977 try llvm_args.append(ret_ptr);
4935 break :blk ret_ptr;4978 break :blk ret_ptr;
...@@ -4951,7 +4994,7 @@ pub const FuncGen = struct {...@@ -4951,7 +4994,7 @@ pub const FuncGen = struct {
4951 const llvm_arg = try self.resolveInst(arg);4994 const llvm_arg = try self.resolveInst(arg);
4952 const llvm_param_ty = try o.lowerType(param_ty);4995 const llvm_param_ty = try o.lowerType(param_ty);
4953 if (isByRef(param_ty, mod)) {4996 if (isByRef(param_ty, mod)) {
4954 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));4997 const alignment = param_ty.abiAlignment(mod).toLlvm();
4955 const loaded = try self.wip.load(.normal, llvm_param_ty, llvm_arg, alignment, "");4998 const loaded = try self.wip.load(.normal, llvm_param_ty, llvm_arg, alignment, "");
4956 try llvm_args.append(loaded);4999 try llvm_args.append(loaded);
4957 } else {5000 } else {
...@@ -4965,7 +5008,7 @@ pub const FuncGen = struct {...@@ -4965,7 +5008,7 @@ pub const FuncGen = struct {
4965 if (isByRef(param_ty, mod)) {5008 if (isByRef(param_ty, mod)) {
4966 try llvm_args.append(llvm_arg);5009 try llvm_args.append(llvm_arg);
4967 } else {5010 } else {
4968 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));5011 const alignment = param_ty.abiAlignment(mod).toLlvm();
4969 const param_llvm_ty = llvm_arg.typeOfWip(&self.wip);5012 const param_llvm_ty = llvm_arg.typeOfWip(&self.wip);
4970 const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment);5013 const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment);
4971 _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment);5014 _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment);
...@@ -4977,7 +5020,7 @@ pub const FuncGen = struct {...@@ -4977,7 +5020,7 @@ pub const FuncGen = struct {
4977 const param_ty = self.typeOf(arg);5020 const param_ty = self.typeOf(arg);
4978 const llvm_arg = try self.resolveInst(arg);5021 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();
4981 const param_llvm_ty = try o.lowerType(param_ty);5024 const param_llvm_ty = try o.lowerType(param_ty);
4982 const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment);5025 const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment);
4983 if (isByRef(param_ty, mod)) {5026 if (isByRef(param_ty, mod)) {
...@@ -4995,13 +5038,13 @@ pub const FuncGen = struct {...@@ -4995,13 +5038,13 @@ pub const FuncGen = struct {
4995 const int_llvm_ty = try o.builder.intType(@intCast(param_ty.abiSize(mod) * 8));5038 const int_llvm_ty = try o.builder.intType(@intCast(param_ty.abiSize(mod) * 8));
49965039
4997 if (isByRef(param_ty, mod)) {5040 if (isByRef(param_ty, mod)) {
4998 const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod));5041 const alignment = param_ty.abiAlignment(mod).toLlvm();
4999 const loaded = try self.wip.load(.normal, int_llvm_ty, llvm_arg, alignment, "");5042 const loaded = try self.wip.load(.normal, int_llvm_ty, llvm_arg, alignment, "");
5000 try llvm_args.append(loaded);5043 try llvm_args.append(loaded);
5001 } else {5044 } else {
5002 // LLVM does not allow bitcasting structs so we must allocate5045 // LLVM does not allow bitcasting structs so we must allocate
5003 // a local, store as one type, and then load as another type.5046 // 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();
5005 const int_ptr = try self.buildAlloca(int_llvm_ty, alignment);5048 const int_ptr = try self.buildAlloca(int_llvm_ty, alignment);
5006 _ = try self.wip.store(.normal, llvm_arg, int_ptr, alignment);5049 _ = try self.wip.store(.normal, llvm_arg, int_ptr, alignment);
5007 const loaded = try self.wip.load(.normal, int_llvm_ty, int_ptr, alignment, "");5050 const loaded = try self.wip.load(.normal, int_llvm_ty, int_ptr, alignment, "");
...@@ -5022,7 +5065,7 @@ pub const FuncGen = struct {...@@ -5022,7 +5065,7 @@ pub const FuncGen = struct {
5022 const llvm_arg = try self.resolveInst(arg);5065 const llvm_arg = try self.resolveInst(arg);
5023 const is_by_ref = isByRef(param_ty, mod);5066 const is_by_ref = isByRef(param_ty, mod);
5024 const arg_ptr = if (is_by_ref) llvm_arg else ptr: {5067 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();
5026 const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment);5069 const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment);
5027 _ = try self.wip.store(.normal, llvm_arg, ptr, alignment);5070 _ = try self.wip.store(.normal, llvm_arg, ptr, alignment);
5028 break :ptr ptr;5071 break :ptr ptr;
...@@ -5048,7 +5091,7 @@ pub const FuncGen = struct {...@@ -5048,7 +5091,7 @@ pub const FuncGen = struct {
5048 const arg = args[it.zig_index - 1];5091 const arg = args[it.zig_index - 1];
5049 const arg_ty = self.typeOf(arg);5092 const arg_ty = self.typeOf(arg);
5050 var llvm_arg = try self.resolveInst(arg);5093 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();
5052 if (!isByRef(arg_ty, mod)) {5095 if (!isByRef(arg_ty, mod)) {
5053 const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment);5096 const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment);
5054 _ = try self.wip.store(.normal, llvm_arg, ptr, alignment);5097 _ = try self.wip.store(.normal, llvm_arg, ptr, alignment);
...@@ -5066,7 +5109,7 @@ pub const FuncGen = struct {...@@ -5066,7 +5109,7 @@ pub const FuncGen = struct {
5066 const arg = args[it.zig_index - 1];5109 const arg = args[it.zig_index - 1];
5067 const arg_ty = self.typeOf(arg);5110 const arg_ty = self.typeOf(arg);
5068 var llvm_arg = try self.resolveInst(arg);5111 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();
5070 if (!isByRef(arg_ty, mod)) {5113 if (!isByRef(arg_ty, mod)) {
5071 const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment);5114 const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment);
5072 _ = try self.wip.store(.normal, llvm_arg, ptr, alignment);5115 _ = try self.wip.store(.normal, llvm_arg, ptr, alignment);
...@@ -5097,7 +5140,7 @@ pub const FuncGen = struct {...@@ -5097,7 +5140,7 @@ pub const FuncGen = struct {
5097 const param_index = it.zig_index - 1;5140 const param_index = it.zig_index - 1;
5098 const param_ty = fn_info.param_types.get(ip)[param_index].toType();5141 const param_ty = fn_info.param_types.get(ip)[param_index].toType();
5099 const param_llvm_ty = try o.lowerType(param_ty);5142 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();
5101 try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);5144 try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty);
5102 },5145 },
5103 .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder),5146 .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder),
...@@ -5128,10 +5171,10 @@ pub const FuncGen = struct {...@@ -5128,10 +5171,10 @@ pub const FuncGen = struct {
5128 if (ptr_info.flags.is_const) {5171 if (ptr_info.flags.is_const) {
5129 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);5172 try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
5130 }5173 }
5131 const elem_align = Builder.Alignment.fromByteUnits(5174 const elem_align = (if (ptr_info.flags.alignment != .none)
5132 ptr_info.flags.alignment.toByteUnitsOptional() orelse5175 @as(InternPool.Alignment, ptr_info.flags.alignment)
5133 @max(ptr_info.child.toType().abiAlignment(mod), 1),5176 else
5134 );5177 ptr_info.child.toType().abiAlignment(mod).max(.@"1")).toLlvm();
5135 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);5178 try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
5136 },5179 },
5137 };5180 };
...@@ -5166,7 +5209,7 @@ pub const FuncGen = struct {...@@ -5166,7 +5209,7 @@ pub const FuncGen = struct {
5166 return rp;5209 return rp;
5167 } else {5210 } else {
5168 // our by-ref status disagrees with sret so we must load.5211 // 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();
5170 return self.wip.load(.normal, llvm_ret_ty, rp, return_alignment, "");5213 return self.wip.load(.normal, llvm_ret_ty, rp, return_alignment, "");
5171 }5214 }
5172 }5215 }
...@@ -5177,7 +5220,7 @@ pub const FuncGen = struct {...@@ -5177,7 +5220,7 @@ pub const FuncGen = struct {
5177 // In this case the function return type is honoring the calling convention by having5220 // In this case the function return type is honoring the calling convention by having
5178 // a different LLVM type than the usual one. We solve this here at the callsite5221 // a different LLVM type than the usual one. We solve this here at the callsite
5179 // by using our canonical type, then loading it if necessary.5222 // 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();
5181 if (o.builder.useLibLlvm())5224 if (o.builder.useLibLlvm())
5182 assert(o.target_data.abiSizeOfType(abi_ret_ty.toLlvm(&o.builder)) >=5225 assert(o.target_data.abiSizeOfType(abi_ret_ty.toLlvm(&o.builder)) >=
5183 o.target_data.abiSizeOfType(llvm_ret_ty.toLlvm(&o.builder)));5226 o.target_data.abiSizeOfType(llvm_ret_ty.toLlvm(&o.builder)));
...@@ -5192,7 +5235,7 @@ pub const FuncGen = struct {...@@ -5192,7 +5235,7 @@ pub const FuncGen = struct {
5192 if (isByRef(return_type, mod)) {5235 if (isByRef(return_type, mod)) {
5193 // our by-ref status disagrees with sret so we must allocate, store,5236 // our by-ref status disagrees with sret so we must allocate, store,
5194 // and return the allocation pointer.5237 // and return the allocation pointer.
5195 const alignment = Builder.Alignment.fromByteUnits(return_type.abiAlignment(mod));5238 const alignment = return_type.abiAlignment(mod).toLlvm();
5196 const rp = try self.buildAlloca(llvm_ret_ty, alignment);5239 const rp = try self.buildAlloca(llvm_ret_ty, alignment);
5197 _ = try self.wip.store(.normal, call, rp, alignment);5240 _ = try self.wip.store(.normal, call, rp, alignment);
5198 return rp;5241 return rp;
...@@ -5266,7 +5309,7 @@ pub const FuncGen = struct {...@@ -5266,7 +5309,7 @@ pub const FuncGen = struct {
52665309
5267 const abi_ret_ty = try lowerFnRetTy(o, fn_info);5310 const abi_ret_ty = try lowerFnRetTy(o, fn_info);
5268 const operand = try self.resolveInst(un_op);5311 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
5271 if (isByRef(ret_ty, mod)) {5314 if (isByRef(ret_ty, mod)) {
5272 // operand is a pointer however self.ret_ptr is null so that means5315 // operand is a pointer however self.ret_ptr is null so that means
...@@ -5311,7 +5354,7 @@ pub const FuncGen = struct {...@@ -5311,7 +5354,7 @@ pub const FuncGen = struct {
5311 }5354 }
5312 const ptr = try self.resolveInst(un_op);5355 const ptr = try self.resolveInst(un_op);
5313 const abi_ret_ty = try lowerFnRetTy(o, fn_info);5356 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();
5315 _ = try self.wip.ret(try self.wip.load(.normal, abi_ret_ty, ptr, alignment, ""));5358 _ = try self.wip.ret(try self.wip.load(.normal, abi_ret_ty, ptr, alignment, ""));
5316 return .none;5359 return .none;
5317 }5360 }
...@@ -5334,7 +5377,7 @@ pub const FuncGen = struct {...@@ -5334,7 +5377,7 @@ pub const FuncGen = struct {
5334 const llvm_va_list_ty = try o.lowerType(va_list_ty);5377 const llvm_va_list_ty = try o.lowerType(va_list_ty);
5335 const mod = o.module;5378 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();
5338 const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment);5381 const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment);
53395382
5340 _ = try self.wip.callIntrinsic(.normal, .none, .va_copy, &.{}, &.{ dest_list, src_list }, "");5383 _ = try self.wip.callIntrinsic(.normal, .none, .va_copy, &.{}, &.{ dest_list, src_list }, "");
...@@ -5358,7 +5401,7 @@ pub const FuncGen = struct {...@@ -5358,7 +5401,7 @@ pub const FuncGen = struct {
5358 const va_list_ty = self.typeOfIndex(inst);5401 const va_list_ty = self.typeOfIndex(inst);
5359 const llvm_va_list_ty = try o.lowerType(va_list_ty);5402 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();
5362 const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment);5405 const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment);
53635406
5364 _ = try self.wip.callIntrinsic(.normal, .none, .va_start, &.{}, &.{dest_list}, "");5407 _ = try self.wip.callIntrinsic(.normal, .none, .va_start, &.{}, &.{dest_list}, "");
...@@ -5690,7 +5733,7 @@ pub const FuncGen = struct {...@@ -5690,7 +5733,7 @@ pub const FuncGen = struct {
5690 return fg.wip.gepStruct(err_union_llvm_ty, err_union, offset, "");5733 return fg.wip.gepStruct(err_union_llvm_ty, err_union, offset, "");
5691 } else if (isByRef(err_union_ty, mod)) {5734 } else if (isByRef(err_union_ty, mod)) {
5692 const payload_ptr = try fg.wip.gepStruct(err_union_llvm_ty, err_union, offset, "");5735 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();
5694 if (isByRef(payload_ty, mod)) {5737 if (isByRef(payload_ty, mod)) {
5695 if (can_elide_load)5738 if (can_elide_load)
5696 return payload_ptr;5739 return payload_ptr;
...@@ -5997,7 +6040,7 @@ pub const FuncGen = struct {...@@ -5997,7 +6040,7 @@ pub const FuncGen = struct {
5997 if (self.canElideLoad(body_tail))6040 if (self.canElideLoad(body_tail))
5998 return ptr;6041 return ptr;
59996042
6000 const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));6043 const elem_alignment = elem_ty.abiAlignment(mod).toLlvm();
6001 return self.loadByRef(ptr, elem_ty, elem_alignment, .normal);6044 return self.loadByRef(ptr, elem_ty, elem_alignment, .normal);
6002 }6045 }
60036046
...@@ -6037,7 +6080,7 @@ pub const FuncGen = struct {...@@ -6037,7 +6080,7 @@ pub const FuncGen = struct {
6037 const elem_ptr =6080 const elem_ptr =
6038 try self.wip.gep(.inbounds, array_llvm_ty, array_llvm_val, &indices, "");6081 try self.wip.gep(.inbounds, array_llvm_ty, array_llvm_val, &indices, "");
6039 if (canElideLoad(self, body_tail)) return elem_ptr;6082 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();
6041 return self.loadByRef(elem_ptr, elem_ty, elem_alignment, .normal);6084 return self.loadByRef(elem_ptr, elem_ty, elem_alignment, .normal);
6042 } else {6085 } else {
6043 const elem_llvm_ty = try o.lowerType(elem_ty);6086 const elem_llvm_ty = try o.lowerType(elem_ty);
...@@ -6097,7 +6140,7 @@ pub const FuncGen = struct {...@@ -6097,7 +6140,7 @@ pub const FuncGen = struct {
6097 &.{rhs}, "");6140 &.{rhs}, "");
6098 if (isByRef(elem_ty, mod)) {6141 if (isByRef(elem_ty, mod)) {
6099 if (self.canElideLoad(body_tail)) return ptr;6142 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();
6101 return self.loadByRef(ptr, elem_ty, elem_alignment, .normal);6144 return self.loadByRef(ptr, elem_ty, elem_alignment, .normal);
6102 }6145 }
61036146
...@@ -6111,7 +6154,7 @@ pub const FuncGen = struct {...@@ -6111,7 +6154,7 @@ pub const FuncGen = struct {
6111 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;6154 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
6112 const ptr_ty = self.typeOf(bin_op.lhs);6155 const ptr_ty = self.typeOf(bin_op.lhs);
6113 const elem_ty = ptr_ty.childType(mod);6156 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
6116 const base_ptr = try self.resolveInst(bin_op.lhs);6159 const base_ptr = try self.resolveInst(bin_op.lhs);
6117 const rhs = try self.resolveInst(bin_op.rhs);6160 const rhs = try self.resolveInst(bin_op.rhs);
...@@ -6163,8 +6206,8 @@ pub const FuncGen = struct {...@@ -6163,8 +6206,8 @@ pub const FuncGen = struct {
6163 switch (struct_ty.zigTypeTag(mod)) {6206 switch (struct_ty.zigTypeTag(mod)) {
6164 .Struct => switch (struct_ty.containerLayout(mod)) {6207 .Struct => switch (struct_ty.containerLayout(mod)) {
6165 .Packed => {6208 .Packed => {
6166 const struct_obj = mod.typeToStruct(struct_ty).?;6209 const struct_type = mod.typeToStruct(struct_ty).?;
6167 const bit_offset = struct_obj.packedFieldBitOffset(mod, field_index);6210 const bit_offset = mod.structPackedFieldBitOffset(struct_type, field_index);
6168 const containing_int = struct_llvm_val;6211 const containing_int = struct_llvm_val;
6169 const shift_amt =6212 const shift_amt =
6170 try o.builder.intValue(containing_int.typeOfWip(&self.wip), bit_offset);6213 try o.builder.intValue(containing_int.typeOfWip(&self.wip), bit_offset);
...@@ -6220,16 +6263,14 @@ pub const FuncGen = struct {...@@ -6220,16 +6263,14 @@ pub const FuncGen = struct {
6220 const alignment = struct_ty.structFieldAlign(field_index, mod);6263 const alignment = struct_ty.structFieldAlign(field_index, mod);
6221 const field_ptr_ty = try mod.ptrType(.{6264 const field_ptr_ty = try mod.ptrType(.{
6222 .child = field_ty.toIntern(),6265 .child = field_ty.toIntern(),
6223 .flags = .{6266 .flags = .{ .alignment = alignment },
6224 .alignment = InternPool.Alignment.fromNonzeroByteUnits(alignment),
6225 },
6226 });6267 });
6227 if (isByRef(field_ty, mod)) {6268 if (isByRef(field_ty, mod)) {
6228 if (canElideLoad(self, body_tail))6269 if (canElideLoad(self, body_tail))
6229 return field_ptr;6270 return field_ptr;
62306271
6231 assert(alignment != 0);6272 assert(alignment != .none);
6232 const field_alignment = Builder.Alignment.fromByteUnits(alignment);6273 const field_alignment = alignment.toLlvm();
6233 return self.loadByRef(field_ptr, field_ty, field_alignment, .normal);6274 return self.loadByRef(field_ptr, field_ty, field_alignment, .normal);
6234 } else {6275 } else {
6235 return self.load(field_ptr, field_ptr_ty);6276 return self.load(field_ptr, field_ptr_ty);
...@@ -6238,11 +6279,11 @@ pub const FuncGen = struct {...@@ -6238,11 +6279,11 @@ pub const FuncGen = struct {
6238 .Union => {6279 .Union => {
6239 const union_llvm_ty = try o.lowerType(struct_ty);6280 const union_llvm_ty = try o.lowerType(struct_ty);
6240 const layout = struct_ty.unionGetLayout(mod);6281 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));
6242 const field_ptr =6283 const field_ptr =
6243 try self.wip.gepStruct(union_llvm_ty, struct_llvm_val, payload_index, "");6284 try self.wip.gepStruct(union_llvm_ty, struct_llvm_val, payload_index, "");
6244 const llvm_field_ty = try o.lowerType(field_ty);6285 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();
6246 if (isByRef(field_ty, mod)) {6287 if (isByRef(field_ty, mod)) {
6247 if (canElideLoad(self, body_tail)) return field_ptr;6288 if (canElideLoad(self, body_tail)) return field_ptr;
6248 return self.loadByRef(field_ptr, field_ty, payload_alignment, .normal);6289 return self.loadByRef(field_ptr, field_ty, payload_alignment, .normal);
...@@ -6457,7 +6498,7 @@ pub const FuncGen = struct {...@@ -6457,7 +6498,7 @@ pub const FuncGen = struct {
6457 if (isByRef(operand_ty, mod)) {6498 if (isByRef(operand_ty, mod)) {
6458 _ = dib.insertDeclareAtEnd(operand.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);6499 _ = dib.insertDeclareAtEnd(operand.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
6459 } else if (o.module.comp.bin_file.options.optimize_mode == .Debug) {6500 } 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();
6461 const alloca = try self.buildAlloca(operand.typeOfWip(&self.wip), alignment);6502 const alloca = try self.buildAlloca(operand.typeOfWip(&self.wip), alignment);
6462 _ = try self.wip.store(.normal, operand, alloca, alignment);6503 _ = try self.wip.store(.normal, operand, alloca, alignment);
6463 _ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);6504 _ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
...@@ -6612,7 +6653,7 @@ pub const FuncGen = struct {...@@ -6612,7 +6653,7 @@ pub const FuncGen = struct {
6612 llvm_param_values[llvm_param_i] = arg_llvm_value;6653 llvm_param_values[llvm_param_i] = arg_llvm_value;
6613 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);6654 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
6614 } else {6655 } else {
6615 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));6656 const alignment = arg_ty.abiAlignment(mod).toLlvm();
6616 const arg_llvm_ty = try o.lowerType(arg_ty);6657 const arg_llvm_ty = try o.lowerType(arg_ty);
6617 const load_inst =6658 const load_inst =
6618 try self.wip.load(.normal, arg_llvm_ty, arg_llvm_value, alignment, "");6659 try self.wip.load(.normal, arg_llvm_ty, arg_llvm_value, alignment, "");
...@@ -6624,7 +6665,7 @@ pub const FuncGen = struct {...@@ -6624,7 +6665,7 @@ pub const FuncGen = struct {
6624 llvm_param_values[llvm_param_i] = arg_llvm_value;6665 llvm_param_values[llvm_param_i] = arg_llvm_value;
6625 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);6666 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip);
6626 } else {6667 } else {
6627 const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod));6668 const alignment = arg_ty.abiAlignment(mod).toLlvm();
6628 const arg_ptr = try self.buildAlloca(arg_llvm_value.typeOfWip(&self.wip), alignment);6669 const arg_ptr = try self.buildAlloca(arg_llvm_value.typeOfWip(&self.wip), alignment);
6629 _ = try self.wip.store(.normal, arg_llvm_value, arg_ptr, alignment);6670 _ = try self.wip.store(.normal, arg_llvm_value, arg_ptr, alignment);
6630 llvm_param_values[llvm_param_i] = arg_ptr;6671 llvm_param_values[llvm_param_i] = arg_ptr;
...@@ -6676,7 +6717,7 @@ pub const FuncGen = struct {...@@ -6676,7 +6717,7 @@ pub const FuncGen = struct {
6676 llvm_param_values[llvm_param_i] = llvm_rw_val;6717 llvm_param_values[llvm_param_i] = llvm_rw_val;
6677 llvm_param_types[llvm_param_i] = llvm_rw_val.typeOfWip(&self.wip);6718 llvm_param_types[llvm_param_i] = llvm_rw_val.typeOfWip(&self.wip);
6678 } else {6719 } else {
6679 const alignment = Builder.Alignment.fromByteUnits(rw_ty.abiAlignment(mod));6720 const alignment = rw_ty.abiAlignment(mod).toLlvm();
6680 const loaded = try self.wip.load(.normal, llvm_elem_ty, llvm_rw_val, alignment, "");6721 const loaded = try self.wip.load(.normal, llvm_elem_ty, llvm_rw_val, alignment, "");
6681 llvm_param_values[llvm_param_i] = loaded;6722 llvm_param_values[llvm_param_i] = loaded;
6682 llvm_param_types[llvm_param_i] = llvm_elem_ty;6723 llvm_param_types[llvm_param_i] = llvm_elem_ty;
...@@ -6837,7 +6878,7 @@ pub const FuncGen = struct {...@@ -6837,7 +6878,7 @@ pub const FuncGen = struct {
6837 const output_ptr = try self.resolveInst(output);6878 const output_ptr = try self.resolveInst(output);
6838 const output_ptr_ty = self.typeOf(output);6879 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();
6841 _ = try self.wip.store(.normal, output_value, output_ptr, alignment);6882 _ = try self.wip.store(.normal, output_value, output_ptr, alignment);
6842 } else {6883 } else {
6843 ret_val = output_value;6884 ret_val = output_value;
...@@ -7030,7 +7071,7 @@ pub const FuncGen = struct {...@@ -7030,7 +7071,7 @@ pub const FuncGen = struct {
7030 if (operand_is_ptr) {7071 if (operand_is_ptr) {
7031 return self.wip.gepStruct(err_union_llvm_ty, operand, offset, "");7072 return self.wip.gepStruct(err_union_llvm_ty, operand, offset, "");
7032 } else if (isByRef(err_union_ty, mod)) {7073 } 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();
7034 const payload_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, offset, "");7075 const payload_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, offset, "");
7035 if (isByRef(payload_ty, mod)) {7076 if (isByRef(payload_ty, mod)) {
7036 if (self.canElideLoad(body_tail)) return payload_ptr;7077 if (self.canElideLoad(body_tail)) return payload_ptr;
...@@ -7093,7 +7134,7 @@ pub const FuncGen = struct {...@@ -7093,7 +7134,7 @@ pub const FuncGen = struct {
7093 }7134 }
7094 const err_union_llvm_ty = try o.lowerType(err_union_ty);7135 const err_union_llvm_ty = try o.lowerType(err_union_ty);
7095 {7136 {
7096 const error_alignment = Builder.Alignment.fromByteUnits(Type.err_int.abiAlignment(mod));7137 const error_alignment = Type.err_int.abiAlignment(mod).toLlvm();
7097 const error_offset = errUnionErrorOffset(payload_ty, mod);7138 const error_offset = errUnionErrorOffset(payload_ty, mod);
7098 // First set the non-error value.7139 // First set the non-error value.
7099 const non_null_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, error_offset, "");7140 const non_null_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, error_offset, "");
...@@ -7133,9 +7174,7 @@ pub const FuncGen = struct {...@@ -7133,9 +7174,7 @@ pub const FuncGen = struct {
7133 const field_ty = struct_ty.structFieldType(field_index, mod);7174 const field_ty = struct_ty.structFieldType(field_index, mod);
7134 const field_ptr_ty = try mod.ptrType(.{7175 const field_ptr_ty = try mod.ptrType(.{
7135 .child = field_ty.toIntern(),7176 .child = field_ty.toIntern(),
7136 .flags = .{7177 .flags = .{ .alignment = field_alignment },
7137 .alignment = InternPool.Alignment.fromNonzeroByteUnits(field_alignment),
7138 },
7139 });7178 });
7140 return self.load(field_ptr, field_ptr_ty);7179 return self.load(field_ptr, field_ptr_ty);
7141 }7180 }
...@@ -7153,7 +7192,7 @@ pub const FuncGen = struct {...@@ -7153,7 +7192,7 @@ pub const FuncGen = struct {
7153 if (optional_ty.optionalReprIsPayload(mod)) return operand;7192 if (optional_ty.optionalReprIsPayload(mod)) return operand;
7154 const llvm_optional_ty = try o.lowerType(optional_ty);7193 const llvm_optional_ty = try o.lowerType(optional_ty);
7155 if (isByRef(optional_ty, mod)) {7194 if (isByRef(optional_ty, mod)) {
7156 const alignment = Builder.Alignment.fromByteUnits(optional_ty.abiAlignment(mod));7195 const alignment = optional_ty.abiAlignment(mod).toLlvm();
7157 const optional_ptr = try self.buildAlloca(llvm_optional_ty, alignment);7196 const optional_ptr = try self.buildAlloca(llvm_optional_ty, alignment);
7158 const payload_ptr = try self.wip.gepStruct(llvm_optional_ty, optional_ptr, 0, "");7197 const payload_ptr = try self.wip.gepStruct(llvm_optional_ty, optional_ptr, 0, "");
7159 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);7198 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);
...@@ -7181,10 +7220,10 @@ pub const FuncGen = struct {...@@ -7181,10 +7220,10 @@ pub const FuncGen = struct {
7181 const payload_offset = errUnionPayloadOffset(payload_ty, mod);7220 const payload_offset = errUnionPayloadOffset(payload_ty, mod);
7182 const error_offset = errUnionErrorOffset(payload_ty, mod);7221 const error_offset = errUnionErrorOffset(payload_ty, mod);
7183 if (isByRef(err_un_ty, mod)) {7222 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();
7185 const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment);7224 const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment);
7186 const err_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, error_offset, "");7225 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();
7188 _ = try self.wip.store(.normal, ok_err_code, err_ptr, error_alignment);7227 _ = try self.wip.store(.normal, ok_err_code, err_ptr, error_alignment);
7189 const payload_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, payload_offset, "");7228 const payload_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, payload_offset, "");
7190 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);7229 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);
...@@ -7210,10 +7249,10 @@ pub const FuncGen = struct {...@@ -7210,10 +7249,10 @@ pub const FuncGen = struct {
7210 const payload_offset = errUnionPayloadOffset(payload_ty, mod);7249 const payload_offset = errUnionPayloadOffset(payload_ty, mod);
7211 const error_offset = errUnionErrorOffset(payload_ty, mod);7250 const error_offset = errUnionErrorOffset(payload_ty, mod);
7212 if (isByRef(err_un_ty, mod)) {7251 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();
7214 const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment);7253 const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment);
7215 const err_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, error_offset, "");7254 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();
7217 _ = try self.wip.store(.normal, operand, err_ptr, error_alignment);7256 _ = try self.wip.store(.normal, operand, err_ptr, error_alignment);
7218 const payload_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, payload_offset, "");7257 const payload_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, payload_offset, "");
7219 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);7258 const payload_ptr_ty = try mod.singleMutPtrType(payload_ty);
...@@ -7260,7 +7299,7 @@ pub const FuncGen = struct {...@@ -7260,7 +7299,7 @@ pub const FuncGen = struct {
7260 const access_kind: Builder.MemoryAccessKind =7299 const access_kind: Builder.MemoryAccessKind =
7261 if (vector_ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal;7300 if (vector_ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal;
7262 const elem_llvm_ty = try o.lowerType(vector_ptr_ty.childType(mod));7301 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();
7264 const loaded = try self.wip.load(access_kind, elem_llvm_ty, vector_ptr, alignment, "");7303 const loaded = try self.wip.load(access_kind, elem_llvm_ty, vector_ptr, alignment, "");
72657304
7266 const new_vector = try self.wip.insertElement(loaded, operand, index, "");7305 const new_vector = try self.wip.insertElement(loaded, operand, index, "");
...@@ -7690,7 +7729,7 @@ pub const FuncGen = struct {...@@ -7690,7 +7729,7 @@ pub const FuncGen = struct {
7690 const overflow_index = o.llvmFieldIndex(inst_ty, 1).?;7729 const overflow_index = o.llvmFieldIndex(inst_ty, 1).?;
76917730
7692 if (isByRef(inst_ty, mod)) {7731 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();
7694 const alloca_inst = try self.buildAlloca(llvm_inst_ty, result_alignment);7733 const alloca_inst = try self.buildAlloca(llvm_inst_ty, result_alignment);
7695 {7734 {
7696 const field_ptr = try self.wip.gepStruct(llvm_inst_ty, alloca_inst, result_index, "");7735 const field_ptr = try self.wip.gepStruct(llvm_inst_ty, alloca_inst, result_index, "");
...@@ -8048,7 +8087,7 @@ pub const FuncGen = struct {...@@ -8048,7 +8087,7 @@ pub const FuncGen = struct {
8048 const overflow_index = o.llvmFieldIndex(dest_ty, 1).?;8087 const overflow_index = o.llvmFieldIndex(dest_ty, 1).?;
80498088
8050 if (isByRef(dest_ty, mod)) {8089 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();
8052 const alloca_inst = try self.buildAlloca(llvm_dest_ty, result_alignment);8091 const alloca_inst = try self.buildAlloca(llvm_dest_ty, result_alignment);
8053 {8092 {
8054 const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, result_index, "");8093 const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, result_index, "");
...@@ -8321,7 +8360,7 @@ pub const FuncGen = struct {...@@ -8321,7 +8360,7 @@ pub const FuncGen = struct {
8321 const array_ptr = try self.buildAlloca(llvm_dest_ty, .default);8360 const array_ptr = try self.buildAlloca(llvm_dest_ty, .default);
8322 const bitcast_ok = elem_ty.bitSize(mod) == elem_ty.abiSize(mod) * 8;8361 const bitcast_ok = elem_ty.bitSize(mod) == elem_ty.abiSize(mod) * 8;
8323 if (bitcast_ok) {8362 if (bitcast_ok) {
8324 const alignment = Builder.Alignment.fromByteUnits(inst_ty.abiAlignment(mod));8363 const alignment = inst_ty.abiAlignment(mod).toLlvm();
8325 _ = try self.wip.store(.normal, operand, array_ptr, alignment);8364 _ = try self.wip.store(.normal, operand, array_ptr, alignment);
8326 } else {8365 } else {
8327 // If the ABI size of the element type is not evenly divisible by size in bits;8366 // If the ABI size of the element type is not evenly divisible by size in bits;
...@@ -8349,7 +8388,7 @@ pub const FuncGen = struct {...@@ -8349,7 +8388,7 @@ pub const FuncGen = struct {
8349 if (bitcast_ok) {8388 if (bitcast_ok) {
8350 // The array is aligned to the element's alignment, while the vector might have a completely8389 // The array is aligned to the element's alignment, while the vector might have a completely
8351 // different alignment. This means we need to enforce the alignment of this load.8390 // 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();
8353 return self.wip.load(.normal, llvm_vector_ty, operand, alignment, "");8392 return self.wip.load(.normal, llvm_vector_ty, operand, alignment, "");
8354 } else {8393 } else {
8355 // If the ABI size of the element type is not evenly divisible by size in bits;8394 // If the ABI size of the element type is not evenly divisible by size in bits;
...@@ -8374,14 +8413,12 @@ pub const FuncGen = struct {...@@ -8374,14 +8413,12 @@ pub const FuncGen = struct {
8374 }8413 }
83758414
8376 if (operand_is_ref) {8415 if (operand_is_ref) {
8377 const alignment = Builder.Alignment.fromByteUnits(operand_ty.abiAlignment(mod));8416 const alignment = operand_ty.abiAlignment(mod).toLlvm();
8378 return self.wip.load(.normal, llvm_dest_ty, operand, alignment, "");8417 return self.wip.load(.normal, llvm_dest_ty, operand, alignment, "");
8379 }8418 }
83808419
8381 if (result_is_ref) {8420 if (result_is_ref) {
8382 const alignment = Builder.Alignment.fromByteUnits(8421 const alignment = operand_ty.abiAlignment(mod).max(inst_ty.abiAlignment(mod)).toLlvm();
8383 @max(operand_ty.abiAlignment(mod), inst_ty.abiAlignment(mod)),
8384 );
8385 const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment);8422 const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment);
8386 _ = try self.wip.store(.normal, operand, result_ptr, alignment);8423 _ = try self.wip.store(.normal, operand, result_ptr, alignment);
8387 return result_ptr;8424 return result_ptr;
...@@ -8393,9 +8430,7 @@ pub const FuncGen = struct {...@@ -8393,9 +8430,7 @@ pub const FuncGen = struct {
8393 // Both our operand and our result are values, not pointers,8430 // Both our operand and our result are values, not pointers,
8394 // but LLVM won't let us bitcast struct values or vectors with padding bits.8431 // but LLVM won't let us bitcast struct values or vectors with padding bits.
8395 // Therefore, we store operand to alloca, then load for result.8432 // Therefore, we store operand to alloca, then load for result.
8396 const alignment = Builder.Alignment.fromByteUnits(8433 const alignment = operand_ty.abiAlignment(mod).max(inst_ty.abiAlignment(mod)).toLlvm();
8397 @max(operand_ty.abiAlignment(mod), inst_ty.abiAlignment(mod)),
8398 );
8399 const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment);8434 const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment);
8400 _ = try self.wip.store(.normal, operand, result_ptr, alignment);8435 _ = try self.wip.store(.normal, operand, result_ptr, alignment);
8401 return self.wip.load(.normal, llvm_dest_ty, result_ptr, alignment, "");8436 return self.wip.load(.normal, llvm_dest_ty, result_ptr, alignment, "");
...@@ -8441,7 +8476,7 @@ pub const FuncGen = struct {...@@ -8441,7 +8476,7 @@ pub const FuncGen = struct {
8441 if (isByRef(inst_ty, mod)) {8476 if (isByRef(inst_ty, mod)) {
8442 _ = dib.insertDeclareAtEnd(arg_val.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);8477 _ = dib.insertDeclareAtEnd(arg_val.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
8443 } else if (o.module.comp.bin_file.options.optimize_mode == .Debug) {8478 } 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();
8445 const alloca = try self.buildAlloca(arg_val.typeOfWip(&self.wip), alignment);8480 const alloca = try self.buildAlloca(arg_val.typeOfWip(&self.wip), alignment);
8446 _ = try self.wip.store(.normal, arg_val, alloca, alignment);8481 _ = try self.wip.store(.normal, arg_val, alloca, alignment);
8447 _ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);8482 _ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
...@@ -8462,7 +8497,7 @@ pub const FuncGen = struct {...@@ -8462,7 +8497,7 @@ pub const FuncGen = struct {
8462 return (try o.lowerPtrToVoid(ptr_ty)).toValue();8497 return (try o.lowerPtrToVoid(ptr_ty)).toValue();
84638498
8464 const pointee_llvm_ty = try o.lowerType(pointee_type);8499 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();
8466 return self.buildAlloca(pointee_llvm_ty, alignment);8501 return self.buildAlloca(pointee_llvm_ty, alignment);
8467 }8502 }
84688503
...@@ -8475,7 +8510,7 @@ pub const FuncGen = struct {...@@ -8475,7 +8510,7 @@ pub const FuncGen = struct {
8475 return (try o.lowerPtrToVoid(ptr_ty)).toValue();8510 return (try o.lowerPtrToVoid(ptr_ty)).toValue();
8476 if (self.ret_ptr != .none) return self.ret_ptr;8511 if (self.ret_ptr != .none) return self.ret_ptr;
8477 const ret_llvm_ty = try o.lowerType(ret_ty);8512 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();
8479 return self.buildAlloca(ret_llvm_ty, alignment);8514 return self.buildAlloca(ret_llvm_ty, alignment);
8480 }8515 }
84818516
...@@ -8515,7 +8550,7 @@ pub const FuncGen = struct {...@@ -8515,7 +8550,7 @@ pub const FuncGen = struct {
8515 const len = try o.builder.intValue(try o.lowerType(Type.usize), operand_ty.abiSize(mod));8550 const len = try o.builder.intValue(try o.lowerType(Type.usize), operand_ty.abiSize(mod));
8516 _ = try self.wip.callMemSet(8551 _ = try self.wip.callMemSet(
8517 dest_ptr,8552 dest_ptr,
8518 Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod)),8553 ptr_ty.ptrAlignment(mod).toLlvm(),
8519 if (safety) try o.builder.intValue(.i8, 0xaa) else try o.builder.undefValue(.i8),8554 if (safety) try o.builder.intValue(.i8, 0xaa) else try o.builder.undefValue(.i8),
8520 len,8555 len,
8521 if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal,8556 if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal,
...@@ -8646,7 +8681,7 @@ pub const FuncGen = struct {...@@ -8646,7 +8681,7 @@ pub const FuncGen = struct {
8646 self.sync_scope,8681 self.sync_scope,
8647 toLlvmAtomicOrdering(extra.successOrder()),8682 toLlvmAtomicOrdering(extra.successOrder()),
8648 toLlvmAtomicOrdering(extra.failureOrder()),8683 toLlvmAtomicOrdering(extra.failureOrder()),
8649 Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod)),8684 ptr_ty.ptrAlignment(mod).toLlvm(),
8650 "",8685 "",
8651 );8686 );
86528687
...@@ -8685,7 +8720,7 @@ pub const FuncGen = struct {...@@ -8685,7 +8720,7 @@ pub const FuncGen = struct {
86858720
8686 const access_kind: Builder.MemoryAccessKind =8721 const access_kind: Builder.MemoryAccessKind =
8687 if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal;8722 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
8690 if (llvm_abi_ty != .none) {8725 if (llvm_abi_ty != .none) {
8691 // operand needs widening and truncating or bitcasting.8726 // operand needs widening and truncating or bitcasting.
...@@ -8741,9 +8776,10 @@ pub const FuncGen = struct {...@@ -8741,9 +8776,10 @@ pub const FuncGen = struct {
8741 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none;8776 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none;
8742 const ordering = toLlvmAtomicOrdering(atomic_load.order);8777 const ordering = toLlvmAtomicOrdering(atomic_load.order);
8743 const llvm_abi_ty = try o.getAtomicAbiType(elem_ty, false);8778 const llvm_abi_ty = try o.getAtomicAbiType(elem_ty, false);
8744 const ptr_alignment = Builder.Alignment.fromByteUnits(8779 const ptr_alignment = (if (info.flags.alignment != .none)
8745 info.flags.alignment.toByteUnitsOptional() orelse info.child.toType().abiAlignment(mod),8780 @as(InternPool.Alignment, info.flags.alignment)
8746 );8781 else
8782 info.child.toType().abiAlignment(mod)).toLlvm();
8747 const access_kind: Builder.MemoryAccessKind =8783 const access_kind: Builder.MemoryAccessKind =
8748 if (info.flags.is_volatile) .@"volatile" else .normal;8784 if (info.flags.is_volatile) .@"volatile" else .normal;
8749 const elem_llvm_ty = try o.lowerType(elem_ty);8785 const elem_llvm_ty = try o.lowerType(elem_ty);
...@@ -8807,7 +8843,7 @@ pub const FuncGen = struct {...@@ -8807,7 +8843,7 @@ pub const FuncGen = struct {
8807 const dest_slice = try self.resolveInst(bin_op.lhs);8843 const dest_slice = try self.resolveInst(bin_op.lhs);
8808 const ptr_ty = self.typeOf(bin_op.lhs);8844 const ptr_ty = self.typeOf(bin_op.lhs);
8809 const elem_ty = self.typeOf(bin_op.rhs);8845 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();
8811 const dest_ptr = try self.sliceOrArrayPtr(dest_slice, ptr_ty);8847 const dest_ptr = try self.sliceOrArrayPtr(dest_slice, ptr_ty);
8812 const access_kind: Builder.MemoryAccessKind =8848 const access_kind: Builder.MemoryAccessKind =
8813 if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal;8849 if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal;
...@@ -8911,15 +8947,13 @@ pub const FuncGen = struct {...@@ -8911,15 +8947,13 @@ pub const FuncGen = struct {
89118947
8912 self.wip.cursor = .{ .block = body_block };8948 self.wip.cursor = .{ .block = body_block };
8913 const elem_abi_align = elem_ty.abiAlignment(mod);8949 const elem_abi_align = elem_ty.abiAlignment(mod);
8914 const it_ptr_align = Builder.Alignment.fromByteUnits(8950 const it_ptr_align = InternPool.Alignment.fromLlvm(dest_ptr_align).min(elem_abi_align).toLlvm();
8915 @min(elem_abi_align, dest_ptr_align.toByteUnits() orelse std.math.maxInt(u64)),
8916 );
8917 if (isByRef(elem_ty, mod)) {8951 if (isByRef(elem_ty, mod)) {
8918 _ = try self.wip.callMemCpy(8952 _ = try self.wip.callMemCpy(
8919 it_ptr.toValue(),8953 it_ptr.toValue(),
8920 it_ptr_align,8954 it_ptr_align,
8921 value,8955 value,
8922 Builder.Alignment.fromByteUnits(elem_abi_align),8956 elem_abi_align.toLlvm(),
8923 try o.builder.intValue(llvm_usize_ty, elem_abi_size),8957 try o.builder.intValue(llvm_usize_ty, elem_abi_size),
8924 access_kind,8958 access_kind,
8925 );8959 );
...@@ -8985,9 +9019,9 @@ pub const FuncGen = struct {...@@ -8985,9 +9019,9 @@ pub const FuncGen = struct {
8985 self.wip.cursor = .{ .block = memcpy_block };9019 self.wip.cursor = .{ .block = memcpy_block };
8986 _ = try self.wip.callMemCpy(9020 _ = try self.wip.callMemCpy(
8987 dest_ptr,9021 dest_ptr,
8988 Builder.Alignment.fromByteUnits(dest_ptr_ty.ptrAlignment(mod)),9022 dest_ptr_ty.ptrAlignment(mod).toLlvm(),
8989 src_ptr,9023 src_ptr,
8990 Builder.Alignment.fromByteUnits(src_ptr_ty.ptrAlignment(mod)),9024 src_ptr_ty.ptrAlignment(mod).toLlvm(),
8991 len,9025 len,
8992 access_kind,9026 access_kind,
8993 );9027 );
...@@ -8998,9 +9032,9 @@ pub const FuncGen = struct {...@@ -8998,9 +9032,9 @@ pub const FuncGen = struct {
89989032
8999 _ = try self.wip.callMemCpy(9033 _ = try self.wip.callMemCpy(
9000 dest_ptr,9034 dest_ptr,
9001 Builder.Alignment.fromByteUnits(dest_ptr_ty.ptrAlignment(mod)),9035 dest_ptr_ty.ptrAlignment(mod).toLlvm(),
9002 src_ptr,9036 src_ptr,
9003 Builder.Alignment.fromByteUnits(src_ptr_ty.ptrAlignment(mod)),9037 src_ptr_ty.ptrAlignment(mod).toLlvm(),
9004 len,9038 len,
9005 access_kind,9039 access_kind,
9006 );9040 );
...@@ -9021,7 +9055,7 @@ pub const FuncGen = struct {...@@ -9021,7 +9055,7 @@ pub const FuncGen = struct {
9021 _ = try self.wip.store(.normal, new_tag, union_ptr, .default);9055 _ = try self.wip.store(.normal, new_tag, union_ptr, .default);
9022 return .none;9056 return .none;
9023 }9057 }
9024 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);9058 const tag_index = @intFromBool(layout.tag_align.compare(.lt, layout.payload_align));
9025 const tag_field_ptr = try self.wip.gepStruct(try o.lowerType(un_ty), union_ptr, tag_index, "");9059 const tag_field_ptr = try self.wip.gepStruct(try o.lowerType(un_ty), union_ptr, tag_index, "");
9026 // TODO alignment on this store9060 // TODO alignment on this store
9027 _ = try self.wip.store(.normal, new_tag, tag_field_ptr, .default);9061 _ = try self.wip.store(.normal, new_tag, tag_field_ptr, .default);
...@@ -9040,13 +9074,13 @@ pub const FuncGen = struct {...@@ -9040,13 +9074,13 @@ pub const FuncGen = struct {
9040 const llvm_un_ty = try o.lowerType(un_ty);9074 const llvm_un_ty = try o.lowerType(un_ty);
9041 if (layout.payload_size == 0)9075 if (layout.payload_size == 0)
9042 return self.wip.load(.normal, llvm_un_ty, union_handle, .default, "");9076 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));
9044 const tag_field_ptr = try self.wip.gepStruct(llvm_un_ty, union_handle, tag_index, "");9078 const tag_field_ptr = try self.wip.gepStruct(llvm_un_ty, union_handle, tag_index, "");
9045 const llvm_tag_ty = llvm_un_ty.structFields(&o.builder)[tag_index];9079 const llvm_tag_ty = llvm_un_ty.structFields(&o.builder)[tag_index];
9046 return self.wip.load(.normal, llvm_tag_ty, tag_field_ptr, .default, "");9080 return self.wip.load(.normal, llvm_tag_ty, tag_field_ptr, .default, "");
9047 } else {9081 } else {
9048 if (layout.payload_size == 0) return union_handle;9082 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));
9050 return self.wip.extractValue(union_handle, &.{tag_index}, "");9084 return self.wip.extractValue(union_handle, &.{tag_index}, "");
9051 }9085 }
9052 }9086 }
...@@ -9605,6 +9639,7 @@ pub const FuncGen = struct {...@@ -9605,6 +9639,7 @@ pub const FuncGen = struct {
9605 fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {9639 fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9606 const o = self.dg.object;9640 const o = self.dg.object;
9607 const mod = o.module;9641 const mod = o.module;
9642 const ip = &mod.intern_pool;
9608 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;9643 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
9609 const result_ty = self.typeOfIndex(inst);9644 const result_ty = self.typeOfIndex(inst);
9610 const len: usize = @intCast(result_ty.arrayLen(mod));9645 const len: usize = @intCast(result_ty.arrayLen(mod));
...@@ -9622,23 +9657,21 @@ pub const FuncGen = struct {...@@ -9622,23 +9657,21 @@ pub const FuncGen = struct {
9622 return vector;9657 return vector;
9623 },9658 },
9624 .Struct => {9659 .Struct => {
9625 if (result_ty.containerLayout(mod) == .Packed) {9660 if (mod.typeToPackedStruct(result_ty)) |struct_type| {
9626 const struct_obj = mod.typeToStruct(result_ty).?;9661 const backing_int_ty = struct_type.backingIntType(ip).*;
9627 assert(struct_obj.haveLayout());9662 assert(backing_int_ty != .none);
9628 const big_bits = struct_obj.backing_int_ty.bitSize(mod);9663 const big_bits = backing_int_ty.toType().bitSize(mod);
9629 const int_ty = try o.builder.intType(@intCast(big_bits));9664 const int_ty = try o.builder.intType(@intCast(big_bits));
9630 const fields = struct_obj.fields.values();
9631 comptime assert(Type.packed_struct_layout_version == 2);9665 comptime assert(Type.packed_struct_layout_version == 2);
9632 var running_int = try o.builder.intValue(int_ty, 0);9666 var running_int = try o.builder.intValue(int_ty, 0);
9633 var running_bits: u16 = 0;9667 var running_bits: u16 = 0;
9634 for (elements, 0..) |elem, i| {9668 for (elements, struct_type.field_types.get(ip)) |elem, field_ty| {
9635 const field = fields[i];9669 if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
9636 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
96379670
9638 const non_int_val = try self.resolveInst(elem);9671 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));
9640 const small_int_ty = try o.builder.intType(ty_bit_size);9673 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))
9642 try self.wip.cast(.ptrtoint, non_int_val, small_int_ty, "")9675 try self.wip.cast(.ptrtoint, non_int_val, small_int_ty, "")
9643 else9676 else
9644 try self.wip.cast(.bitcast, non_int_val, small_int_ty, "");9677 try self.wip.cast(.bitcast, non_int_val, small_int_ty, "");
...@@ -9652,10 +9685,12 @@ pub const FuncGen = struct {...@@ -9652,10 +9685,12 @@ pub const FuncGen = struct {
9652 return running_int;9685 return running_int;
9653 }9686 }
96549687
9688 assert(result_ty.containerLayout(mod) != .Packed);
9689
9655 if (isByRef(result_ty, mod)) {9690 if (isByRef(result_ty, mod)) {
9656 // TODO in debug builds init to undef so that the padding will be 0xaa9691 // TODO in debug builds init to undef so that the padding will be 0xaa
9657 // even if we fully populate the fields.9692 // 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();
9659 const alloca_inst = try self.buildAlloca(llvm_result_ty, alignment);9694 const alloca_inst = try self.buildAlloca(llvm_result_ty, alignment);
96609695
9661 for (elements, 0..) |elem, i| {9696 for (elements, 0..) |elem, i| {
...@@ -9668,9 +9703,7 @@ pub const FuncGen = struct {...@@ -9668,9 +9703,7 @@ pub const FuncGen = struct {
9668 const field_ptr_ty = try mod.ptrType(.{9703 const field_ptr_ty = try mod.ptrType(.{
9669 .child = self.typeOf(elem).toIntern(),9704 .child = self.typeOf(elem).toIntern(),
9670 .flags = .{9705 .flags = .{
9671 .alignment = InternPool.Alignment.fromNonzeroByteUnits(9706 .alignment = result_ty.structFieldAlign(i, mod),
9672 result_ty.structFieldAlign(i, mod),
9673 ),
9674 },9707 },
9675 });9708 });
9676 try self.store(field_ptr, field_ptr_ty, llvm_elem, .none);9709 try self.store(field_ptr, field_ptr_ty, llvm_elem, .none);
...@@ -9694,7 +9727,7 @@ pub const FuncGen = struct {...@@ -9694,7 +9727,7 @@ pub const FuncGen = struct {
96949727
9695 const llvm_usize = try o.lowerType(Type.usize);9728 const llvm_usize = try o.lowerType(Type.usize);
9696 const usize_zero = try o.builder.intValue(llvm_usize, 0);9729 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();
9698 const alloca_inst = try self.buildAlloca(llvm_result_ty, alignment);9731 const alloca_inst = try self.buildAlloca(llvm_result_ty, alignment);
96999732
9700 const array_info = result_ty.arrayInfo(mod);9733 const array_info = result_ty.arrayInfo(mod);
...@@ -9770,7 +9803,7 @@ pub const FuncGen = struct {...@@ -9770,7 +9803,7 @@ pub const FuncGen = struct {
9770 // necessarily match the format that we need, depending on which tag is active.9803 // necessarily match the format that we need, depending on which tag is active.
9771 // We must construct the correct unnamed struct type here, in order to then set9804 // We must construct the correct unnamed struct type here, in order to then set
9772 // the fields appropriately.9805 // the fields appropriately.
9773 const alignment = Builder.Alignment.fromByteUnits(layout.abi_align);9806 const alignment = layout.abi_align.toLlvm();
9774 const result_ptr = try self.buildAlloca(union_llvm_ty, alignment);9807 const result_ptr = try self.buildAlloca(union_llvm_ty, alignment);
9775 const llvm_payload = try self.resolveInst(extra.init);9808 const llvm_payload = try self.resolveInst(extra.init);
9776 const field_ty = union_obj.field_types.get(ip)[extra.field_index].toType();9809 const field_ty = union_obj.field_types.get(ip)[extra.field_index].toType();
...@@ -9799,7 +9832,7 @@ pub const FuncGen = struct {...@@ -9799,7 +9832,7 @@ pub const FuncGen = struct {
9799 const tag_ty = try o.lowerType(union_obj.enum_tag_ty.toType());9832 const tag_ty = try o.lowerType(union_obj.enum_tag_ty.toType());
9800 var fields: [3]Builder.Type = undefined;9833 var fields: [3]Builder.Type = undefined;
9801 var fields_len: usize = 2;9834 var fields_len: usize = 2;
9802 if (layout.tag_align >= layout.payload_align) {9835 if (layout.tag_align.compare(.gte, layout.payload_align)) {
9803 fields = .{ tag_ty, payload_ty, undefined };9836 fields = .{ tag_ty, payload_ty, undefined };
9804 } else {9837 } else {
9805 fields = .{ payload_ty, tag_ty, undefined };9838 fields = .{ payload_ty, tag_ty, undefined };
...@@ -9815,7 +9848,7 @@ pub const FuncGen = struct {...@@ -9815,7 +9848,7 @@ pub const FuncGen = struct {
9815 // tag and the payload.9848 // tag and the payload.
9816 const field_ptr_ty = try mod.ptrType(.{9849 const field_ptr_ty = try mod.ptrType(.{
9817 .child = field_ty.toIntern(),9850 .child = field_ty.toIntern(),
9818 .flags = .{ .alignment = InternPool.Alignment.fromNonzeroByteUnits(field_align) },9851 .flags = .{ .alignment = field_align },
9819 });9852 });
9820 if (layout.tag_size == 0) {9853 if (layout.tag_size == 0) {
9821 const indices = [3]Builder.Value{ usize_zero, i32_zero, i32_zero };9854 const indices = [3]Builder.Value{ usize_zero, i32_zero, i32_zero };
...@@ -9827,7 +9860,7 @@ pub const FuncGen = struct {...@@ -9827,7 +9860,7 @@ pub const FuncGen = struct {
9827 }9860 }
98289861
9829 {9862 {
9830 const payload_index = @intFromBool(layout.tag_align >= layout.payload_align);9863 const payload_index = @intFromBool(layout.tag_align.compare(.gte, layout.payload_align));
9831 const indices: [3]Builder.Value =9864 const indices: [3]Builder.Value =
9832 .{ usize_zero, try o.builder.intValue(.i32, payload_index), i32_zero };9865 .{ usize_zero, try o.builder.intValue(.i32, payload_index), i32_zero };
9833 const len: usize = if (field_size == layout.payload_size) 2 else 3;9866 const len: usize = if (field_size == layout.payload_size) 2 else 3;
...@@ -9836,12 +9869,12 @@ pub const FuncGen = struct {...@@ -9836,12 +9869,12 @@ pub const FuncGen = struct {
9836 try self.store(field_ptr, field_ptr_ty, llvm_payload, .none);9869 try self.store(field_ptr, field_ptr_ty, llvm_payload, .none);
9837 }9870 }
9838 {9871 {
9839 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);9872 const tag_index = @intFromBool(layout.tag_align.compare(.lt, layout.payload_align));
9840 const indices: [2]Builder.Value = .{ usize_zero, try o.builder.intValue(.i32, tag_index) };9873 const indices: [2]Builder.Value = .{ usize_zero, try o.builder.intValue(.i32, tag_index) };
9841 const field_ptr = try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, &indices, "");9874 const field_ptr = try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, &indices, "");
9842 const tag_ty = try o.lowerType(union_obj.enum_tag_ty.toType());9875 const tag_ty = try o.lowerType(union_obj.enum_tag_ty.toType());
9843 const llvm_tag = try o.builder.intValue(tag_ty, tag_int);9876 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();
9845 _ = try self.wip.store(.normal, llvm_tag, field_ptr, tag_alignment);9878 _ = try self.wip.store(.normal, llvm_tag, field_ptr, tag_alignment);
9846 }9879 }
98479880
...@@ -9978,7 +10011,7 @@ pub const FuncGen = struct {...@@ -9978,7 +10011,7 @@ pub const FuncGen = struct {
9978 variable_index.setMutability(.constant, &o.builder);10011 variable_index.setMutability(.constant, &o.builder);
9979 variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);10012 variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
9980 variable_index.setAlignment(10013 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(),
9982 &o.builder,10015 &o.builder,
9983 );10016 );
998410017
...@@ -10023,7 +10056,7 @@ pub const FuncGen = struct {...@@ -10023,7 +10056,7 @@ pub const FuncGen = struct {
10023 // We have a pointer and we need to return a pointer to the first field.10056 // We have a pointer and we need to return a pointer to the first field.
10024 const payload_ptr = try fg.wip.gepStruct(opt_llvm_ty, opt_handle, 0, "");10057 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();
10027 if (isByRef(payload_ty, mod)) {10060 if (isByRef(payload_ty, mod)) {
10028 if (can_elide_load)10061 if (can_elide_load)
10029 return payload_ptr;10062 return payload_ptr;
...@@ -10050,7 +10083,7 @@ pub const FuncGen = struct {...@@ -10050,7 +10083,7 @@ pub const FuncGen = struct {
10050 const mod = o.module;10083 const mod = o.module;
1005110084
10052 if (isByRef(optional_ty, mod)) {10085 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();
10054 const alloca_inst = try self.buildAlloca(optional_llvm_ty, payload_alignment);10087 const alloca_inst = try self.buildAlloca(optional_llvm_ty, payload_alignment);
1005510088
10056 {10089 {
...@@ -10123,7 +10156,7 @@ pub const FuncGen = struct {...@@ -10123,7 +10156,7 @@ pub const FuncGen = struct {
10123 .Union => {10156 .Union => {
10124 const layout = struct_ty.unionGetLayout(mod);10157 const layout = struct_ty.unionGetLayout(mod);
10125 if (layout.payload_size == 0 or struct_ty.containerLayout(mod) == .Packed) return struct_ptr;10158 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));
10127 const union_llvm_ty = try o.lowerType(struct_ty);10160 const union_llvm_ty = try o.lowerType(struct_ty);
10128 return self.wip.gepStruct(union_llvm_ty, struct_ptr, payload_index, "");10161 return self.wip.gepStruct(union_llvm_ty, struct_ptr, payload_index, "");
10129 },10162 },
...@@ -10142,9 +10175,7 @@ pub const FuncGen = struct {...@@ -10142,9 +10175,7 @@ pub const FuncGen = struct {
10142 const o = fg.dg.object;10175 const o = fg.dg.object;
10143 const mod = o.module;10176 const mod = o.module;
10144 const pointee_llvm_ty = try o.lowerType(pointee_type);10177 const pointee_llvm_ty = try o.lowerType(pointee_type);
10145 const result_align = Builder.Alignment.fromByteUnits(10178 const result_align = InternPool.Alignment.fromLlvm(ptr_alignment).max(pointee_type.abiAlignment(mod)).toLlvm();
10146 @max(ptr_alignment.toByteUnits() orelse 0, pointee_type.abiAlignment(mod)),
10147 );
10148 const result_ptr = try fg.buildAlloca(pointee_llvm_ty, result_align);10179 const result_ptr = try fg.buildAlloca(pointee_llvm_ty, result_align);
10149 const size_bytes = pointee_type.abiSize(mod);10180 const size_bytes = pointee_type.abiSize(mod);
10150 _ = try fg.wip.callMemCpy(10181 _ = try fg.wip.callMemCpy(
...@@ -10168,9 +10199,11 @@ pub const FuncGen = struct {...@@ -10168,9 +10199,11 @@ pub const FuncGen = struct {
10168 const elem_ty = info.child.toType();10199 const elem_ty = info.child.toType();
10169 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none;10200 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none;
1017010201
10171 const ptr_alignment = Builder.Alignment.fromByteUnits(10202 const ptr_alignment = (if (info.flags.alignment != .none)
10172 info.flags.alignment.toByteUnitsOptional() orelse elem_ty.abiAlignment(mod),10203 @as(InternPool.Alignment, info.flags.alignment)
10173 );10204 else
10205 elem_ty.abiAlignment(mod)).toLlvm();
10206
10174 const access_kind: Builder.MemoryAccessKind =10207 const access_kind: Builder.MemoryAccessKind =
10175 if (info.flags.is_volatile) .@"volatile" else .normal;10208 if (info.flags.is_volatile) .@"volatile" else .normal;
1017610209
...@@ -10201,7 +10234,7 @@ pub const FuncGen = struct {...@@ -10201,7 +10234,7 @@ pub const FuncGen = struct {
10201 const elem_llvm_ty = try o.lowerType(elem_ty);10234 const elem_llvm_ty = try o.lowerType(elem_ty);
1020210235
10203 if (isByRef(elem_ty, mod)) {10236 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();
10205 const result_ptr = try self.buildAlloca(elem_llvm_ty, result_align);10238 const result_ptr = try self.buildAlloca(elem_llvm_ty, result_align);
1020610239
10207 const same_size_int = try o.builder.intType(@intCast(elem_bits));10240 const same_size_int = try o.builder.intType(@intCast(elem_bits));
...@@ -10239,7 +10272,7 @@ pub const FuncGen = struct {...@@ -10239,7 +10272,7 @@ pub const FuncGen = struct {
10239 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) {10272 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) {
10240 return;10273 return;
10241 }10274 }
10242 const ptr_alignment = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));10275 const ptr_alignment = ptr_ty.ptrAlignment(mod).toLlvm();
10243 const access_kind: Builder.MemoryAccessKind =10276 const access_kind: Builder.MemoryAccessKind =
10244 if (info.flags.is_volatile) .@"volatile" else .normal;10277 if (info.flags.is_volatile) .@"volatile" else .normal;
1024510278
...@@ -10305,7 +10338,7 @@ pub const FuncGen = struct {...@@ -10305,7 +10338,7 @@ pub const FuncGen = struct {
10305 ptr,10338 ptr,
10306 ptr_alignment,10339 ptr_alignment,
10307 elem,10340 elem,
10308 Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod)),10341 elem_ty.abiAlignment(mod).toLlvm(),
10309 try o.builder.intValue(try o.lowerType(Type.usize), elem_ty.abiSize(mod)),10342 try o.builder.intValue(try o.lowerType(Type.usize), elem_ty.abiSize(mod)),
10310 access_kind,10343 access_kind,
10311 );10344 );
...@@ -10337,7 +10370,7 @@ pub const FuncGen = struct {...@@ -10337,7 +10370,7 @@ pub const FuncGen = struct {
10337 if (!target_util.hasValgrindSupport(target)) return default_value;10370 if (!target_util.hasValgrindSupport(target)) return default_value;
1033810371
10339 const llvm_usize = try o.lowerType(Type.usize);10372 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
10342 const array_llvm_ty = try o.builder.arrayType(6, llvm_usize);10375 const array_llvm_ty = try o.builder.arrayType(6, llvm_usize);
10343 const array_ptr = if (fg.valgrind_client_request_array == .none) a: {10376 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...@@ -10718,6 +10751,7 @@ fn lowerWin64FnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Err
1071810751
10719fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type {10752fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type {
10720 const mod = o.module;10753 const mod = o.module;
10754 const ip = &mod.intern_pool;
10721 const return_type = fn_info.return_type.toType();10755 const return_type = fn_info.return_type.toType();
10722 if (isScalar(mod, return_type)) {10756 if (isScalar(mod, return_type)) {
10723 return o.lowerType(return_type);10757 return o.lowerType(return_type);
...@@ -10761,12 +10795,16 @@ fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.E...@@ -10761,12 +10795,16 @@ fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.E
10761 const first_non_integer = std.mem.indexOfNone(x86_64_abi.Class, &classes, &.{.integer});10795 const first_non_integer = std.mem.indexOfNone(x86_64_abi.Class, &classes, &.{.integer});
10762 if (first_non_integer == null or classes[first_non_integer.?] == .none) {10796 if (first_non_integer == null or classes[first_non_integer.?] == .none) {
10763 assert(first_non_integer orelse classes.len == types_index);10797 assert(first_non_integer orelse classes.len == types_index);
10764 if (mod.intern_pool.indexToKey(return_type.toIntern()) == .struct_type) {10798 switch (ip.indexToKey(return_type.toIntern())) {
10765 var struct_it = return_type.iterateStructOffsets(mod);10799 .struct_type => |struct_type| {
10766 while (struct_it.next()) |_| {}10800 assert(struct_type.haveLayout(ip));
10767 assert((std.math.divCeil(u64, struct_it.offset, 8) catch unreachable) == types_index);10801 const size: u64 = struct_type.size(ip).*;
10768 if (struct_it.offset % 8 > 0) types_buffer[types_index - 1] =10802 assert((std.math.divCeil(u64, size, 8) catch unreachable) == types_index);
10769 try o.builder.intType(@intCast(struct_it.offset % 8 * 8));10803 if (size % 8 > 0) {
10804 types_buffer[types_index - 1] = try o.builder.intType(@intCast(size % 8 * 8));
10805 }
10806 },
10807 else => {},
10770 }10808 }
10771 if (types_index == 1) return types_buffer[0];10809 if (types_index == 1) return types_buffer[0];
10772 }10810 }
...@@ -10982,6 +11020,7 @@ const ParamTypeIterator = struct {...@@ -10982,6 +11020,7 @@ const ParamTypeIterator = struct {
1098211020
10983 fn nextSystemV(it: *ParamTypeIterator, ty: Type) Allocator.Error!?Lowering {11021 fn nextSystemV(it: *ParamTypeIterator, ty: Type) Allocator.Error!?Lowering {
10984 const mod = it.object.module;11022 const mod = it.object.module;
11023 const ip = &mod.intern_pool;
10985 const classes = x86_64_abi.classifySystemV(ty, mod, .arg);11024 const classes = x86_64_abi.classifySystemV(ty, mod, .arg);
10986 if (classes[0] == .memory) {11025 if (classes[0] == .memory) {
10987 it.zig_index += 1;11026 it.zig_index += 1;
...@@ -11037,12 +11076,17 @@ const ParamTypeIterator = struct {...@@ -11037,12 +11076,17 @@ const ParamTypeIterator = struct {
11037 it.llvm_index += 1;11076 it.llvm_index += 1;
11038 return .abi_sized_int;11077 return .abi_sized_int;
11039 }11078 }
11040 if (mod.intern_pool.indexToKey(ty.toIntern()) == .struct_type) {11079 switch (ip.indexToKey(ty.toIntern())) {
11041 var struct_it = ty.iterateStructOffsets(mod);11080 .struct_type => |struct_type| {
11042 while (struct_it.next()) |_| {}11081 assert(struct_type.haveLayout(ip));
11043 assert((std.math.divCeil(u64, struct_it.offset, 8) catch unreachable) == types_index);11082 const size: u64 = struct_type.size(ip).*;
11044 if (struct_it.offset % 8 > 0) types_buffer[types_index - 1] =11083 assert((std.math.divCeil(u64, size, 8) catch unreachable) == types_index);
11045 try it.object.builder.intType(@intCast(struct_it.offset % 8 * 8));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 => {},
11046 }11090 }
11047 }11091 }
11048 it.types_len = types_index;11092 it.types_len = types_index;
...@@ -11137,8 +11181,6 @@ fn isByRef(ty: Type, mod: *Module) bool {...@@ -11137,8 +11181,6 @@ fn isByRef(ty: Type, mod: *Module) bool {
1113711181
11138 .Array, .Frame => return ty.hasRuntimeBits(mod),11182 .Array, .Frame => return ty.hasRuntimeBits(mod),
11139 .Struct => {11183 .Struct => {
11140 // Packed structs are represented to LLVM as integers.
11141 if (ty.containerLayout(mod) == .Packed) return false;
11142 const struct_type = switch (ip.indexToKey(ty.toIntern())) {11184 const struct_type = switch (ip.indexToKey(ty.toIntern())) {
11143 .anon_struct_type => |tuple| {11185 .anon_struct_type => |tuple| {
11144 var count: usize = 0;11186 var count: usize = 0;
...@@ -11154,14 +11196,18 @@ fn isByRef(ty: Type, mod: *Module) bool {...@@ -11154,14 +11196,18 @@ fn isByRef(ty: Type, mod: *Module) bool {
11154 .struct_type => |s| s,11196 .struct_type => |s| s,
11155 else => unreachable,11197 else => unreachable,
11156 };11198 };
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| {
11162 count += 1;11207 count += 1;
11163 if (count > max_fields_byval) return true;11208 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;
11165 }11211 }
11166 return false;11212 return false;
11167 },11213 },
...@@ -11362,11 +11408,11 @@ fn buildAllocaInner(...@@ -11362,11 +11408,11 @@ fn buildAllocaInner(
11362}11408}
1136311409
11364fn errUnionPayloadOffset(payload_ty: Type, mod: *Module) u1 {11410fn 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)));
11366}11412}
1136711413
11368fn errUnionErrorOffset(payload_ty: Type, mod: *Module) u1 {11414fn 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)));
11370}11416}
1137111417
11372/// Returns true for asm constraint (e.g. "=*m", "=r") if it accepts a memory location11418/// Returns true for asm constraint (e.g. "=*m", "=r") if it accepts a memory location
src/codegen/spirv.zig+26-24
...@@ -792,24 +792,28 @@ pub const DeclGen = struct {...@@ -792,24 +792,28 @@ pub const DeclGen = struct {
792 },792 },
793 .vector_type => return dg.todo("indirect constant of type {}", .{ty.fmt(mod)}),793 .vector_type => return dg.todo("indirect constant of type {}", .{ty.fmt(mod)}),
794 .struct_type => {794 .struct_type => {
795 const struct_ty = mod.typeToStruct(ty).?;795 const struct_type = mod.typeToStruct(ty).?;
796 if (struct_ty.layout == .Packed) {796 if (struct_type.layout == .Packed) {
797 return dg.todo("packed struct constants", .{});797 return dg.todo("packed struct constants", .{});
798 }798 }
799799
800 // TODO iterate with runtime order instead so that struct field
801 // reordering can be enabled for this backend.
800 const struct_begin = self.size;802 const struct_begin = self.size;
801 for (struct_ty.fields.values(), 0..) |field, i| {803 for (struct_type.field_types.get(ip), 0..) |field_ty, i_usize| {
802 if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue;804 const i: u32 = @intCast(i_usize);
805 if (struct_type.fieldIsComptime(ip, i)) continue;
806 if (!field_ty.toType().hasRuntimeBits(mod)) continue;
803807
804 const field_val = switch (aggregate.storage) {808 const field_val = switch (aggregate.storage) {
805 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{809 .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
806 .ty = field.ty.toIntern(),810 .ty = field_ty,
807 .storage = .{ .u64 = bytes[i] },811 .storage = .{ .u64 = bytes[i] },
808 } }),812 } }),
809 .elems => |elems| elems[i],813 .elems => |elems| elems[i],
810 .repeated_elem => |elem| elem,814 .repeated_elem => |elem| elem,
811 };815 };
812 try self.lower(field.ty, field_val.toValue());816 try self.lower(field_ty.toType(), field_val.toValue());
813817
814 // Add padding if required.818 // Add padding if required.
815 // TODO: Add to type generation as well?819 // TODO: Add to type generation as well?
...@@ -838,7 +842,7 @@ pub const DeclGen = struct {...@@ -838,7 +842,7 @@ pub const DeclGen = struct {
838 const active_field_ty = union_obj.field_types.get(ip)[active_field].toType();842 const active_field_ty = union_obj.field_types.get(ip)[active_field].toType();
839843
840 const has_tag = layout.tag_size != 0;844 const has_tag = layout.tag_size != 0;
841 const tag_first = layout.tag_align >= layout.payload_align;845 const tag_first = layout.tag_align.compare(.gte, layout.payload_align);
842846
843 if (has_tag and tag_first) {847 if (has_tag and tag_first) {
844 try self.lower(ty.unionTagTypeSafety(mod).?, un.tag.toValue());848 try self.lower(ty.unionTagTypeSafety(mod).?, un.tag.toValue());
...@@ -1094,7 +1098,7 @@ pub const DeclGen = struct {...@@ -1094,7 +1098,7 @@ pub const DeclGen = struct {
1094 val,1098 val,
1095 .UniformConstant,1099 .UniformConstant,
1096 false,1100 false,
1097 alignment,1101 @intCast(alignment.toByteUnits(0)),
1098 );1102 );
1099 log.debug("indirect constant: index = {}", .{@intFromEnum(spv_decl_index)});1103 log.debug("indirect constant: index = {}", .{@intFromEnum(spv_decl_index)});
1100 try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {});1104 try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {});
...@@ -1180,7 +1184,7 @@ pub const DeclGen = struct {...@@ -1180,7 +1184,7 @@ pub const DeclGen = struct {
1180 var member_names = std.BoundedArray(CacheString, 4){};1184 var member_names = std.BoundedArray(CacheString, 4){};
11811185
1182 const has_tag = layout.tag_size != 0;1186 const has_tag = layout.tag_size != 0;
1183 const tag_first = layout.tag_align >= layout.payload_align;1187 const tag_first = layout.tag_align.compare(.gte, layout.payload_align);
1184 const u8_ty_ref = try self.intType(.unsigned, 8); // TODO: What if Int8Type is not enabled?1188 const u8_ty_ref = try self.intType(.unsigned, 8); // TODO: What if Int8Type is not enabled?
11851189
1186 if (has_tag and tag_first) {1190 if (has_tag and tag_first) {
...@@ -1333,7 +1337,7 @@ pub const DeclGen = struct {...@@ -1333,7 +1337,7 @@ pub const DeclGen = struct {
1333 } });1337 } });
1334 },1338 },
1335 .Struct => {1339 .Struct => {
1336 const struct_ty = switch (ip.indexToKey(ty.toIntern())) {1340 const struct_type = switch (ip.indexToKey(ty.toIntern())) {
1337 .anon_struct_type => |tuple| {1341 .anon_struct_type => |tuple| {
1338 const member_types = try self.gpa.alloc(CacheRef, tuple.values.len);1342 const member_types = try self.gpa.alloc(CacheRef, tuple.values.len);
1339 defer self.gpa.free(member_types);1343 defer self.gpa.free(member_types);
...@@ -1350,13 +1354,12 @@ pub const DeclGen = struct {...@@ -1350,13 +1354,12 @@ pub const DeclGen = struct {
1350 .member_types = member_types[0..member_index],1354 .member_types = member_types[0..member_index],
1351 } });1355 } });
1352 },1356 },
1353 .struct_type => |struct_ty| struct_ty,1357 .struct_type => |struct_type| struct_type,
1354 else => unreachable,1358 else => unreachable,
1355 };1359 };
13561360
1357 const struct_obj = mod.structPtrUnwrap(struct_ty.index).?;1361 if (struct_type.layout == .Packed) {
1358 if (struct_obj.layout == .Packed) {1362 return try self.resolveType(struct_type.backingIntType(ip).toType(), .direct);
1359 return try self.resolveType(struct_obj.backing_int_ty, .direct);
1360 }1363 }
13611364
1362 var member_types = std.ArrayList(CacheRef).init(self.gpa);1365 var member_types = std.ArrayList(CacheRef).init(self.gpa);
...@@ -1365,16 +1368,15 @@ pub const DeclGen = struct {...@@ -1365,16 +1368,15 @@ pub const DeclGen = struct {
1365 var member_names = std.ArrayList(CacheString).init(self.gpa);1368 var member_names = std.ArrayList(CacheString).init(self.gpa);
1366 defer member_names.deinit();1369 defer member_names.deinit();
13671370
1368 var it = struct_obj.runtimeFieldIterator(mod);1371 var it = struct_type.iterateRuntimeOrder(ip);
1369 while (it.next()) |field_and_index| {1372 while (it.next()) |field_index| {
1370 const field = field_and_index.field;1373 const field_ty = struct_type.field_types.get(ip)[field_index];
1371 const index = field_and_index.index;1374 const field_name = ip.stringToSlice(struct_type.field_names.get(ip)[field_index]);
1372 const field_name = ip.stringToSlice(struct_obj.fields.keys()[index]);1375 try member_types.append(try self.resolveType(field_ty.toType(), .indirect));
1373 try member_types.append(try self.resolveType(field.ty, .indirect));
1374 try member_names.append(try self.spv.resolveString(field_name));1376 try member_names.append(try self.spv.resolveString(field_name));
1375 }1377 }
13761378
1377 const name = ip.stringToSlice(try struct_obj.getFullyQualifiedName(self.module));1379 const name = ip.stringToSlice(try mod.declPtr(struct_type.decl.unwrap().?).getFullyQualifiedName(mod));
13781380
1379 return try self.spv.resolve(.{ .struct_type = .{1381 return try self.spv.resolve(.{ .struct_type = .{
1380 .name = try self.spv.resolveString(name),1382 .name = try self.spv.resolveString(name),
...@@ -1500,7 +1502,7 @@ pub const DeclGen = struct {...@@ -1500,7 +1502,7 @@ pub const DeclGen = struct {
1500 const error_align = Type.anyerror.abiAlignment(mod);1502 const error_align = Type.anyerror.abiAlignment(mod);
1501 const payload_align = payload_ty.abiAlignment(mod);1503 const payload_align = payload_ty.abiAlignment(mod);
15021504
1503 const error_first = error_align > payload_align;1505 const error_first = error_align.compare(.gt, payload_align);
1504 return .{1506 return .{
1505 .payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(mod),1507 .payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(mod),
1506 .error_first = error_first,1508 .error_first = error_first,
...@@ -1662,7 +1664,7 @@ pub const DeclGen = struct {...@@ -1662,7 +1664,7 @@ pub const DeclGen = struct {
1662 init_val,1664 init_val,
1663 actual_storage_class,1665 actual_storage_class,
1664 final_storage_class == .Generic,1666 final_storage_class == .Generic,
1665 @as(u32, @intCast(decl.alignment.toByteUnits(0))),1667 @intCast(decl.alignment.toByteUnits(0)),
1666 );1668 );
1667 }1669 }
1668 }1670 }
...@@ -2603,7 +2605,7 @@ pub const DeclGen = struct {...@@ -2603,7 +2605,7 @@ pub const DeclGen = struct {
2603 if (layout.payload_size == 0) return union_handle;2605 if (layout.payload_size == 0) return union_handle;
26042606
2605 const tag_ty = un_ty.unionTagTypeSafety(mod).?;2607 const tag_ty = un_ty.unionTagTypeSafety(mod).?;
2606 const tag_index = @intFromBool(layout.tag_align < layout.payload_align);2608 const tag_index = @intFromBool(layout.tag_align.compare(.lt, layout.payload_align));
2607 return try self.extractField(tag_ty, union_handle, tag_index);2609 return try self.extractField(tag_ty, union_handle, tag_index);
2608 }2610 }
26092611
src/link/Coff.zig+4-4
...@@ -1118,7 +1118,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In...@@ -1118,7 +1118,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In
1118 },1118 },
1119 };1119 };
11201120
1121 const required_alignment = tv.ty.abiAlignment(mod);1121 const required_alignment: u32 = @intCast(tv.ty.abiAlignment(mod).toByteUnits(0));
1122 const atom = self.getAtomPtr(atom_index);1122 const atom = self.getAtomPtr(atom_index);
1123 atom.size = @as(u32, @intCast(code.len));1123 atom.size = @as(u32, @intCast(code.len));
1124 atom.getSymbolPtr(self).value = try self.allocateAtom(atom_index, atom.size, required_alignment);1124 atom.getSymbolPtr(self).value = try self.allocateAtom(atom_index, atom.size, required_alignment);
...@@ -1196,7 +1196,7 @@ fn updateLazySymbolAtom(...@@ -1196,7 +1196,7 @@ fn updateLazySymbolAtom(
1196 const gpa = self.base.allocator;1196 const gpa = self.base.allocator;
1197 const mod = self.base.options.module.?;1197 const mod = self.base.options.module.?;
11981198
1199 var required_alignment: u32 = undefined;1199 var required_alignment: InternPool.Alignment = .none;
1200 var code_buffer = std.ArrayList(u8).init(gpa);1200 var code_buffer = std.ArrayList(u8).init(gpa);
1201 defer code_buffer.deinit();1201 defer code_buffer.deinit();
12021202
...@@ -1240,7 +1240,7 @@ fn updateLazySymbolAtom(...@@ -1240,7 +1240,7 @@ fn updateLazySymbolAtom(
1240 symbol.section_number = @as(coff.SectionNumber, @enumFromInt(section_index + 1));1240 symbol.section_number = @as(coff.SectionNumber, @enumFromInt(section_index + 1));
1241 symbol.type = .{ .complex_type = .NULL, .base_type = .NULL };1241 symbol.type = .{ .complex_type = .NULL, .base_type = .NULL };
12421242
1243 const vaddr = try self.allocateAtom(atom_index, code_len, required_alignment);1243 const vaddr = try self.allocateAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits(0)));
1244 errdefer self.freeAtom(atom_index);1244 errdefer self.freeAtom(atom_index);
12451245
1246 log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr });1246 log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr });
...@@ -1322,7 +1322,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []u8, comple...@@ -1322,7 +1322,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []u8, comple
1322 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));1322 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
13231323
1324 log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });1324 log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });
1325 const required_alignment = decl.getAlignment(mod);1325 const required_alignment: u32 = @intCast(decl.getAlignment(mod).toByteUnits(0));
13261326
1327 const decl_metadata = self.decls.get(decl_index).?;1327 const decl_metadata = self.decls.get(decl_index).?;
1328 const atom_index = decl_metadata.atom;1328 const atom_index = decl_metadata.atom;
src/link/Dwarf.zig+42-28
...@@ -341,37 +341,51 @@ pub const DeclState = struct {...@@ -341,37 +341,51 @@ pub const DeclState = struct {
341 try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);341 try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
342 }342 }
343 },343 },
344 .struct_type => |struct_type| s: {344 .struct_type => |struct_type| {
345 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :s;
346 // DW.AT.name, DW.FORM.string345 // DW.AT.name, DW.FORM.string
347 try ty.print(dbg_info_buffer.writer(), mod);346 try ty.print(dbg_info_buffer.writer(), mod);
348 try dbg_info_buffer.append(0);347 try dbg_info_buffer.append(0);
349348
350 if (struct_obj.layout == .Packed) {349 if (struct_type.layout == .Packed) {
351 log.debug("TODO implement .debug_info for packed structs", .{});350 log.debug("TODO implement .debug_info for packed structs", .{});
352 break :blk;351 break :blk;
353 }352 }
354353
355 for (354 if (struct_type.isTuple(ip)) {
356 struct_obj.fields.keys(),355 for (struct_type.field_types.get(ip), struct_type.offsets.get(ip), 0..) |field_ty, field_off, field_index| {
357 struct_obj.fields.values(),356 if (!field_ty.toType().hasRuntimeBits(mod)) continue;
358 0..,357 // DW.AT.member
359 ) |field_name_ip, field, field_index| {358 try dbg_info_buffer.append(@intFromEnum(AbbrevKind.struct_member));
360 if (!field.ty.hasRuntimeBits(mod)) continue;359 // DW.AT.name, DW.FORM.string
361 const field_name = ip.stringToSlice(field_name_ip);360 try dbg_info_buffer.writer().print("{d}\x00", .{field_index});
362 // DW.AT.member361 // DW.AT.type, DW.FORM.ref4
363 try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2);362 var index = dbg_info_buffer.items.len;
364 dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevKind.struct_member));363 try dbg_info_buffer.resize(index + 4);
365 // DW.AT.name, DW.FORM.string364 try self.addTypeRelocGlobal(atom_index, field_ty.toType(), @as(u32, @intCast(index)));
366 dbg_info_buffer.appendSliceAssumeCapacity(field_name);365 // DW.AT.data_member_location, DW.FORM.udata
367 dbg_info_buffer.appendAssumeCapacity(0);366 try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);
368 // DW.AT.type, DW.FORM.ref4367 }
369 var index = dbg_info_buffer.items.len;368 } else {
370 try dbg_info_buffer.resize(index + 4);369 for (
371 try self.addTypeRelocGlobal(atom_index, field.ty, @as(u32, @intCast(index)));370 struct_type.field_names.get(ip),
372 // DW.AT.data_member_location, DW.FORM.udata371 struct_type.field_types.get(ip),
373 const field_off = ty.structFieldOffset(field_index, mod);372 struct_type.offsets.get(ip),
374 try leb128.writeULEB128(dbg_info_buffer.writer(), field_off);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 }
375 }389 }
376 },390 },
377 else => unreachable,391 else => unreachable,
...@@ -416,8 +430,8 @@ pub const DeclState = struct {...@@ -416,8 +430,8 @@ pub const DeclState = struct {
416 .Union => {430 .Union => {
417 const union_obj = mod.typeToUnion(ty).?;431 const union_obj = mod.typeToUnion(ty).?;
418 const layout = mod.getUnionLayout(union_obj);432 const layout = mod.getUnionLayout(union_obj);
419 const payload_offset = if (layout.tag_align >= layout.payload_align) layout.tag_size else 0;433 const payload_offset = if (layout.tag_align.compare(.gte, layout.payload_align)) layout.tag_size else 0;
420 const tag_offset = if (layout.tag_align >= layout.payload_align) 0 else layout.payload_size;434 const tag_offset = if (layout.tag_align.compare(.gte, layout.payload_align)) 0 else layout.payload_size;
421 // TODO this is temporary to match current state of unions in Zig - we don't yet have435 // TODO this is temporary to match current state of unions in Zig - we don't yet have
422 // safety checks implemented meaning the implicit tag is not yet stored and generated436 // safety checks implemented meaning the implicit tag is not yet stored and generated
423 // for untagged unions.437 // for untagged unions.
...@@ -496,11 +510,11 @@ pub const DeclState = struct {...@@ -496,11 +510,11 @@ pub const DeclState = struct {
496 .ErrorUnion => {510 .ErrorUnion => {
497 const error_ty = ty.errorUnionSet(mod);511 const error_ty = ty.errorUnionSet(mod);
498 const payload_ty = ty.errorUnionPayload(mod);512 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);
500 const error_align = Type.anyerror.abiAlignment(mod);514 const error_align = Type.anyerror.abiAlignment(mod);
501 const abi_size = ty.abiSize(mod);515 const abi_size = ty.abiSize(mod);
502 const payload_off = if (error_align >= payload_align) Type.anyerror.abiSize(mod) else 0;516 const payload_off = if (error_align.compare(.gte, payload_align)) Type.anyerror.abiSize(mod) else 0;
503 const error_off = if (error_align >= payload_align) 0 else payload_ty.abiSize(mod);517 const error_off = if (error_align.compare(.gte, payload_align)) 0 else payload_ty.abiSize(mod);
504518
505 // DW.AT.structure_type519 // DW.AT.structure_type
506 try dbg_info_buffer.append(@intFromEnum(AbbrevKind.struct_type));520 try dbg_info_buffer.append(@intFromEnum(AbbrevKind.struct_type));
src/link/Elf.zig+26-26
...@@ -409,7 +409,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -409,7 +409,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
409 const image_base = self.calcImageBase();409 const image_base = self.calcImageBase();
410410
411 if (self.phdr_table_index == null) {411 if (self.phdr_table_index == null) {
412 self.phdr_table_index = @as(u16, @intCast(self.phdrs.items.len));412 self.phdr_table_index = @intCast(self.phdrs.items.len);
413 const p_align: u16 = switch (self.ptr_width) {413 const p_align: u16 = switch (self.ptr_width) {
414 .p32 => @alignOf(elf.Elf32_Phdr),414 .p32 => @alignOf(elf.Elf32_Phdr),
415 .p64 => @alignOf(elf.Elf64_Phdr),415 .p64 => @alignOf(elf.Elf64_Phdr),
...@@ -428,7 +428,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -428,7 +428,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
428 }428 }
429429
430 if (self.phdr_table_load_index == null) {430 if (self.phdr_table_load_index == null) {
431 self.phdr_table_load_index = @as(u16, @intCast(self.phdrs.items.len));431 self.phdr_table_load_index = @intCast(self.phdrs.items.len);
432 // TODO Same as for GOT432 // TODO Same as for GOT
433 try self.phdrs.append(gpa, .{433 try self.phdrs.append(gpa, .{
434 .p_type = elf.PT_LOAD,434 .p_type = elf.PT_LOAD,
...@@ -444,7 +444,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -444,7 +444,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
444 }444 }
445445
446 if (self.phdr_load_re_index == null) {446 if (self.phdr_load_re_index == null) {
447 self.phdr_load_re_index = @as(u16, @intCast(self.phdrs.items.len));447 self.phdr_load_re_index = @intCast(self.phdrs.items.len);
448 const file_size = self.base.options.program_code_size_hint;448 const file_size = self.base.options.program_code_size_hint;
449 const p_align = self.page_size;449 const p_align = self.page_size;
450 const off = self.findFreeSpace(file_size, p_align);450 const off = self.findFreeSpace(file_size, p_align);
...@@ -465,7 +465,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -465,7 +465,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
465 }465 }
466466
467 if (self.phdr_got_index == null) {467 if (self.phdr_got_index == null) {
468 self.phdr_got_index = @as(u16, @intCast(self.phdrs.items.len));468 self.phdr_got_index = @intCast(self.phdrs.items.len);
469 const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint;469 const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint;
470 // We really only need ptr alignment but since we are using PROGBITS, linux requires470 // We really only need ptr alignment but since we are using PROGBITS, linux requires
471 // page align.471 // page align.
...@@ -490,7 +490,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -490,7 +490,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
490 }490 }
491491
492 if (self.phdr_load_ro_index == null) {492 if (self.phdr_load_ro_index == null) {
493 self.phdr_load_ro_index = @as(u16, @intCast(self.phdrs.items.len));493 self.phdr_load_ro_index = @intCast(self.phdrs.items.len);
494 // TODO Find a hint about how much data need to be in rodata ?494 // TODO Find a hint about how much data need to be in rodata ?
495 const file_size = 1024;495 const file_size = 1024;
496 // Same reason as for GOT496 // Same reason as for GOT
...@@ -513,7 +513,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -513,7 +513,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
513 }513 }
514514
515 if (self.phdr_load_rw_index == null) {515 if (self.phdr_load_rw_index == null) {
516 self.phdr_load_rw_index = @as(u16, @intCast(self.phdrs.items.len));516 self.phdr_load_rw_index = @intCast(self.phdrs.items.len);
517 // TODO Find a hint about how much data need to be in data ?517 // TODO Find a hint about how much data need to be in data ?
518 const file_size = 1024;518 const file_size = 1024;
519 // Same reason as for GOT519 // Same reason as for GOT
...@@ -536,7 +536,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -536,7 +536,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
536 }536 }
537537
538 if (self.phdr_load_zerofill_index == null) {538 if (self.phdr_load_zerofill_index == null) {
539 self.phdr_load_zerofill_index = @as(u16, @intCast(self.phdrs.items.len));539 self.phdr_load_zerofill_index = @intCast(self.phdrs.items.len);
540 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);540 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
541 const off = self.phdrs.items[self.phdr_load_rw_index.?].p_offset;541 const off = self.phdrs.items[self.phdr_load_rw_index.?].p_offset;
542 log.debug("found PT_LOAD zerofill free space 0x{x} to 0x{x}", .{ off, off });542 log.debug("found PT_LOAD zerofill free space 0x{x} to 0x{x}", .{ off, off });
...@@ -556,7 +556,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -556,7 +556,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
556 }556 }
557557
558 if (self.shstrtab_section_index == null) {558 if (self.shstrtab_section_index == null) {
559 self.shstrtab_section_index = @as(u16, @intCast(self.shdrs.items.len));559 self.shstrtab_section_index = @intCast(self.shdrs.items.len);
560 assert(self.shstrtab.buffer.items.len == 0);560 assert(self.shstrtab.buffer.items.len == 0);
561 try self.shstrtab.buffer.append(gpa, 0); // need a 0 at position 0561 try self.shstrtab.buffer.append(gpa, 0); // need a 0 at position 0
562 const off = self.findFreeSpace(self.shstrtab.buffer.items.len, 1);562 const off = self.findFreeSpace(self.shstrtab.buffer.items.len, 1);
...@@ -578,7 +578,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -578,7 +578,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
578 }578 }
579579
580 if (self.strtab_section_index == null) {580 if (self.strtab_section_index == null) {
581 self.strtab_section_index = @as(u16, @intCast(self.shdrs.items.len));581 self.strtab_section_index = @intCast(self.shdrs.items.len);
582 assert(self.strtab.buffer.items.len == 0);582 assert(self.strtab.buffer.items.len == 0);
583 try self.strtab.buffer.append(gpa, 0); // need a 0 at position 0583 try self.strtab.buffer.append(gpa, 0); // need a 0 at position 0
584 const off = self.findFreeSpace(self.strtab.buffer.items.len, 1);584 const off = self.findFreeSpace(self.strtab.buffer.items.len, 1);
...@@ -600,7 +600,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -600,7 +600,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
600 }600 }
601601
602 if (self.text_section_index == null) {602 if (self.text_section_index == null) {
603 self.text_section_index = @as(u16, @intCast(self.shdrs.items.len));603 self.text_section_index = @intCast(self.shdrs.items.len);
604 const phdr = &self.phdrs.items[self.phdr_load_re_index.?];604 const phdr = &self.phdrs.items[self.phdr_load_re_index.?];
605 try self.shdrs.append(gpa, .{605 try self.shdrs.append(gpa, .{
606 .sh_name = try self.shstrtab.insert(gpa, ".text"),606 .sh_name = try self.shstrtab.insert(gpa, ".text"),
...@@ -620,7 +620,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -620,7 +620,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
620 }620 }
621621
622 if (self.got_section_index == null) {622 if (self.got_section_index == null) {
623 self.got_section_index = @as(u16, @intCast(self.shdrs.items.len));623 self.got_section_index = @intCast(self.shdrs.items.len);
624 const phdr = &self.phdrs.items[self.phdr_got_index.?];624 const phdr = &self.phdrs.items[self.phdr_got_index.?];
625 try self.shdrs.append(gpa, .{625 try self.shdrs.append(gpa, .{
626 .sh_name = try self.shstrtab.insert(gpa, ".got"),626 .sh_name = try self.shstrtab.insert(gpa, ".got"),
...@@ -639,7 +639,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -639,7 +639,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
639 }639 }
640640
641 if (self.rodata_section_index == null) {641 if (self.rodata_section_index == null) {
642 self.rodata_section_index = @as(u16, @intCast(self.shdrs.items.len));642 self.rodata_section_index = @intCast(self.shdrs.items.len);
643 const phdr = &self.phdrs.items[self.phdr_load_ro_index.?];643 const phdr = &self.phdrs.items[self.phdr_load_ro_index.?];
644 try self.shdrs.append(gpa, .{644 try self.shdrs.append(gpa, .{
645 .sh_name = try self.shstrtab.insert(gpa, ".rodata"),645 .sh_name = try self.shstrtab.insert(gpa, ".rodata"),
...@@ -659,7 +659,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -659,7 +659,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
659 }659 }
660660
661 if (self.data_section_index == null) {661 if (self.data_section_index == null) {
662 self.data_section_index = @as(u16, @intCast(self.shdrs.items.len));662 self.data_section_index = @intCast(self.shdrs.items.len);
663 const phdr = &self.phdrs.items[self.phdr_load_rw_index.?];663 const phdr = &self.phdrs.items[self.phdr_load_rw_index.?];
664 try self.shdrs.append(gpa, .{664 try self.shdrs.append(gpa, .{
665 .sh_name = try self.shstrtab.insert(gpa, ".data"),665 .sh_name = try self.shstrtab.insert(gpa, ".data"),
...@@ -679,7 +679,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -679,7 +679,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
679 }679 }
680680
681 if (self.bss_section_index == null) {681 if (self.bss_section_index == null) {
682 self.bss_section_index = @as(u16, @intCast(self.shdrs.items.len));682 self.bss_section_index = @intCast(self.shdrs.items.len);
683 const phdr = &self.phdrs.items[self.phdr_load_zerofill_index.?];683 const phdr = &self.phdrs.items[self.phdr_load_zerofill_index.?];
684 try self.shdrs.append(gpa, .{684 try self.shdrs.append(gpa, .{
685 .sh_name = try self.shstrtab.insert(gpa, ".bss"),685 .sh_name = try self.shstrtab.insert(gpa, ".bss"),
...@@ -699,7 +699,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -699,7 +699,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
699 }699 }
700700
701 if (self.symtab_section_index == null) {701 if (self.symtab_section_index == null) {
702 self.symtab_section_index = @as(u16, @intCast(self.shdrs.items.len));702 self.symtab_section_index = @intCast(self.shdrs.items.len);
703 const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym);703 const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym);
704 const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym);704 const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym);
705 const file_size = self.base.options.symbol_count_hint * each_size;705 const file_size = self.base.options.symbol_count_hint * each_size;
...@@ -714,7 +714,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -714,7 +714,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
714 .sh_size = file_size,714 .sh_size = file_size,
715 // The section header index of the associated string table.715 // The section header index of the associated string table.
716 .sh_link = self.strtab_section_index.?,716 .sh_link = self.strtab_section_index.?,
717 .sh_info = @as(u32, @intCast(self.symbols.items.len)),717 .sh_info = @intCast(self.symbols.items.len),
718 .sh_addralign = min_align,718 .sh_addralign = min_align,
719 .sh_entsize = each_size,719 .sh_entsize = each_size,
720 });720 });
...@@ -723,7 +723,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -723,7 +723,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
723723
724 if (self.dwarf) |*dw| {724 if (self.dwarf) |*dw| {
725 if (self.debug_str_section_index == null) {725 if (self.debug_str_section_index == null) {
726 self.debug_str_section_index = @as(u16, @intCast(self.shdrs.items.len));726 self.debug_str_section_index = @intCast(self.shdrs.items.len);
727 assert(dw.strtab.buffer.items.len == 0);727 assert(dw.strtab.buffer.items.len == 0);
728 try dw.strtab.buffer.append(gpa, 0);728 try dw.strtab.buffer.append(gpa, 0);
729 try self.shdrs.append(gpa, .{729 try self.shdrs.append(gpa, .{
...@@ -743,7 +743,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -743,7 +743,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
743 }743 }
744744
745 if (self.debug_info_section_index == null) {745 if (self.debug_info_section_index == null) {
746 self.debug_info_section_index = @as(u16, @intCast(self.shdrs.items.len));746 self.debug_info_section_index = @intCast(self.shdrs.items.len);
747 const file_size_hint = 200;747 const file_size_hint = 200;
748 const p_align = 1;748 const p_align = 1;
749 const off = self.findFreeSpace(file_size_hint, p_align);749 const off = self.findFreeSpace(file_size_hint, p_align);
...@@ -768,7 +768,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -768,7 +768,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
768 }768 }
769769
770 if (self.debug_abbrev_section_index == null) {770 if (self.debug_abbrev_section_index == null) {
771 self.debug_abbrev_section_index = @as(u16, @intCast(self.shdrs.items.len));771 self.debug_abbrev_section_index = @intCast(self.shdrs.items.len);
772 const file_size_hint = 128;772 const file_size_hint = 128;
773 const p_align = 1;773 const p_align = 1;
774 const off = self.findFreeSpace(file_size_hint, p_align);774 const off = self.findFreeSpace(file_size_hint, p_align);
...@@ -793,7 +793,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -793,7 +793,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
793 }793 }
794794
795 if (self.debug_aranges_section_index == null) {795 if (self.debug_aranges_section_index == null) {
796 self.debug_aranges_section_index = @as(u16, @intCast(self.shdrs.items.len));796 self.debug_aranges_section_index = @intCast(self.shdrs.items.len);
797 const file_size_hint = 160;797 const file_size_hint = 160;
798 const p_align = 16;798 const p_align = 16;
799 const off = self.findFreeSpace(file_size_hint, p_align);799 const off = self.findFreeSpace(file_size_hint, p_align);
...@@ -818,7 +818,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -818,7 +818,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
818 }818 }
819819
820 if (self.debug_line_section_index == null) {820 if (self.debug_line_section_index == null) {
821 self.debug_line_section_index = @as(u16, @intCast(self.shdrs.items.len));821 self.debug_line_section_index = @intCast(self.shdrs.items.len);
822 const file_size_hint = 250;822 const file_size_hint = 250;
823 const p_align = 1;823 const p_align = 1;
824 const off = self.findFreeSpace(file_size_hint, p_align);824 const off = self.findFreeSpace(file_size_hint, p_align);
...@@ -2666,12 +2666,12 @@ fn updateDeclCode(...@@ -2666,12 +2666,12 @@ fn updateDeclCode(
26662666
2667 const old_size = atom_ptr.size;2667 const old_size = atom_ptr.size;
2668 const old_vaddr = atom_ptr.value;2668 const old_vaddr = atom_ptr.value;
2669 atom_ptr.alignment = math.log2_int(u64, required_alignment);2669 atom_ptr.alignment = required_alignment;
2670 atom_ptr.size = code.len;2670 atom_ptr.size = code.len;
26712671
2672 if (old_size > 0 and self.base.child_pid == null) {2672 if (old_size > 0 and self.base.child_pid == null) {
2673 const capacity = atom_ptr.capacity(self);2673 const capacity = atom_ptr.capacity(self);
2674 const need_realloc = code.len > capacity or !mem.isAlignedGeneric(u64, sym.value, required_alignment);2674 const need_realloc = code.len > capacity or !required_alignment.check(sym.value);
2675 if (need_realloc) {2675 if (need_realloc) {
2676 try atom_ptr.grow(self);2676 try atom_ptr.grow(self);
2677 log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, old_vaddr, atom_ptr.value });2677 log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, old_vaddr, atom_ptr.value });
...@@ -2869,7 +2869,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol....@@ -2869,7 +2869,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.
2869 const mod = self.base.options.module.?;2869 const mod = self.base.options.module.?;
2870 const zig_module = self.file(self.zig_module_index.?).?.zig_module;2870 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
28712871
2872 var required_alignment: u32 = undefined;2872 var required_alignment: InternPool.Alignment = .none;
2873 var code_buffer = std.ArrayList(u8).init(gpa);2873 var code_buffer = std.ArrayList(u8).init(gpa);
2874 defer code_buffer.deinit();2874 defer code_buffer.deinit();
28752875
...@@ -2918,7 +2918,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol....@@ -2918,7 +2918,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.
2918 const atom_ptr = local_sym.atom(self).?;2918 const atom_ptr = local_sym.atom(self).?;
2919 atom_ptr.alive = true;2919 atom_ptr.alive = true;
2920 atom_ptr.name_offset = name_str_index;2920 atom_ptr.name_offset = name_str_index;
2921 atom_ptr.alignment = math.log2_int(u64, required_alignment);2921 atom_ptr.alignment = required_alignment;
2922 atom_ptr.size = code.len;2922 atom_ptr.size = code.len;
29232923
2924 try atom_ptr.allocate(self);2924 try atom_ptr.allocate(self);
...@@ -2995,7 +2995,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module...@@ -2995,7 +2995,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
2995 const atom_ptr = local_sym.atom(self).?;2995 const atom_ptr = local_sym.atom(self).?;
2996 atom_ptr.alive = true;2996 atom_ptr.alive = true;
2997 atom_ptr.name_offset = name_str_index;2997 atom_ptr.name_offset = name_str_index;
2998 atom_ptr.alignment = math.log2_int(u64, required_alignment);2998 atom_ptr.alignment = required_alignment;
2999 atom_ptr.size = code.len;2999 atom_ptr.size = code.len;
30003000
3001 try atom_ptr.allocate(self);3001 try atom_ptr.allocate(self);
src/link/Elf/Atom.zig+8-9
...@@ -11,7 +11,7 @@ file_index: File.Index = 0,...@@ -11,7 +11,7 @@ file_index: File.Index = 0,
11size: u64 = 0,11size: u64 = 0,
1212
13/// Alignment of this atom as a power of two.13/// Alignment of this atom as a power of two.
14alignment: u8 = 0,14alignment: Alignment = .@"1",
1515
16/// Index of the input section.16/// Index of the input section.
17input_section_index: Index = 0,17input_section_index: Index = 0,
...@@ -42,6 +42,8 @@ fde_end: u32 = 0,...@@ -42,6 +42,8 @@ fde_end: u32 = 0,
42prev_index: Index = 0,42prev_index: Index = 0,
43next_index: Index = 0,43next_index: Index = 0,
4444
45pub const Alignment = @import("../../InternPool.zig").Alignment;
46
45pub fn name(self: Atom, elf_file: *Elf) []const u8 {47pub fn name(self: Atom, elf_file: *Elf) []const u8 {
46 return elf_file.strtab.getAssumeExists(self.name_offset);48 return elf_file.strtab.getAssumeExists(self.name_offset);
47}49}
...@@ -112,7 +114,6 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {...@@ -112,7 +114,6 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
112 const free_list = &meta.free_list;114 const free_list = &meta.free_list;
113 const last_atom_index = &meta.last_atom_index;115 const last_atom_index = &meta.last_atom_index;
114 const new_atom_ideal_capacity = Elf.padToIdeal(self.size);116 const new_atom_ideal_capacity = Elf.padToIdeal(self.size);
115 const alignment = try std.math.powi(u64, 2, self.alignment);
116117
117 // We use these to indicate our intention to update metadata, placing the new atom,118 // We use these to indicate our intention to update metadata, placing the new atom,
118 // and possibly removing a free list node.119 // and possibly removing a free list node.
...@@ -136,7 +137,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {...@@ -136,7 +137,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
136 const ideal_capacity_end_vaddr = std.math.add(u64, big_atom.value, ideal_capacity) catch ideal_capacity;137 const ideal_capacity_end_vaddr = std.math.add(u64, big_atom.value, ideal_capacity) catch ideal_capacity;
137 const capacity_end_vaddr = big_atom.value + cap;138 const capacity_end_vaddr = big_atom.value + cap;
138 const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity;139 const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity;
139 const new_start_vaddr = std.mem.alignBackward(u64, new_start_vaddr_unaligned, alignment);140 const new_start_vaddr = self.alignment.backward(new_start_vaddr_unaligned);
140 if (new_start_vaddr < ideal_capacity_end_vaddr) {141 if (new_start_vaddr < ideal_capacity_end_vaddr) {
141 // Additional bookkeeping here to notice if this free list node142 // Additional bookkeeping here to notice if this free list node
142 // should be deleted because the block that it points to has grown to take up143 // should be deleted because the block that it points to has grown to take up
...@@ -163,7 +164,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {...@@ -163,7 +164,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
163 } else if (elf_file.atom(last_atom_index.*)) |last| {164 } else if (elf_file.atom(last_atom_index.*)) |last| {
164 const ideal_capacity = Elf.padToIdeal(last.size);165 const ideal_capacity = Elf.padToIdeal(last.size);
165 const ideal_capacity_end_vaddr = last.value + ideal_capacity;166 const ideal_capacity_end_vaddr = last.value + ideal_capacity;
166 const new_start_vaddr = std.mem.alignForward(u64, ideal_capacity_end_vaddr, alignment);167 const new_start_vaddr = self.alignment.forward(ideal_capacity_end_vaddr);
167 // Set up the metadata to be updated, after errors are no longer possible.168 // Set up the metadata to be updated, after errors are no longer possible.
168 atom_placement = last.atom_index;169 atom_placement = last.atom_index;
169 break :blk new_start_vaddr;170 break :blk new_start_vaddr;
...@@ -192,7 +193,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {...@@ -192,7 +193,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
192 elf_file.debug_aranges_section_dirty = true;193 elf_file.debug_aranges_section_dirty = true;
193 }194 }
194 }195 }
195 shdr.sh_addralign = @max(shdr.sh_addralign, alignment);196 shdr.sh_addralign = @max(shdr.sh_addralign, self.alignment.toByteUnitsOptional().?);
196197
197 // This function can also reallocate an atom.198 // This function can also reallocate an atom.
198 // In this case we need to "unplug" it from its previous location before199 // In this case we need to "unplug" it from its previous location before
...@@ -224,10 +225,8 @@ pub fn shrink(self: *Atom, elf_file: *Elf) void {...@@ -224,10 +225,8 @@ pub fn shrink(self: *Atom, elf_file: *Elf) void {
224}225}
225226
226pub fn grow(self: *Atom, elf_file: *Elf) !void {227pub fn grow(self: *Atom, elf_file: *Elf) !void {
227 const alignment = try std.math.powi(u64, 2, self.alignment);228 if (!self.alignment.check(self.value) or self.size > self.capacity(elf_file))
228 const align_ok = std.mem.alignBackward(u64, self.value, alignment) == self.value;229 try self.allocate(elf_file);
229 const need_realloc = !align_ok or self.size > self.capacity(elf_file);
230 if (need_realloc) try self.allocate(elf_file);
231}230}
232231
233pub fn free(self: *Atom, elf_file: *Elf) void {232pub fn free(self: *Atom, elf_file: *Elf) void {
src/link/Elf/Object.zig+4-3
...@@ -181,10 +181,10 @@ fn addAtom(self: *Object, shdr: elf.Elf64_Shdr, shndx: u16, name: [:0]const u8,...@@ -181,10 +181,10 @@ fn addAtom(self: *Object, shdr: elf.Elf64_Shdr, shndx: u16, name: [:0]const u8,
181 const data = try self.shdrContents(shndx);181 const data = try self.shdrContents(shndx);
182 const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*;182 const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*;
183 atom.size = chdr.ch_size;183 atom.size = chdr.ch_size;
184 atom.alignment = math.log2_int(u64, chdr.ch_addralign);184 atom.alignment = Alignment.fromNonzeroByteUnits(chdr.ch_addralign);
185 } else {185 } else {
186 atom.size = shdr.sh_size;186 atom.size = shdr.sh_size;
187 atom.alignment = math.log2_int(u64, shdr.sh_addralign);187 atom.alignment = Alignment.fromNonzeroByteUnits(shdr.sh_addralign);
188 }188 }
189}189}
190190
...@@ -571,7 +571,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {...@@ -571,7 +571,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
571 atom.file = self.index;571 atom.file = self.index;
572 atom.size = this_sym.st_size;572 atom.size = this_sym.st_size;
573 const alignment = this_sym.st_value;573 const alignment = this_sym.st_value;
574 atom.alignment = math.log2_int(u64, alignment);574 atom.alignment = Alignment.fromNonzeroByteUnits(alignment);
575575
576 var sh_flags: u32 = elf.SHF_ALLOC | elf.SHF_WRITE;576 var sh_flags: u32 = elf.SHF_ALLOC | elf.SHF_WRITE;
577 if (is_tls) sh_flags |= elf.SHF_TLS;577 if (is_tls) sh_flags |= elf.SHF_TLS;
...@@ -870,3 +870,4 @@ const Fde = eh_frame.Fde;...@@ -870,3 +870,4 @@ const Fde = eh_frame.Fde;
870const File = @import("file.zig").File;870const File = @import("file.zig").File;
871const StringTable = @import("../strtab.zig").StringTable;871const StringTable = @import("../strtab.zig").StringTable;
872const Symbol = @import("Symbol.zig");872const Symbol = @import("Symbol.zig");
873const Alignment = Atom.Alignment;
src/link/MachO.zig+17-18
...@@ -1425,7 +1425,7 @@ pub fn allocateSpecialSymbols(self: *MachO) !void {...@@ -1425,7 +1425,7 @@ pub fn allocateSpecialSymbols(self: *MachO) !void {
14251425
1426const CreateAtomOpts = struct {1426const CreateAtomOpts = struct {
1427 size: u64 = 0,1427 size: u64 = 0,
1428 alignment: u32 = 0,1428 alignment: Alignment = .@"1",
1429};1429};
14301430
1431pub fn createAtom(self: *MachO, sym_index: u32, opts: CreateAtomOpts) !Atom.Index {1431pub fn createAtom(self: *MachO, sym_index: u32, opts: CreateAtomOpts) !Atom.Index {
...@@ -1473,7 +1473,7 @@ pub fn createTentativeDefAtoms(self: *MachO) !void {...@@ -1473,7 +1473,7 @@ pub fn createTentativeDefAtoms(self: *MachO) !void {
14731473
1474 const atom_index = try self.createAtom(global.sym_index, .{1474 const atom_index = try self.createAtom(global.sym_index, .{
1475 .size = size,1475 .size = size,
1476 .alignment = alignment,1476 .alignment = @enumFromInt(alignment),
1477 });1477 });
1478 const atom = self.getAtomPtr(atom_index);1478 const atom = self.getAtomPtr(atom_index);
1479 atom.file = global.file;1479 atom.file = global.file;
...@@ -1493,7 +1493,7 @@ pub fn createDyldPrivateAtom(self: *MachO) !void {...@@ -1493,7 +1493,7 @@ pub fn createDyldPrivateAtom(self: *MachO) !void {
1493 const sym_index = try self.allocateSymbol();1493 const sym_index = try self.allocateSymbol();
1494 const atom_index = try self.createAtom(sym_index, .{1494 const atom_index = try self.createAtom(sym_index, .{
1495 .size = @sizeOf(u64),1495 .size = @sizeOf(u64),
1496 .alignment = 3,1496 .alignment = .@"8",
1497 });1497 });
1498 try self.atom_by_index_table.putNoClobber(self.base.allocator, sym_index, atom_index);1498 try self.atom_by_index_table.putNoClobber(self.base.allocator, sym_index, atom_index);
14991499
...@@ -1510,7 +1510,7 @@ pub fn createDyldPrivateAtom(self: *MachO) !void {...@@ -1510,7 +1510,7 @@ pub fn createDyldPrivateAtom(self: *MachO) !void {
1510 switch (self.mode) {1510 switch (self.mode) {
1511 .zld => self.addAtomToSection(atom_index),1511 .zld => self.addAtomToSection(atom_index),
1512 .incremental => {1512 .incremental => {
1513 sym.n_value = try self.allocateAtom(atom_index, atom.size, @alignOf(u64));1513 sym.n_value = try self.allocateAtom(atom_index, atom.size, .@"8");
1514 log.debug("allocated dyld_private atom at 0x{x}", .{sym.n_value});1514 log.debug("allocated dyld_private atom at 0x{x}", .{sym.n_value});
1515 var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64);1515 var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64);
1516 try self.writeAtom(atom_index, &buffer);1516 try self.writeAtom(atom_index, &buffer);
...@@ -1521,7 +1521,7 @@ pub fn createDyldPrivateAtom(self: *MachO) !void {...@@ -1521,7 +1521,7 @@ pub fn createDyldPrivateAtom(self: *MachO) !void {
1521fn createThreadLocalDescriptorAtom(self: *MachO, sym_name: []const u8, target: SymbolWithLoc) !Atom.Index {1521fn createThreadLocalDescriptorAtom(self: *MachO, sym_name: []const u8, target: SymbolWithLoc) !Atom.Index {
1522 const gpa = self.base.allocator;1522 const gpa = self.base.allocator;
1523 const size = 3 * @sizeOf(u64);1523 const size = 3 * @sizeOf(u64);
1524 const required_alignment: u32 = 1;1524 const required_alignment: Alignment = .@"1";
1525 const sym_index = try self.allocateSymbol();1525 const sym_index = try self.allocateSymbol();
1526 const atom_index = try self.createAtom(sym_index, .{});1526 const atom_index = try self.createAtom(sym_index, .{});
1527 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index);1527 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index);
...@@ -2030,10 +2030,10 @@ fn shrinkAtom(self: *MachO, atom_index: Atom.Index, new_block_size: u64) void {...@@ -2030,10 +2030,10 @@ fn shrinkAtom(self: *MachO, atom_index: Atom.Index, new_block_size: u64) void {
2030 // capacity, insert a free list node for it.2030 // capacity, insert a free list node for it.
2031}2031}
20322032
2033fn growAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignment: u64) !u64 {2033fn growAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignment: Alignment) !u64 {
2034 const atom = self.getAtom(atom_index);2034 const atom = self.getAtom(atom_index);
2035 const sym = atom.getSymbol(self);2035 const sym = atom.getSymbol(self);
2036 const align_ok = mem.alignBackward(u64, sym.n_value, alignment) == sym.n_value;2036 const align_ok = alignment.check(sym.n_value);
2037 const need_realloc = !align_ok or new_atom_size > atom.capacity(self);2037 const need_realloc = !align_ok or new_atom_size > atom.capacity(self);
2038 if (!need_realloc) return sym.n_value;2038 if (!need_realloc) return sym.n_value;
2039 return self.allocateAtom(atom_index, new_atom_size, alignment);2039 return self.allocateAtom(atom_index, new_atom_size, alignment);
...@@ -2350,7 +2350,7 @@ fn updateLazySymbolAtom(...@@ -2350,7 +2350,7 @@ fn updateLazySymbolAtom(
2350 const gpa = self.base.allocator;2350 const gpa = self.base.allocator;
2351 const mod = self.base.options.module.?;2351 const mod = self.base.options.module.?;
23522352
2353 var required_alignment: u32 = undefined;2353 var required_alignment: Alignment = .none;
2354 var code_buffer = std.ArrayList(u8).init(gpa);2354 var code_buffer = std.ArrayList(u8).init(gpa);
2355 defer code_buffer.deinit();2355 defer code_buffer.deinit();
23562356
...@@ -2617,7 +2617,7 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64...@@ -2617,7 +2617,7 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64
2617 sym.n_desc = 0;2617 sym.n_desc = 0;
26182618
2619 const capacity = atom.capacity(self);2619 const capacity = atom.capacity(self);
2620 const need_realloc = code_len > capacity or !mem.isAlignedGeneric(u64, sym.n_value, required_alignment);2620 const need_realloc = code_len > capacity or !required_alignment.check(sym.n_value);
26212621
2622 if (need_realloc) {2622 if (need_realloc) {
2623 const vaddr = try self.growAtom(atom_index, code_len, required_alignment);2623 const vaddr = try self.growAtom(atom_index, code_len, required_alignment);
...@@ -3204,7 +3204,7 @@ pub fn addAtomToSection(self: *MachO, atom_index: Atom.Index) void {...@@ -3204,7 +3204,7 @@ pub fn addAtomToSection(self: *MachO, atom_index: Atom.Index) void {
3204 self.sections.set(sym.n_sect - 1, section);3204 self.sections.set(sym.n_sect - 1, section);
3205}3205}
32063206
3207fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignment: u64) !u64 {3207fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignment: Alignment) !u64 {
3208 const tracy = trace(@src());3208 const tracy = trace(@src());
3209 defer tracy.end();3209 defer tracy.end();
32103210
...@@ -3247,7 +3247,7 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm...@@ -3247,7 +3247,7 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm
3247 const ideal_capacity_end_vaddr = math.add(u64, sym.n_value, ideal_capacity) catch ideal_capacity;3247 const ideal_capacity_end_vaddr = math.add(u64, sym.n_value, ideal_capacity) catch ideal_capacity;
3248 const capacity_end_vaddr = sym.n_value + capacity;3248 const capacity_end_vaddr = sym.n_value + capacity;
3249 const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity;3249 const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity;
3250 const new_start_vaddr = mem.alignBackward(u64, new_start_vaddr_unaligned, alignment);3250 const new_start_vaddr = alignment.backward(new_start_vaddr_unaligned);
3251 if (new_start_vaddr < ideal_capacity_end_vaddr) {3251 if (new_start_vaddr < ideal_capacity_end_vaddr) {
3252 // Additional bookkeeping here to notice if this free list node3252 // Additional bookkeeping here to notice if this free list node
3253 // should be deleted because the atom that it points to has grown to take up3253 // should be deleted because the atom that it points to has grown to take up
...@@ -3276,11 +3276,11 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm...@@ -3276,11 +3276,11 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm
3276 const last_symbol = last.getSymbol(self);3276 const last_symbol = last.getSymbol(self);
3277 const ideal_capacity = if (requires_padding) padToIdeal(last.size) else last.size;3277 const ideal_capacity = if (requires_padding) padToIdeal(last.size) else last.size;
3278 const ideal_capacity_end_vaddr = last_symbol.n_value + ideal_capacity;3278 const ideal_capacity_end_vaddr = last_symbol.n_value + ideal_capacity;
3279 const new_start_vaddr = mem.alignForward(u64, ideal_capacity_end_vaddr, alignment);3279 const new_start_vaddr = alignment.forward(ideal_capacity_end_vaddr);
3280 atom_placement = last_index;3280 atom_placement = last_index;
3281 break :blk new_start_vaddr;3281 break :blk new_start_vaddr;
3282 } else {3282 } else {
3283 break :blk mem.alignForward(u64, segment.vmaddr, alignment);3283 break :blk alignment.forward(segment.vmaddr);
3284 }3284 }
3285 };3285 };
32863286
...@@ -3295,10 +3295,8 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm...@@ -3295,10 +3295,8 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm
3295 self.segment_table_dirty = true;3295 self.segment_table_dirty = true;
3296 }3296 }
32973297
3298 const align_pow = @as(u32, @intCast(math.log2(alignment)));3298 assert(alignment != .none);
3299 if (header.@"align" < align_pow) {3299 header.@"align" = @min(header.@"align", @intFromEnum(alignment));
3300 header.@"align" = align_pow;
3301 }
3302 self.getAtomPtr(atom_index).size = new_atom_size;3300 self.getAtomPtr(atom_index).size = new_atom_size;
33033301
3304 if (atom.prev_index) |prev_index| {3302 if (atom.prev_index) |prev_index| {
...@@ -3338,7 +3336,7 @@ pub fn getGlobalSymbol(self: *MachO, name: []const u8, lib_name: ?[]const u8) !u...@@ -3338,7 +3336,7 @@ pub fn getGlobalSymbol(self: *MachO, name: []const u8, lib_name: ?[]const u8) !u
33383336
3339pub fn writeSegmentHeaders(self: *MachO, writer: anytype) !void {3337pub fn writeSegmentHeaders(self: *MachO, writer: anytype) !void {
3340 for (self.segments.items, 0..) |seg, i| {3338 for (self.segments.items, 0..) |seg, i| {
3341 const indexes = self.getSectionIndexes(@as(u8, @intCast(i)));3339 const indexes = self.getSectionIndexes(@intCast(i));
3342 var out_seg = seg;3340 var out_seg = seg;
3343 out_seg.cmdsize = @sizeOf(macho.segment_command_64);3341 out_seg.cmdsize = @sizeOf(macho.segment_command_64);
3344 out_seg.nsects = 0;3342 out_seg.nsects = 0;
...@@ -5526,6 +5524,7 @@ const Trie = @import("MachO/Trie.zig");...@@ -5526,6 +5524,7 @@ const Trie = @import("MachO/Trie.zig");
5526const Type = @import("../type.zig").Type;5524const Type = @import("../type.zig").Type;
5527const TypedValue = @import("../TypedValue.zig");5525const TypedValue = @import("../TypedValue.zig");
5528const Value = @import("../value.zig").Value;5526const Value = @import("../value.zig").Value;
5527const Alignment = Atom.Alignment;
55295528
5530pub const DebugSymbols = @import("MachO/DebugSymbols.zig");5529pub const DebugSymbols = @import("MachO/DebugSymbols.zig");
5531pub const Bind = @import("MachO/dyld_info/bind.zig").Bind(*const MachO, SymbolWithLoc);5530pub const Bind = @import("MachO/dyld_info/bind.zig").Bind(*const MachO, SymbolWithLoc);
src/link/MachO/Atom.zig+3-1
...@@ -28,13 +28,15 @@ size: u64 = 0,...@@ -28,13 +28,15 @@ size: u64 = 0,
2828
29/// Alignment of this atom as a power of 2.29/// Alignment of this atom as a power of 2.
30/// For instance, aligmment of 0 should be read as 2^0 = 1 byte aligned.30/// For instance, aligmment of 0 should be read as 2^0 = 1 byte aligned.
31alignment: u32 = 0,31alignment: Alignment = .@"1",
3232
33/// Points to the previous and next neighbours33/// Points to the previous and next neighbours
34/// TODO use the same trick as with symbols: reserve index 0 as null atom34/// TODO use the same trick as with symbols: reserve index 0 as null atom
35next_index: ?Index = null,35next_index: ?Index = null,
36prev_index: ?Index = null,36prev_index: ?Index = null,
3737
38pub const Alignment = @import("../../InternPool.zig").Alignment;
39
38pub const Index = u32;40pub const Index = u32;
3941
40pub const Binding = struct {42pub const Binding = struct {
src/link/MachO/Object.zig+12-8
...@@ -382,7 +382,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) !...@@ -382,7 +382,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) !
382 const out_sect_id = (try Atom.getOutputSection(macho_file, sect)) orelse continue;382 const out_sect_id = (try Atom.getOutputSection(macho_file, sect)) orelse continue;
383 if (sect.size == 0) continue;383 if (sect.size == 0) continue;
384384
385 const sect_id = @as(u8, @intCast(id));385 const sect_id: u8 = @intCast(id);
386 const sym_index = self.getSectionAliasSymbolIndex(sect_id);386 const sym_index = self.getSectionAliasSymbolIndex(sect_id);
387 const atom_index = try self.createAtomFromSubsection(387 const atom_index = try self.createAtomFromSubsection(
388 macho_file,388 macho_file,
...@@ -391,7 +391,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) !...@@ -391,7 +391,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) !
391 sym_index,391 sym_index,
392 1,392 1,
393 sect.size,393 sect.size,
394 sect.@"align",394 Alignment.fromLog2Units(sect.@"align"),
395 out_sect_id,395 out_sect_id,
396 );396 );
397 macho_file.addAtomToSection(atom_index);397 macho_file.addAtomToSection(atom_index);
...@@ -470,7 +470,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) !...@@ -470,7 +470,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) !
470 sym_index,470 sym_index,
471 1,471 1,
472 atom_size,472 atom_size,
473 sect.@"align",473 Alignment.fromLog2Units(sect.@"align"),
474 out_sect_id,474 out_sect_id,
475 );475 );
476 if (!sect.isZerofill()) {476 if (!sect.isZerofill()) {
...@@ -494,10 +494,10 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) !...@@ -494,10 +494,10 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) !
494 else494 else
495 sect.addr + sect.size - addr;495 sect.addr + sect.size - addr;
496496
497 const atom_align = if (addr > 0)497 const atom_align = Alignment.fromLog2Units(if (addr > 0)
498 @min(@ctz(addr), sect.@"align")498 @min(@ctz(addr), sect.@"align")
499 else499 else
500 sect.@"align";500 sect.@"align");
501501
502 const atom_index = try self.createAtomFromSubsection(502 const atom_index = try self.createAtomFromSubsection(
503 macho_file,503 macho_file,
...@@ -532,7 +532,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) !...@@ -532,7 +532,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) !
532 sect_start_index,532 sect_start_index,
533 sect_loc.len,533 sect_loc.len,
534 sect.size,534 sect.size,
535 sect.@"align",535 Alignment.fromLog2Units(sect.@"align"),
536 out_sect_id,536 out_sect_id,
537 );537 );
538 if (!sect.isZerofill()) {538 if (!sect.isZerofill()) {
...@@ -551,11 +551,14 @@ fn createAtomFromSubsection(...@@ -551,11 +551,14 @@ fn createAtomFromSubsection(
551 inner_sym_index: u32,551 inner_sym_index: u32,
552 inner_nsyms_trailing: u32,552 inner_nsyms_trailing: u32,
553 size: u64,553 size: u64,
554 alignment: u32,554 alignment: Alignment,
555 out_sect_id: u8,555 out_sect_id: u8,
556) !Atom.Index {556) !Atom.Index {
557 const gpa = macho_file.base.allocator;557 const gpa = macho_file.base.allocator;
558 const atom_index = try macho_file.createAtom(sym_index, .{ .size = size, .alignment = alignment });558 const atom_index = try macho_file.createAtom(sym_index, .{
559 .size = size,
560 .alignment = alignment,
561 });
559 const atom = macho_file.getAtomPtr(atom_index);562 const atom = macho_file.getAtomPtr(atom_index);
560 atom.inner_sym_index = inner_sym_index;563 atom.inner_sym_index = inner_sym_index;
561 atom.inner_nsyms_trailing = inner_nsyms_trailing;564 atom.inner_nsyms_trailing = inner_nsyms_trailing;
...@@ -1115,3 +1118,4 @@ const MachO = @import("../MachO.zig");...@@ -1115,3 +1118,4 @@ const MachO = @import("../MachO.zig");
1115const Platform = @import("load_commands.zig").Platform;1118const Platform = @import("load_commands.zig").Platform;
1116const SymbolWithLoc = MachO.SymbolWithLoc;1119const SymbolWithLoc = MachO.SymbolWithLoc;
1117const UnwindInfo = @import("UnwindInfo.zig");1120const UnwindInfo = @import("UnwindInfo.zig");
1121const Alignment = Atom.Alignment;
src/link/MachO/thunks.zig+7-4
...@@ -104,7 +104,7 @@ pub fn createThunks(macho_file: *MachO, sect_id: u8) !void {...@@ -104,7 +104,7 @@ pub fn createThunks(macho_file: *MachO, sect_id: u8) !void {
104104
105 while (true) {105 while (true) {
106 const atom = macho_file.getAtom(group_end);106 const atom = macho_file.getAtom(group_end);
107 offset = mem.alignForward(u64, offset, try math.powi(u32, 2, atom.alignment));107 offset = atom.alignment.forward(offset);
108108
109 const sym = macho_file.getSymbolPtr(atom.getSymbolWithLoc());109 const sym = macho_file.getSymbolPtr(atom.getSymbolWithLoc());
110 sym.n_value = offset;110 sym.n_value = offset;
...@@ -112,7 +112,7 @@ pub fn createThunks(macho_file: *MachO, sect_id: u8) !void {...@@ -112,7 +112,7 @@ pub fn createThunks(macho_file: *MachO, sect_id: u8) !void {
112112
113 macho_file.logAtom(group_end, log);113 macho_file.logAtom(group_end, log);
114114
115 header.@"align" = @max(header.@"align", atom.alignment);115 header.@"align" = @max(header.@"align", atom.alignment.toLog2Units());
116116
117 allocated.putAssumeCapacityNoClobber(group_end, {});117 allocated.putAssumeCapacityNoClobber(group_end, {});
118118
...@@ -196,7 +196,7 @@ fn allocateThunk(...@@ -196,7 +196,7 @@ fn allocateThunk(
196196
197 macho_file.logAtom(atom_index, log);197 macho_file.logAtom(atom_index, log);
198198
199 header.@"align" = @max(header.@"align", atom.alignment);199 header.@"align" = @max(header.@"align", atom.alignment.toLog2Units());
200200
201 if (end_atom_index == atom_index) break;201 if (end_atom_index == atom_index) break;
202202
...@@ -326,7 +326,10 @@ fn isReachable(...@@ -326,7 +326,10 @@ fn isReachable(
326326
327fn createThunkAtom(macho_file: *MachO) !Atom.Index {327fn createThunkAtom(macho_file: *MachO) !Atom.Index {
328 const sym_index = try macho_file.allocateSymbol();328 const sym_index = try macho_file.allocateSymbol();
329 const atom_index = try macho_file.createAtom(sym_index, .{ .size = @sizeOf(u32) * 3, .alignment = 2 });329 const atom_index = try macho_file.createAtom(sym_index, .{
330 .size = @sizeOf(u32) * 3,
331 .alignment = .@"4",
332 });
330 const sym = macho_file.getSymbolPtr(.{ .sym_index = sym_index });333 const sym = macho_file.getSymbolPtr(.{ .sym_index = sym_index });
331 sym.n_type = macho.N_SECT;334 sym.n_type = macho.N_SECT;
332 sym.n_sect = macho_file.text_section_index.? + 1;335 sym.n_sect = macho_file.text_section_index.? + 1;
src/link/MachO/zld.zig+3-6
...@@ -985,19 +985,16 @@ fn calcSectionSizes(macho_file: *MachO) !void {...@@ -985,19 +985,16 @@ fn calcSectionSizes(macho_file: *MachO) !void {
985985
986 while (true) {986 while (true) {
987 const atom = macho_file.getAtom(atom_index);987 const atom = macho_file.getAtom(atom_index);
988 const atom_alignment = try math.powi(u32, 2, atom.alignment);988 const atom_offset = atom.alignment.forward(header.size);
989 const atom_offset = mem.alignForward(u64, header.size, atom_alignment);
990 const padding = atom_offset - header.size;989 const padding = atom_offset - header.size;
991990
992 const sym = macho_file.getSymbolPtr(atom.getSymbolWithLoc());991 const sym = macho_file.getSymbolPtr(atom.getSymbolWithLoc());
993 sym.n_value = atom_offset;992 sym.n_value = atom_offset;
994993
995 header.size += padding + atom.size;994 header.size += padding + atom.size;
996 header.@"align" = @max(header.@"align", atom.alignment);995 header.@"align" = @max(header.@"align", atom.alignment.toLog2Units());
997996
998 if (atom.next_index) |next_index| {997 atom_index = atom.next_index orelse break;
999 atom_index = next_index;
1000 } else break;
1001 }998 }
1002 }999 }
10031000
src/link/Plan9.zig+1-1
...@@ -1106,7 +1106,7 @@ fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Ind...@@ -1106,7 +1106,7 @@ fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Ind
1106 const gpa = self.base.allocator;1106 const gpa = self.base.allocator;
1107 const mod = self.base.options.module.?;1107 const mod = self.base.options.module.?;
11081108
1109 var required_alignment: u32 = undefined;1109 var required_alignment: InternPool.Alignment = .none;
1110 var code_buffer = std.ArrayList(u8).init(gpa);1110 var code_buffer = std.ArrayList(u8).init(gpa);
1111 defer code_buffer.deinit();1111 defer code_buffer.deinit();
11121112
src/link/Wasm.zig+23-21
...@@ -187,8 +187,10 @@ debug_pubtypes_atom: ?Atom.Index = null,...@@ -187,8 +187,10 @@ debug_pubtypes_atom: ?Atom.Index = null,
187/// rather than by the linker.187/// rather than by the linker.
188synthetic_functions: std.ArrayListUnmanaged(Atom.Index) = .{},188synthetic_functions: std.ArrayListUnmanaged(Atom.Index) = .{},
189189
190pub const Alignment = types.Alignment;
191
190pub const Segment = struct {192pub const Segment = struct {
191 alignment: u32,193 alignment: Alignment,
192 size: u32,194 size: u32,
193 offset: u32,195 offset: u32,
194 flags: u32,196 flags: u32,
...@@ -1490,7 +1492,7 @@ fn finishUpdateDecl(wasm: *Wasm, decl_index: Module.Decl.Index, code: []const u8...@@ -1490,7 +1492,7 @@ fn finishUpdateDecl(wasm: *Wasm, decl_index: Module.Decl.Index, code: []const u8
1490 try atom.code.appendSlice(wasm.base.allocator, code);1492 try atom.code.appendSlice(wasm.base.allocator, code);
1491 try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {});1493 try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {});
14921494
1493 atom.size = @as(u32, @intCast(code.len));1495 atom.size = @intCast(code.len);
1494 if (code.len == 0) return;1496 if (code.len == 0) return;
1495 atom.alignment = decl.getAlignment(mod);1497 atom.alignment = decl.getAlignment(mod);
1496}1498}
...@@ -2050,7 +2052,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {...@@ -2050,7 +2052,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
2050 };2052 };
20512053
2052 const segment: *Segment = &wasm.segments.items[final_index];2054 const segment: *Segment = &wasm.segments.items[final_index];
2053 segment.alignment = @max(segment.alignment, atom.alignment);2055 segment.alignment = segment.alignment.max(atom.alignment);
20542056
2055 try wasm.appendAtomAtIndex(final_index, atom_index);2057 try wasm.appendAtomAtIndex(final_index, atom_index);
2056}2058}
...@@ -2121,7 +2123,7 @@ fn allocateAtoms(wasm: *Wasm) !void {...@@ -2121,7 +2123,7 @@ fn allocateAtoms(wasm: *Wasm) !void {
2121 }2123 }
2122 }2124 }
2123 }2125 }
2124 offset = std.mem.alignForward(u32, offset, atom.alignment);2126 offset = @intCast(atom.alignment.forward(offset));
2125 atom.offset = offset;2127 atom.offset = offset;
2126 log.debug("Atom '{s}' allocated from 0x{x:0>8} to 0x{x:0>8} size={d}", .{2128 log.debug("Atom '{s}' allocated from 0x{x:0>8} to 0x{x:0>8} size={d}", .{
2127 symbol_loc.getName(wasm),2129 symbol_loc.getName(wasm),
...@@ -2132,7 +2134,7 @@ fn allocateAtoms(wasm: *Wasm) !void {...@@ -2132,7 +2134,7 @@ fn allocateAtoms(wasm: *Wasm) !void {
2132 offset += atom.size;2134 offset += atom.size;
2133 atom_index = atom.prev orelse break;2135 atom_index = atom.prev orelse break;
2134 }2136 }
2135 segment.size = std.mem.alignForward(u32, offset, segment.alignment);2137 segment.size = @intCast(segment.alignment.forward(offset));
2136 }2138 }
2137}2139}
21382140
...@@ -2351,7 +2353,7 @@ fn createSyntheticFunction(...@@ -2351,7 +2353,7 @@ fn createSyntheticFunction(
2351 .offset = 0,2353 .offset = 0,
2352 .sym_index = loc.index,2354 .sym_index = loc.index,
2353 .file = null,2355 .file = null,
2354 .alignment = 1,2356 .alignment = .@"1",
2355 .next = null,2357 .next = null,
2356 .prev = null,2358 .prev = null,
2357 .code = function_body.moveToUnmanaged(),2359 .code = function_body.moveToUnmanaged(),
...@@ -2382,11 +2384,11 @@ pub fn createFunction(...@@ -2382,11 +2384,11 @@ pub fn createFunction(
2382 const atom_index = @as(Atom.Index, @intCast(wasm.managed_atoms.items.len));2384 const atom_index = @as(Atom.Index, @intCast(wasm.managed_atoms.items.len));
2383 const atom = try wasm.managed_atoms.addOne(wasm.base.allocator);2385 const atom = try wasm.managed_atoms.addOne(wasm.base.allocator);
2384 atom.* = .{2386 atom.* = .{
2385 .size = @as(u32, @intCast(function_body.items.len)),2387 .size = @intCast(function_body.items.len),
2386 .offset = 0,2388 .offset = 0,
2387 .sym_index = loc.index,2389 .sym_index = loc.index,
2388 .file = null,2390 .file = null,
2389 .alignment = 1,2391 .alignment = .@"1",
2390 .next = null,2392 .next = null,
2391 .prev = null,2393 .prev = null,
2392 .code = function_body.moveToUnmanaged(),2394 .code = function_body.moveToUnmanaged(),
...@@ -2734,8 +2736,8 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2734,8 +2736,8 @@ fn setupMemory(wasm: *Wasm) !void {
2734 const page_size = std.wasm.page_size; // 64kb2736 const page_size = std.wasm.page_size; // 64kb
2735 // Use the user-provided stack size or else we use 1MB by default2737 // Use the user-provided stack size or else we use 1MB by default
2736 const stack_size = wasm.base.options.stack_size_override orelse page_size * 16;2738 const stack_size = wasm.base.options.stack_size_override orelse page_size * 16;
2737 const stack_alignment = 16; // wasm's stack alignment as specified by tool-convention2739 const stack_alignment: Alignment = .@"16"; // wasm's stack alignment as specified by tool-convention
2738 const heap_alignment = 16; // wasm's heap alignment as specified by tool-convention2740 const heap_alignment: Alignment = .@"16"; // wasm's heap alignment as specified by tool-convention
27392741
2740 // Always place the stack at the start by default2742 // Always place the stack at the start by default
2741 // unless the user specified the global-base flag2743 // unless the user specified the global-base flag
...@@ -2748,7 +2750,7 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2748,7 +2750,7 @@ fn setupMemory(wasm: *Wasm) !void {
2748 const is_obj = wasm.base.options.output_mode == .Obj;2750 const is_obj = wasm.base.options.output_mode == .Obj;
27492751
2750 if (place_stack_first and !is_obj) {2752 if (place_stack_first and !is_obj) {
2751 memory_ptr = std.mem.alignForward(u64, memory_ptr, stack_alignment);2753 memory_ptr = stack_alignment.forward(memory_ptr);
2752 memory_ptr += stack_size;2754 memory_ptr += stack_size;
2753 // We always put the stack pointer global at index 02755 // We always put the stack pointer global at index 0
2754 wasm.wasm_globals.items[0].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr))));2756 wasm.wasm_globals.items[0].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr))));
...@@ -2758,7 +2760,7 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2758,7 +2760,7 @@ fn setupMemory(wasm: *Wasm) !void {
2758 var data_seg_it = wasm.data_segments.iterator();2760 var data_seg_it = wasm.data_segments.iterator();
2759 while (data_seg_it.next()) |entry| {2761 while (data_seg_it.next()) |entry| {
2760 const segment = &wasm.segments.items[entry.value_ptr.*];2762 const segment = &wasm.segments.items[entry.value_ptr.*];
2761 memory_ptr = std.mem.alignForward(u64, memory_ptr, segment.alignment);2763 memory_ptr = segment.alignment.forward(memory_ptr);
27622764
2763 // set TLS-related symbols2765 // set TLS-related symbols
2764 if (mem.eql(u8, entry.key_ptr.*, ".tdata")) {2766 if (mem.eql(u8, entry.key_ptr.*, ".tdata")) {
...@@ -2768,7 +2770,7 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2768,7 +2770,7 @@ fn setupMemory(wasm: *Wasm) !void {
2768 }2770 }
2769 if (wasm.findGlobalSymbol("__tls_align")) |loc| {2771 if (wasm.findGlobalSymbol("__tls_align")) |loc| {
2770 const sym = loc.getSymbol(wasm);2772 const sym = loc.getSymbol(wasm);
2771 wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.alignment);2773 wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.alignment.toByteUnitsOptional().?);
2772 }2774 }
2773 if (wasm.findGlobalSymbol("__tls_base")) |loc| {2775 if (wasm.findGlobalSymbol("__tls_base")) |loc| {
2774 const sym = loc.getSymbol(wasm);2776 const sym = loc.getSymbol(wasm);
...@@ -2795,7 +2797,7 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2795,7 +2797,7 @@ fn setupMemory(wasm: *Wasm) !void {
2795 }2797 }
27962798
2797 if (!place_stack_first and !is_obj) {2799 if (!place_stack_first and !is_obj) {
2798 memory_ptr = std.mem.alignForward(u64, memory_ptr, stack_alignment);2800 memory_ptr = stack_alignment.forward(memory_ptr);
2799 memory_ptr += stack_size;2801 memory_ptr += stack_size;
2800 wasm.wasm_globals.items[0].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr))));2802 wasm.wasm_globals.items[0].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr))));
2801 }2803 }
...@@ -2804,7 +2806,7 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2804,7 +2806,7 @@ fn setupMemory(wasm: *Wasm) !void {
2804 // We must set its virtual address so it can be used in relocations.2806 // We must set its virtual address so it can be used in relocations.
2805 if (wasm.findGlobalSymbol("__heap_base")) |loc| {2807 if (wasm.findGlobalSymbol("__heap_base")) |loc| {
2806 const symbol = loc.getSymbol(wasm);2808 const symbol = loc.getSymbol(wasm);
2807 symbol.virtual_address = @as(u32, @intCast(mem.alignForward(u64, memory_ptr, heap_alignment)));2809 symbol.virtual_address = @intCast(heap_alignment.forward(memory_ptr));
2808 }2810 }
28092811
2810 // Setup the max amount of pages2812 // Setup the max amount of pages
...@@ -2879,7 +2881,7 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32...@@ -2879,7 +2881,7 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32
2879 flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE);2881 flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE);
2880 }2882 }
2881 try wasm.segments.append(wasm.base.allocator, .{2883 try wasm.segments.append(wasm.base.allocator, .{
2882 .alignment = 1,2884 .alignment = .@"1",
2883 .size = 0,2885 .size = 0,
2884 .offset = 0,2886 .offset = 0,
2885 .flags = flags,2887 .flags = flags,
...@@ -2954,7 +2956,7 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32...@@ -2954,7 +2956,7 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32
2954/// Appends a new segment with default field values2956/// Appends a new segment with default field values
2955fn appendDummySegment(wasm: *Wasm) !void {2957fn appendDummySegment(wasm: *Wasm) !void {
2956 try wasm.segments.append(wasm.base.allocator, .{2958 try wasm.segments.append(wasm.base.allocator, .{
2957 .alignment = 1,2959 .alignment = .@"1",
2958 .size = 0,2960 .size = 0,
2959 .offset = 0,2961 .offset = 0,
2960 .flags = 0,2962 .flags = 0,
...@@ -3011,7 +3013,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void {...@@ -3011,7 +3013,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void {
3011 // the pointers into the list using addends which are appended to the relocation.3013 // the pointers into the list using addends which are appended to the relocation.
3012 const names_atom_index = try wasm.createAtom();3014 const names_atom_index = try wasm.createAtom();
3013 const names_atom = wasm.getAtomPtr(names_atom_index);3015 const names_atom = wasm.getAtomPtr(names_atom_index);
3014 names_atom.alignment = 1;3016 names_atom.alignment = .@"1";
3015 const sym_name = try wasm.string_table.put(wasm.base.allocator, "__zig_err_names");3017 const sym_name = try wasm.string_table.put(wasm.base.allocator, "__zig_err_names");
3016 const names_symbol = &wasm.symbols.items[names_atom.sym_index];3018 const names_symbol = &wasm.symbols.items[names_atom.sym_index];
3017 names_symbol.* = .{3019 names_symbol.* = .{
...@@ -3085,7 +3087,7 @@ pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) !...@@ -3085,7 +3087,7 @@ pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) !
3085 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),3087 .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
3086 };3088 };
30873089
3088 atom.alignment = 1; // debug sections are always 1-byte-aligned3090 atom.alignment = .@"1"; // debug sections are always 1-byte-aligned
3089 return atom_index;3091 return atom_index;
3090}3092}
30913093
...@@ -4724,12 +4726,12 @@ fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.ArrayList(u8)) !void {...@@ -4724,12 +4726,12 @@ fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.ArrayList(u8)) !void {
4724 for (wasm.segment_info.values()) |segment_info| {4726 for (wasm.segment_info.values()) |segment_info| {
4725 log.debug("Emit segment: {s} align({d}) flags({b})", .{4727 log.debug("Emit segment: {s} align({d}) flags({b})", .{
4726 segment_info.name,4728 segment_info.name,
4727 @ctz(segment_info.alignment),4729 segment_info.alignment,
4728 segment_info.flags,4730 segment_info.flags,
4729 });4731 });
4730 try leb.writeULEB128(writer, @as(u32, @intCast(segment_info.name.len)));4732 try leb.writeULEB128(writer, @as(u32, @intCast(segment_info.name.len)));
4731 try writer.writeAll(segment_info.name);4733 try writer.writeAll(segment_info.name);
4732 try leb.writeULEB128(writer, @ctz(segment_info.alignment));4734 try leb.writeULEB128(writer, segment_info.alignment.toLog2Units());
4733 try leb.writeULEB128(writer, segment_info.flags);4735 try leb.writeULEB128(writer, segment_info.flags);
4734 }4736 }
47354737
src/link/Wasm/Atom.zig+2-2
...@@ -19,7 +19,7 @@ relocs: std.ArrayListUnmanaged(types.Relocation) = .{},...@@ -19,7 +19,7 @@ relocs: std.ArrayListUnmanaged(types.Relocation) = .{},
19/// Contains the binary data of an atom, which can be non-relocated19/// Contains the binary data of an atom, which can be non-relocated
20code: std.ArrayListUnmanaged(u8) = .{},20code: std.ArrayListUnmanaged(u8) = .{},
21/// For code this is 1, for data this is set to the highest value of all segments21/// For code this is 1, for data this is set to the highest value of all segments
22alignment: u32,22alignment: Wasm.Alignment,
23/// Offset into the section where the atom lives, this already accounts23/// Offset into the section where the atom lives, this already accounts
24/// for alignment.24/// for alignment.
25offset: u32,25offset: u32,
...@@ -43,7 +43,7 @@ pub const Index = u32;...@@ -43,7 +43,7 @@ pub const Index = u32;
4343
44/// Represents a default empty wasm `Atom`44/// Represents a default empty wasm `Atom`
45pub const empty: Atom = .{45pub const empty: Atom = .{
46 .alignment = 1,46 .alignment = .@"1",
47 .file = null,47 .file = null,
48 .next = null,48 .next = null,
49 .offset = 0,49 .offset = 0,
src/link/Wasm/Object.zig+7-9
...@@ -8,6 +8,7 @@ const types = @import("types.zig");...@@ -8,6 +8,7 @@ const types = @import("types.zig");
8const std = @import("std");8const std = @import("std");
9const Wasm = @import("../Wasm.zig");9const Wasm = @import("../Wasm.zig");
10const Symbol = @import("Symbol.zig");10const Symbol = @import("Symbol.zig");
11const Alignment = types.Alignment;
1112
12const Allocator = std.mem.Allocator;13const Allocator = std.mem.Allocator;
13const leb = std.leb;14const leb = std.leb;
...@@ -88,12 +89,9 @@ const RelocatableData = struct {...@@ -88,12 +89,9 @@ const RelocatableData = struct {
88 /// meta data of the given object file.89 /// meta data of the given object file.
89 /// NOTE: Alignment is encoded as a power of 2, so we shift the symbol's90 /// NOTE: Alignment is encoded as a power of 2, so we shift the symbol's
90 /// alignment to retrieve the natural alignment.91 /// alignment to retrieve the natural alignment.
91 pub fn getAlignment(relocatable_data: RelocatableData, object: *const Object) u32 {92 pub fn getAlignment(relocatable_data: RelocatableData, object: *const Object) Alignment {
92 if (relocatable_data.type != .data) return 1;93 if (relocatable_data.type != .data) return .@"1";
93 const data_alignment = object.segment_info[relocatable_data.index].alignment;94 return object.segment_info[relocatable_data.index].alignment;
94 if (data_alignment == 0) return 1;
95 // Decode from power of 2 to natural alignment
96 return @as(u32, 1) << @as(u5, @intCast(data_alignment));
97 }95 }
9896
99 /// Returns the symbol kind that corresponds to the relocatable section97 /// Returns the symbol kind that corresponds to the relocatable section
...@@ -671,7 +669,7 @@ fn Parser(comptime ReaderType: type) type {...@@ -671,7 +669,7 @@ fn Parser(comptime ReaderType: type) type {
671 try reader.readNoEof(name);669 try reader.readNoEof(name);
672 segment.* = .{670 segment.* = .{
673 .name = name,671 .name = name,
674 .alignment = try leb.readULEB128(u32, reader),672 .alignment = @enumFromInt(try leb.readULEB128(u32, reader)),
675 .flags = try leb.readULEB128(u32, reader),673 .flags = try leb.readULEB128(u32, reader),
676 };674 };
677 log.debug("Found segment: {s} align({d}) flags({b})", .{675 log.debug("Found segment: {s} align({d}) flags({b})", .{
...@@ -919,7 +917,7 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b...@@ -919,7 +917,7 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b
919 continue; // found unknown section, so skip parsing into atom as we do not know how to handle it.917 continue; // found unknown section, so skip parsing into atom as we do not know how to handle it.
920 };918 };
921919
922 const atom_index = @as(Atom.Index, @intCast(wasm_bin.managed_atoms.items.len));920 const atom_index: Atom.Index = @intCast(wasm_bin.managed_atoms.items.len);
923 const atom = try wasm_bin.managed_atoms.addOne(gpa);921 const atom = try wasm_bin.managed_atoms.addOne(gpa);
924 atom.* = Atom.empty;922 atom.* = Atom.empty;
925 atom.file = object_index;923 atom.file = object_index;
...@@ -984,7 +982,7 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b...@@ -984,7 +982,7 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b
984982
985 const segment: *Wasm.Segment = &wasm_bin.segments.items[final_index];983 const segment: *Wasm.Segment = &wasm_bin.segments.items[final_index];
986 if (relocatable_data.type == .data) { //code section and debug sections are 1-byte aligned984 if (relocatable_data.type == .data) { //code section and debug sections are 1-byte aligned
987 segment.alignment = @max(segment.alignment, atom.alignment);985 segment.alignment = segment.alignment.max(atom.alignment);
988 }986 }
989987
990 try wasm_bin.appendAtomAtIndex(final_index, atom_index);988 try wasm_bin.appendAtomAtIndex(final_index, atom_index);
src/link/Wasm/types.zig+3-1
...@@ -109,11 +109,13 @@ pub const SubsectionType = enum(u8) {...@@ -109,11 +109,13 @@ pub const SubsectionType = enum(u8) {
109 WASM_SYMBOL_TABLE = 8,109 WASM_SYMBOL_TABLE = 8,
110};110};
111111
112pub const Alignment = @import("../../InternPool.zig").Alignment;
113
112pub const Segment = struct {114pub const Segment = struct {
113 /// Segment's name, encoded as UTF-8 bytes.115 /// Segment's name, encoded as UTF-8 bytes.
114 name: []const u8,116 name: []const u8,
115 /// The required alignment of the segment, encoded as a power of 2117 /// The required alignment of the segment, encoded as a power of 2
116 alignment: u32,118 alignment: Alignment,
117 /// Bitfield containing flags for a segment119 /// Bitfield containing flags for a segment
118 flags: u32,120 flags: u32,
119121
src/target.zig+7-6
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const std = @import("std");1const std = @import("std");
2const Type = @import("type.zig").Type;2const Type = @import("type.zig").Type;
3const AddressSpace = std.builtin.AddressSpace;3const AddressSpace = std.builtin.AddressSpace;
4const Alignment = @import("InternPool.zig").Alignment;
45
5pub const ArchOsAbi = struct {6pub const ArchOsAbi = struct {
6 arch: std.Target.Cpu.Arch,7 arch: std.Target.Cpu.Arch,
...@@ -595,13 +596,13 @@ pub fn llvmMachineAbi(target: std.Target) ?[:0]const u8 {...@@ -595,13 +596,13 @@ pub fn llvmMachineAbi(target: std.Target) ?[:0]const u8 {
595}596}
596597
597/// This function returns 1 if function alignment is not observable or settable.598/// This function returns 1 if function alignment is not observable or settable.
598pub fn defaultFunctionAlignment(target: std.Target) u32 {599pub fn defaultFunctionAlignment(target: std.Target) Alignment {
599 return switch (target.cpu.arch) {600 return switch (target.cpu.arch) {
600 .arm, .armeb => 4,601 .arm, .armeb => .@"4",
601 .aarch64, .aarch64_32, .aarch64_be => 4,602 .aarch64, .aarch64_32, .aarch64_be => .@"4",
602 .sparc, .sparcel, .sparc64 => 4,603 .sparc, .sparcel, .sparc64 => .@"4",
603 .riscv64 => 2,604 .riscv64 => .@"2",
604 else => 1,605 else => .@"1",
605 };606 };
606}607}
607608
src/type.zig+265-402
...@@ -9,6 +9,7 @@ const target_util = @import("target.zig");...@@ -9,6 +9,7 @@ const target_util = @import("target.zig");
9const TypedValue = @import("TypedValue.zig");9const TypedValue = @import("TypedValue.zig");
10const Sema = @import("Sema.zig");10const Sema = @import("Sema.zig");
11const InternPool = @import("InternPool.zig");11const InternPool = @import("InternPool.zig");
12const Alignment = InternPool.Alignment;
1213
13/// Both types and values are canonically represented by a single 32-bit integer14/// Both types and values are canonically represented by a single 32-bit integer
14/// which is an index into an `InternPool` data structure.15/// which is an index into an `InternPool` data structure.
...@@ -196,9 +197,11 @@ pub const Type = struct {...@@ -196,9 +197,11 @@ pub const Type = struct {
196 info.packed_offset.host_size != 0 or197 info.packed_offset.host_size != 0 or
197 info.flags.vector_index != .none)198 info.flags.vector_index != .none)
198 {199 {
199 const alignment = info.flags.alignment.toByteUnitsOptional() orelse200 const alignment = if (info.flags.alignment != .none)
201 info.flags.alignment
202 else
200 info.child.toType().abiAlignment(mod);203 info.child.toType().abiAlignment(mod);
201 try writer.print("align({d}", .{alignment});204 try writer.print("align({d}", .{alignment.toByteUnits(0)});
202205
203 if (info.packed_offset.bit_offset != 0 or info.packed_offset.host_size != 0) {206 if (info.packed_offset.bit_offset != 0 or info.packed_offset.host_size != 0) {
204 try writer.print(":{d}:{d}", .{207 try writer.print(":{d}:{d}", .{
...@@ -315,8 +318,8 @@ pub const Type = struct {...@@ -315,8 +318,8 @@ pub const Type = struct {
315 .generic_poison => unreachable,318 .generic_poison => unreachable,
316 },319 },
317 .struct_type => |struct_type| {320 .struct_type => |struct_type| {
318 if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| {321 if (struct_type.decl.unwrap()) |decl_index| {
319 const decl = mod.declPtr(struct_obj.owner_decl);322 const decl = mod.declPtr(decl_index);
320 try decl.renderFullyQualifiedName(mod, writer);323 try decl.renderFullyQualifiedName(mod, writer);
321 } else if (struct_type.namespace.unwrap()) |namespace_index| {324 } else if (struct_type.namespace.unwrap()) |namespace_index| {
322 const namespace = mod.namespacePtr(namespace_index);325 const namespace = mod.namespacePtr(namespace_index);
...@@ -561,24 +564,20 @@ pub const Type = struct {...@@ -561,24 +564,20 @@ pub const Type = struct {
561 .generic_poison => unreachable,564 .generic_poison => unreachable,
562 },565 },
563 .struct_type => |struct_type| {566 .struct_type => |struct_type| {
564 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse {567 if (struct_type.assumeRuntimeBitsIfFieldTypesWip(ip)) {
565 // This struct has no fields.
566 return false;
567 };
568 if (struct_obj.status == .field_types_wip) {
569 // In this case, we guess that hasRuntimeBits() for this type is true,568 // In this case, we guess that hasRuntimeBits() for this type is true,
570 // and then later if our guess was incorrect, we emit a compile error.569 // and then later if our guess was incorrect, we emit a compile error.
571 struct_obj.assumed_runtime_bits = true;
572 return true;570 return true;
573 }571 }
574 switch (strat) {572 switch (strat) {
575 .sema => |sema| _ = try sema.resolveTypeFields(ty),573 .sema => |sema| _ = try sema.resolveTypeFields(ty),
576 .eager => assert(struct_obj.haveFieldTypes()),574 .eager => assert(struct_type.haveFieldTypes(ip)),
577 .lazy => if (!struct_obj.haveFieldTypes()) return error.NeedLazy,575 .lazy => if (!struct_type.haveFieldTypes(ip)) return error.NeedLazy,
578 }576 }
579 for (struct_obj.fields.values()) |field| {577 for (0..struct_type.field_types.len) |i| {
580 if (field.is_comptime) continue;578 if (struct_type.comptime_bits.getBit(ip, i)) continue;
581 if (try field.ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat))579 const field_ty = struct_type.field_types.get(ip)[i].toType();
580 if (try field_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat))
582 return true;581 return true;
583 } else {582 } else {
584 return false;583 return false;
...@@ -728,11 +727,8 @@ pub const Type = struct {...@@ -728,11 +727,8 @@ pub const Type = struct {
728 => false,727 => false,
729 },728 },
730 .struct_type => |struct_type| {729 .struct_type => |struct_type| {
731 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse {730 // Struct with no fields have a well-defined layout of no bits.
732 // Struct with no fields has a well-defined layout of no bits.731 return struct_type.layout != .Auto or struct_type.field_types.len == 0;
733 return true;
734 };
735 return struct_obj.layout != .Auto;
736 },732 },
737 .union_type => |union_type| switch (union_type.flagsPtr(ip).runtime_tag) {733 .union_type => |union_type| switch (union_type.flagsPtr(ip).runtime_tag) {
738 .none, .safety => union_type.flagsPtr(ip).layout != .Auto,734 .none, .safety => union_type.flagsPtr(ip).layout != .Auto,
...@@ -806,22 +802,23 @@ pub const Type = struct {...@@ -806,22 +802,23 @@ pub const Type = struct {
806 return mod.intern_pool.isNoReturn(ty.toIntern());802 return mod.intern_pool.isNoReturn(ty.toIntern());
807 }803 }
808804
809 /// Returns 0 if the pointer is naturally aligned and the element type is 0-bit.805 /// Returns `none` if the pointer is naturally aligned and the element type is 0-bit.
810 pub fn ptrAlignment(ty: Type, mod: *Module) u32 {806 pub fn ptrAlignment(ty: Type, mod: *Module) Alignment {
811 return ptrAlignmentAdvanced(ty, mod, null) catch unreachable;807 return ptrAlignmentAdvanced(ty, mod, null) catch unreachable;
812 }808 }
813809
814 pub fn ptrAlignmentAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) !u32 {810 pub fn ptrAlignmentAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) !Alignment {
815 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {811 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
816 .ptr_type => |ptr_type| {812 .ptr_type => |ptr_type| {
817 if (ptr_type.flags.alignment.toByteUnitsOptional()) |a| {813 if (ptr_type.flags.alignment != .none)
818 return @as(u32, @intCast(a));814 return ptr_type.flags.alignment;
819 } else if (opt_sema) |sema| {815
816 if (opt_sema) |sema| {
820 const res = try ptr_type.child.toType().abiAlignmentAdvanced(mod, .{ .sema = sema });817 const res = try ptr_type.child.toType().abiAlignmentAdvanced(mod, .{ .sema = sema });
821 return res.scalar;818 return res.scalar;
822 } else {
823 return (ptr_type.child.toType().abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar;
824 }819 }
820
821 return (ptr_type.child.toType().abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar;
825 },822 },
826 .opt_type => |child| child.toType().ptrAlignmentAdvanced(mod, opt_sema),823 .opt_type => |child| child.toType().ptrAlignmentAdvanced(mod, opt_sema),
827 else => unreachable,824 else => unreachable,
...@@ -836,8 +833,8 @@ pub const Type = struct {...@@ -836,8 +833,8 @@ pub const Type = struct {
836 };833 };
837 }834 }
838835
839 /// Returns 0 for 0-bit types.836 /// Never returns `none`. Asserts that all necessary type resolution is already done.
840 pub fn abiAlignment(ty: Type, mod: *Module) u32 {837 pub fn abiAlignment(ty: Type, mod: *Module) Alignment {
841 return (ty.abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar;838 return (ty.abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar;
842 }839 }
843840
...@@ -846,12 +843,12 @@ pub const Type = struct {...@@ -846,12 +843,12 @@ pub const Type = struct {
846 pub fn lazyAbiAlignment(ty: Type, mod: *Module) !Value {843 pub fn lazyAbiAlignment(ty: Type, mod: *Module) !Value {
847 switch (try ty.abiAlignmentAdvanced(mod, .lazy)) {844 switch (try ty.abiAlignmentAdvanced(mod, .lazy)) {
848 .val => |val| return val,845 .val => |val| return val,
849 .scalar => |x| return mod.intValue(Type.comptime_int, x),846 .scalar => |x| return mod.intValue(Type.comptime_int, x.toByteUnits(0)),
850 }847 }
851 }848 }
852849
853 pub const AbiAlignmentAdvanced = union(enum) {850 pub const AbiAlignmentAdvanced = union(enum) {
854 scalar: u32,851 scalar: Alignment,
855 val: Value,852 val: Value,
856 };853 };
857854
...@@ -881,36 +878,36 @@ pub const Type = struct {...@@ -881,36 +878,36 @@ pub const Type = struct {
881 };878 };
882879
883 switch (ty.toIntern()) {880 switch (ty.toIntern()) {
884 .empty_struct_type => return AbiAlignmentAdvanced{ .scalar = 0 },881 .empty_struct_type => return AbiAlignmentAdvanced{ .scalar = .@"1" },
885 else => switch (ip.indexToKey(ty.toIntern())) {882 else => switch (ip.indexToKey(ty.toIntern())) {
886 .int_type => |int_type| {883 .int_type => |int_type| {
887 if (int_type.bits == 0) return AbiAlignmentAdvanced{ .scalar = 0 };884 if (int_type.bits == 0) return AbiAlignmentAdvanced{ .scalar = .@"1" };
888 return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(int_type.bits, target) };885 return .{ .scalar = intAbiAlignment(int_type.bits, target) };
889 },886 },
890 .ptr_type, .anyframe_type => {887 .ptr_type, .anyframe_type => {
891 return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) };888 return .{ .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)) };
892 },889 },
893 .array_type => |array_type| {890 .array_type => |array_type| {
894 return array_type.child.toType().abiAlignmentAdvanced(mod, strat);891 return array_type.child.toType().abiAlignmentAdvanced(mod, strat);
895 },892 },
896 .vector_type => |vector_type| {893 .vector_type => |vector_type| {
897 const bits_u64 = try bitSizeAdvanced(vector_type.child.toType(), mod, opt_sema);894 const bits_u64 = try bitSizeAdvanced(vector_type.child.toType(), mod, opt_sema);
898 const bits = @as(u32, @intCast(bits_u64));895 const bits: u32 = @intCast(bits_u64);
899 const bytes = ((bits * vector_type.len) + 7) / 8;896 const bytes = ((bits * vector_type.len) + 7) / 8;
900 const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes);897 const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes);
901 return AbiAlignmentAdvanced{ .scalar = alignment };898 return .{ .scalar = Alignment.fromByteUnits(alignment) };
902 },899 },
903900
904 .opt_type => return abiAlignmentAdvancedOptional(ty, mod, strat),901 .opt_type => return abiAlignmentAdvancedOptional(ty, mod, strat),
905 .error_union_type => |info| return abiAlignmentAdvancedErrorUnion(ty, mod, strat, info.payload_type.toType()),902 .error_union_type => |info| return abiAlignmentAdvancedErrorUnion(ty, mod, strat, info.payload_type.toType()),
906903
907 // TODO revisit this when we have the concept of the error tag type904 // TODO revisit this when we have the concept of the error tag type
908 .error_set_type, .inferred_error_set_type => return AbiAlignmentAdvanced{ .scalar = 2 },905 .error_set_type, .inferred_error_set_type => return .{ .scalar = .@"2" },
909906
910 // represents machine code; not a pointer907 // represents machine code; not a pointer
911 .func_type => |func_type| return AbiAlignmentAdvanced{908 .func_type => |func_type| return .{
912 .scalar = if (func_type.alignment.toByteUnitsOptional()) |a|909 .scalar = if (func_type.alignment != .none)
913 @as(u32, @intCast(a))910 func_type.alignment
914 else911 else
915 target_util.defaultFunctionAlignment(target),912 target_util.defaultFunctionAlignment(target),
916 },913 },
...@@ -926,47 +923,50 @@ pub const Type = struct {...@@ -926,47 +923,50 @@ pub const Type = struct {
926 .call_modifier,923 .call_modifier,
927 .prefetch_options,924 .prefetch_options,
928 .anyopaque,925 .anyopaque,
929 => return AbiAlignmentAdvanced{ .scalar = 1 },926 => return .{ .scalar = .@"1" },
930927
931 .usize,928 .usize,
932 .isize,929 .isize,
933 .export_options,930 .export_options,
934 .extern_options,931 .extern_options,
935 => return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) },932 .type_info,
936933 => return .{
937 .c_char => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.char) },934 .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)),
938 .c_short => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.short) },935 },
939 .c_ushort => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ushort) },936
940 .c_int => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.int) },937 .c_char => return .{ .scalar = cTypeAlign(target, .char) },
941 .c_uint => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.uint) },938 .c_short => return .{ .scalar = cTypeAlign(target, .short) },
942 .c_long => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.long) },939 .c_ushort => return .{ .scalar = cTypeAlign(target, .ushort) },
943 .c_ulong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ulong) },940 .c_int => return .{ .scalar = cTypeAlign(target, .int) },
944 .c_longlong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longlong) },941 .c_uint => return .{ .scalar = cTypeAlign(target, .uint) },
945 .c_ulonglong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ulonglong) },942 .c_long => return .{ .scalar = cTypeAlign(target, .long) },
946 .c_longdouble => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) },943 .c_ulong => return .{ .scalar = cTypeAlign(target, .ulong) },
947944 .c_longlong => return .{ .scalar = cTypeAlign(target, .longlong) },
948 .f16 => return AbiAlignmentAdvanced{ .scalar = 2 },945 .c_ulonglong => return .{ .scalar = cTypeAlign(target, .ulonglong) },
949 .f32 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.float) },946 .c_longdouble => return .{ .scalar = cTypeAlign(target, .longdouble) },
947
948 .f16 => return .{ .scalar = .@"2" },
949 .f32 => return .{ .scalar = cTypeAlign(target, .float) },
950 .f64 => switch (target.c_type_bit_size(.double)) {950 .f64 => switch (target.c_type_bit_size(.double)) {
951 64 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.double) },951 64 => return .{ .scalar = cTypeAlign(target, .double) },
952 else => return AbiAlignmentAdvanced{ .scalar = 8 },952 else => return .{ .scalar = .@"8" },
953 },953 },
954 .f80 => switch (target.c_type_bit_size(.longdouble)) {954 .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) },
956 else => {956 else => {
957 const u80_ty: Type = .{ .ip_index = .u80_type };957 const u80_ty: Type = .{ .ip_index = .u80_type };
958 return AbiAlignmentAdvanced{ .scalar = abiAlignment(u80_ty, mod) };958 return .{ .scalar = abiAlignment(u80_ty, mod) };
959 },959 },
960 },960 },
961 .f128 => switch (target.c_type_bit_size(.longdouble)) {961 .f128 => switch (target.c_type_bit_size(.longdouble)) {
962 128 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) },962 128 => return .{ .scalar = cTypeAlign(target, .longdouble) },
963 else => return AbiAlignmentAdvanced{ .scalar = 16 },963 else => return .{ .scalar = .@"16" },
964 },964 },
965965
966 // TODO revisit this when we have the concept of the error tag type966 // TODO revisit this when we have the concept of the error tag type
967 .anyerror,967 .anyerror,
968 .adhoc_inferred_error_set,968 .adhoc_inferred_error_set,
969 => return AbiAlignmentAdvanced{ .scalar = 2 },969 => return .{ .scalar = .@"2" },
970970
971 .void,971 .void,
972 .type,972 .type,
...@@ -975,90 +975,46 @@ pub const Type = struct {...@@ -975,90 +975,46 @@ pub const Type = struct {
975 .null,975 .null,
976 .undefined,976 .undefined,
977 .enum_literal,977 .enum_literal,
978 .type_info,978 => return .{ .scalar = .@"1" },
979 => return AbiAlignmentAdvanced{ .scalar = 0 },
980979
981 .noreturn => unreachable,980 .noreturn => unreachable,
982 .generic_poison => unreachable,981 .generic_poison => unreachable,
983 },982 },
984 .struct_type => |struct_type| {983 .struct_type => |struct_type| {
985 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse984 if (struct_type.layout == .Packed) {
986 return AbiAlignmentAdvanced{ .scalar = 0 };
987
988 if (opt_sema) |sema| {
989 if (struct_obj.status == .field_types_wip) {
990 // We'll guess "pointer-aligned", if the struct has an
991 // underaligned pointer field then some allocations
992 // might require explicit alignment.
993 return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) };
994 }
995 _ = try sema.resolveTypeFields(ty);
996 }
997 if (!struct_obj.haveFieldTypes()) switch (strat) {
998 .eager => unreachable, // struct layout not resolved
999 .sema => unreachable, // handled above
1000 .lazy => return .{ .val = (try mod.intern(.{ .int = .{
1001 .ty = .comptime_int_type,
1002 .storage = .{ .lazy_align = ty.toIntern() },
1003 } })).toValue() },
1004 };
1005 if (struct_obj.layout == .Packed) {
1006 switch (strat) {985 switch (strat) {
1007 .sema => |sema| try sema.resolveTypeLayout(ty),986 .sema => |sema| try sema.resolveTypeLayout(ty),
1008 .lazy => if (!struct_obj.haveLayout()) return .{ .val = (try mod.intern(.{ .int = .{987 .lazy => if (struct_type.backingIntType(ip).* == .none) return .{
1009 .ty = .comptime_int_type,988 .val = (try mod.intern(.{ .int = .{
1010 .storage = .{ .lazy_align = ty.toIntern() },
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 = .{
1036 .ty = .comptime_int_type,989 .ty = .comptime_int_type,
1037 .storage = .{ .lazy_align = ty.toIntern() },990 .storage = .{ .lazy_align = ty.toIntern() },
1038 } })).toValue() },991 } })).toValue(),
1039 },992 },
1040 }));993 .eager => {},
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 }
1050 }994 }
995 return .{ .scalar = struct_type.backingIntType(ip).toType().abiAlignment(mod) };
1051 }996 }
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 };
1053 },1011 },
1054 .anon_struct_type => |tuple| {1012 .anon_struct_type => |tuple| {
1055 var big_align: u32 = 0;1013 var big_align: Alignment = .@"1";
1056 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {1014 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
1057 if (val != .none) continue; // comptime field1015 if (val != .none) continue; // comptime field
1058 if (!(field_ty.toType().hasRuntimeBits(mod))) continue;
1059
1060 switch (try field_ty.toType().abiAlignmentAdvanced(mod, strat)) {1016 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),
1062 .val => switch (strat) {1018 .val => switch (strat) {
1063 .eager => unreachable, // field type alignment not resolved1019 .eager => unreachable, // field type alignment not resolved
1064 .sema => unreachable, // passed to abiAlignmentAdvanced above1020 .sema => unreachable, // passed to abiAlignmentAdvanced above
...@@ -1069,7 +1025,7 @@ pub const Type = struct {...@@ -1069,7 +1025,7 @@ pub const Type = struct {
1069 },1025 },
1070 }1026 }
1071 }1027 }
1072 return AbiAlignmentAdvanced{ .scalar = big_align };1028 return .{ .scalar = big_align };
1073 },1029 },
10741030
1075 .union_type => |union_type| {1031 .union_type => |union_type| {
...@@ -1078,7 +1034,7 @@ pub const Type = struct {...@@ -1078,7 +1034,7 @@ pub const Type = struct {
1078 // We'll guess "pointer-aligned", if the union has an1034 // We'll guess "pointer-aligned", if the union has an
1079 // underaligned pointer field then some allocations1035 // underaligned pointer field then some allocations
1080 // might require explicit alignment.1036 // might require explicit alignment.
1081 return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) };1037 return .{ .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)) };
1082 }1038 }
1083 _ = try sema.resolveTypeFields(ty);1039 _ = try sema.resolveTypeFields(ty);
1084 }1040 }
...@@ -1095,13 +1051,11 @@ pub const Type = struct {...@@ -1095,13 +1051,11 @@ pub const Type = struct {
1095 if (union_obj.hasTag(ip)) {1051 if (union_obj.hasTag(ip)) {
1096 return abiAlignmentAdvanced(union_obj.enum_tag_ty.toType(), mod, strat);1052 return abiAlignmentAdvanced(union_obj.enum_tag_ty.toType(), mod, strat);
1097 } else {1053 } else {
1098 return AbiAlignmentAdvanced{1054 return .{ .scalar = .@"1" };
1099 .scalar = @intFromBool(union_obj.flagsPtr(ip).layout == .Extern),
1100 };
1101 }1055 }
1102 }1056 }
11031057
1104 var max_align: u32 = 0;1058 var max_align: Alignment = .@"1";
1105 if (union_obj.hasTag(ip)) max_align = union_obj.enum_tag_ty.toType().abiAlignment(mod);1059 if (union_obj.hasTag(ip)) max_align = union_obj.enum_tag_ty.toType().abiAlignment(mod);
1106 for (0..union_obj.field_names.len) |field_index| {1060 for (0..union_obj.field_names.len) |field_index| {
1107 const field_ty = union_obj.field_types.get(ip)[field_index].toType();1061 const field_ty = union_obj.field_types.get(ip)[field_index].toType();
...@@ -1117,8 +1071,9 @@ pub const Type = struct {...@@ -1117,8 +1071,9 @@ pub const Type = struct {
1117 else => |e| return e,1071 else => |e| return e,
1118 })) continue;1072 })) continue;
11191073
1120 const field_align_bytes: u32 = @intCast(field_align.toByteUnitsOptional() orelse1074 const field_align_bytes: Alignment = if (field_align != .none)
1121 switch (try field_ty.abiAlignmentAdvanced(mod, strat)) {1075 field_align
1076 else switch (try field_ty.abiAlignmentAdvanced(mod, strat)) {
1122 .scalar => |a| a,1077 .scalar => |a| a,
1123 .val => switch (strat) {1078 .val => switch (strat) {
1124 .eager => unreachable, // struct layout not resolved1079 .eager => unreachable, // struct layout not resolved
...@@ -1128,13 +1083,15 @@ pub const Type = struct {...@@ -1128,13 +1083,15 @@ pub const Type = struct {
1128 .storage = .{ .lazy_align = ty.toIntern() },1083 .storage = .{ .lazy_align = ty.toIntern() },
1129 } })).toValue() },1084 } })).toValue() },
1130 },1085 },
1131 });1086 };
1132 max_align = @max(max_align, field_align_bytes);1087 max_align = max_align.max(field_align_bytes);
1133 }1088 }
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),
1135 },1094 },
1136 .opaque_type => return AbiAlignmentAdvanced{ .scalar = 1 },
1137 .enum_type => |enum_type| return AbiAlignmentAdvanced{ .scalar = enum_type.tag_ty.toType().abiAlignment(mod) },
11381095
1139 // values, not types1096 // values, not types
1140 .undef,1097 .undef,
...@@ -1179,20 +1136,15 @@ pub const Type = struct {...@@ -1179,20 +1136,15 @@ pub const Type = struct {
1179 } })).toValue() },1136 } })).toValue() },
1180 else => |e| return e,1137 else => |e| return e,
1181 })) {1138 })) {
1182 return AbiAlignmentAdvanced{ .scalar = code_align };1139 return .{ .scalar = code_align };
1183 }1140 }
1184 return AbiAlignmentAdvanced{ .scalar = @max(1141 return .{ .scalar = code_align.max(
1185 code_align,
1186 (try payload_ty.abiAlignmentAdvanced(mod, strat)).scalar,1142 (try payload_ty.abiAlignmentAdvanced(mod, strat)).scalar,
1187 ) };1143 ) };
1188 },1144 },
1189 .lazy => {1145 .lazy => {
1190 switch (try payload_ty.abiAlignmentAdvanced(mod, strat)) {1146 switch (try payload_ty.abiAlignmentAdvanced(mod, strat)) {
1191 .scalar => |payload_align| {1147 .scalar => |payload_align| return .{ .scalar = code_align.max(payload_align) },
1192 return AbiAlignmentAdvanced{
1193 .scalar = @max(code_align, payload_align),
1194 };
1195 },
1196 .val => {},1148 .val => {},
1197 }1149 }
1198 return .{ .val = (try mod.intern(.{ .int = .{1150 return .{ .val = (try mod.intern(.{ .int = .{
...@@ -1212,9 +1164,11 @@ pub const Type = struct {...@@ -1212,9 +1164,11 @@ pub const Type = struct {
1212 const child_type = ty.optionalChild(mod);1164 const child_type = ty.optionalChild(mod);
12131165
1214 switch (child_type.zigTypeTag(mod)) {1166 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 },
1216 .ErrorSet => return abiAlignmentAdvanced(Type.anyerror, mod, strat),1170 .ErrorSet => return abiAlignmentAdvanced(Type.anyerror, mod, strat),
1217 .NoReturn => return AbiAlignmentAdvanced{ .scalar = 0 },1171 .NoReturn => return .{ .scalar = .@"1" },
1218 else => {},1172 else => {},
1219 }1173 }
12201174
...@@ -1227,12 +1181,12 @@ pub const Type = struct {...@@ -1227,12 +1181,12 @@ pub const Type = struct {
1227 } })).toValue() },1181 } })).toValue() },
1228 else => |e| return e,1182 else => |e| return e,
1229 })) {1183 })) {
1230 return AbiAlignmentAdvanced{ .scalar = 1 };1184 return .{ .scalar = .@"1" };
1231 }1185 }
1232 return child_type.abiAlignmentAdvanced(mod, strat);1186 return child_type.abiAlignmentAdvanced(mod, strat);
1233 },1187 },
1234 .lazy => switch (try child_type.abiAlignmentAdvanced(mod, strat)) {1188 .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") },
1236 .val => return .{ .val = (try mod.intern(.{ .int = .{1190 .val => return .{ .val = (try mod.intern(.{ .int = .{
1237 .ty = .comptime_int_type,1191 .ty = .comptime_int_type,
1238 .storage = .{ .lazy_align = ty.toIntern() },1192 .storage = .{ .lazy_align = ty.toIntern() },
...@@ -1310,8 +1264,7 @@ pub const Type = struct {...@@ -1310,8 +1264,7 @@ pub const Type = struct {
1310 .storage = .{ .lazy_size = ty.toIntern() },1264 .storage = .{ .lazy_size = ty.toIntern() },
1311 } })).toValue() },1265 } })).toValue() },
1312 };1266 };
1313 const elem_bits_u64 = try vector_type.child.toType().bitSizeAdvanced(mod, opt_sema);1267 const elem_bits = try vector_type.child.toType().bitSizeAdvanced(mod, opt_sema);
1314 const elem_bits = @as(u32, @intCast(elem_bits_u64));
1315 const total_bits = elem_bits * vector_type.len;1268 const total_bits = elem_bits * vector_type.len;
1316 const total_bytes = (total_bits + 7) / 8;1269 const total_bytes = (total_bits + 7) / 8;
1317 const alignment = switch (try ty.abiAlignmentAdvanced(mod, strat)) {1270 const alignment = switch (try ty.abiAlignmentAdvanced(mod, strat)) {
...@@ -1321,8 +1274,7 @@ pub const Type = struct {...@@ -1321,8 +1274,7 @@ pub const Type = struct {
1321 .storage = .{ .lazy_size = ty.toIntern() },1274 .storage = .{ .lazy_size = ty.toIntern() },
1322 } })).toValue() },1275 } })).toValue() },
1323 };1276 };
1324 const result = std.mem.alignForward(u32, total_bytes, alignment);1277 return AbiSizeAdvanced{ .scalar = alignment.forward(total_bytes) };
1325 return AbiSizeAdvanced{ .scalar = result };
1326 },1278 },
13271279
1328 .opt_type => return ty.abiSizeAdvancedOptional(mod, strat),1280 .opt_type => return ty.abiSizeAdvancedOptional(mod, strat),
...@@ -1360,16 +1312,16 @@ pub const Type = struct {...@@ -1360,16 +1312,16 @@ pub const Type = struct {
1360 };1312 };
13611313
1362 var size: u64 = 0;1314 var size: u64 = 0;
1363 if (code_align > payload_align) {1315 if (code_align.compare(.gt, payload_align)) {
1364 size += code_size;1316 size += code_size;
1365 size = std.mem.alignForward(u64, size, payload_align);1317 size = payload_align.forward(size);
1366 size += payload_size;1318 size += payload_size;
1367 size = std.mem.alignForward(u64, size, code_align);1319 size = code_align.forward(size);
1368 } else {1320 } else {
1369 size += payload_size;1321 size += payload_size;
1370 size = std.mem.alignForward(u64, size, code_align);1322 size = code_align.forward(size);
1371 size += code_size;1323 size += code_size;
1372 size = std.mem.alignForward(u64, size, payload_align);1324 size = payload_align.forward(size);
1373 }1325 }
1374 return AbiSizeAdvanced{ .scalar = size };1326 return AbiSizeAdvanced{ .scalar = size };
1375 },1327 },
...@@ -1435,41 +1387,35 @@ pub const Type = struct {...@@ -1435,41 +1387,35 @@ pub const Type = struct {
1435 .noreturn => unreachable,1387 .noreturn => unreachable,
1436 .generic_poison => unreachable,1388 .generic_poison => unreachable,
1437 },1389 },
1438 .struct_type => |struct_type| switch (ty.containerLayout(mod)) {1390 .struct_type => |struct_type| {
1439 .Packed => {1391 switch (strat) {
1440 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse1392 .sema => |sema| try sema.resolveTypeLayout(ty),
1441 return AbiSizeAdvanced{ .scalar = 0 };1393 .lazy => switch (struct_type.layout) {
14421394 .Packed => {
1443 switch (strat) {1395 if (struct_type.backingIntType(ip).* == .none) return .{
1444 .sema => |sema| try sema.resolveTypeLayout(ty),1396 .val = (try mod.intern(.{ .int = .{
1445 .lazy => if (!struct_obj.haveLayout()) return .{ .val = (try mod.intern(.{ .int = .{1397 .ty = .comptime_int_type,
1446 .ty = .comptime_int_type,1398 .storage = .{ .lazy_size = ty.toIntern() },
1447 .storage = .{ .lazy_size = ty.toIntern() },1399 } })).toValue(),
1448 } })).toValue() },1400 };
1449 .eager => {},
1450 }
1451 assert(struct_obj.haveLayout());
1452 return AbiSizeAdvanced{ .scalar = struct_obj.backing_int_ty.abiSize(mod) };
1453 },
1454 else => {
1455 switch (strat) {
1456 .sema => |sema| try sema.resolveTypeLayout(ty),
1457 .lazy => {
1458 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse
1459 return AbiSizeAdvanced{ .scalar = 0 };
1460 if (!struct_obj.haveLayout()) return .{ .val = (try mod.intern(.{ .int = .{
1461 .ty = .comptime_int_type,
1462 .storage = .{ .lazy_size = ty.toIntern() },
1463 } })).toValue() };
1464 },1401 },
1465 .eager => {},1402 .Auto, .Extern => {
1466 }1403 if (!struct_type.haveLayout(ip)) return .{
1467 const field_count = ty.structFieldCount(mod);1404 .val = (try mod.intern(.{ .int = .{
1468 if (field_count == 0) {1405 .ty = .comptime_int_type,
1469 return AbiSizeAdvanced{ .scalar = 0 };1406 .storage = .{ .lazy_size = ty.toIntern() },
1470 }1407 } })).toValue(),
1471 return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, mod) };1408 };
1472 },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 };
1473 },1419 },
1474 .anon_struct_type => |tuple| {1420 .anon_struct_type => |tuple| {
1475 switch (strat) {1421 switch (strat) {
...@@ -1565,20 +1511,19 @@ pub const Type = struct {...@@ -1565,20 +1511,19 @@ pub const Type = struct {
1565 // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal1511 // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
1566 // to the child type's ABI alignment.1512 // to the child type's ABI alignment.
1567 return AbiSizeAdvanced{1513 return AbiSizeAdvanced{
1568 .scalar = child_ty.abiAlignment(mod) + payload_size,1514 .scalar = child_ty.abiAlignment(mod).toByteUnits(0) + payload_size,
1569 };1515 };
1570 }1516 }
15711517
1572 fn intAbiSize(bits: u16, target: Target) u64 {1518 fn intAbiSize(bits: u16, target: Target) u64 {
1573 const alignment = intAbiAlignment(bits, target);1519 return intAbiAlignment(bits, target).forward(@as(u16, @intCast((@as(u17, bits) + 7) / 8)));
1574 return std.mem.alignForward(u64, @as(u16, @intCast((@as(u17, bits) + 7) / 8)), alignment);
1575 }1520 }
15761521
1577 fn intAbiAlignment(bits: u16, target: Target) u32 {1522 fn intAbiAlignment(bits: u16, target: Target) Alignment {
1578 return @min(1523 return Alignment.fromByteUnits(@min(
1579 std.math.ceilPowerOfTwoPromote(u16, @as(u16, @intCast((@as(u17, bits) + 7) / 8))),1524 std.math.ceilPowerOfTwoPromote(u16, @as(u16, @intCast((@as(u17, bits) + 7) / 8))),
1580 target.maxIntAlignment(),1525 target.maxIntAlignment(),
1581 );1526 ));
1582 }1527 }
15831528
1584 pub fn bitSize(ty: Type, mod: *Module) u64 {1529 pub fn bitSize(ty: Type, mod: *Module) u64 {
...@@ -1610,7 +1555,7 @@ pub const Type = struct {...@@ -1610,7 +1555,7 @@ pub const Type = struct {
1610 const len = array_type.len + @intFromBool(array_type.sentinel != .none);1555 const len = array_type.len + @intFromBool(array_type.sentinel != .none);
1611 if (len == 0) return 0;1556 if (len == 0) return 0;
1612 const elem_ty = array_type.child.toType();1557 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));
1614 if (elem_size == 0) return 0;1559 if (elem_size == 0) return 0;
1615 const elem_bit_size = try bitSizeAdvanced(elem_ty, mod, opt_sema);1560 const elem_bit_size = try bitSizeAdvanced(elem_ty, mod, opt_sema);
1616 return (len - 1) * 8 * elem_size + elem_bit_size;1561 return (len - 1) * 8 * elem_size + elem_bit_size;
...@@ -1675,35 +1620,33 @@ pub const Type = struct {...@@ -1675,35 +1620,33 @@ pub const Type = struct {
1675 .enum_literal => unreachable,1620 .enum_literal => unreachable,
1676 .generic_poison => unreachable,1621 .generic_poison => unreachable,
16771622
1678 .atomic_order => unreachable, // missing call to resolveTypeFields1623 .atomic_order => unreachable,
1679 .atomic_rmw_op => unreachable, // missing call to resolveTypeFields1624 .atomic_rmw_op => unreachable,
1680 .calling_convention => unreachable, // missing call to resolveTypeFields1625 .calling_convention => unreachable,
1681 .address_space => unreachable, // missing call to resolveTypeFields1626 .address_space => unreachable,
1682 .float_mode => unreachable, // missing call to resolveTypeFields1627 .float_mode => unreachable,
1683 .reduce_op => unreachable, // missing call to resolveTypeFields1628 .reduce_op => unreachable,
1684 .call_modifier => unreachable, // missing call to resolveTypeFields1629 .call_modifier => unreachable,
1685 .prefetch_options => unreachable, // missing call to resolveTypeFields1630 .prefetch_options => unreachable,
1686 .export_options => unreachable, // missing call to resolveTypeFields1631 .export_options => unreachable,
1687 .extern_options => unreachable, // missing call to resolveTypeFields1632 .extern_options => unreachable,
1688 .type_info => unreachable, // missing call to resolveTypeFields1633 .type_info => unreachable,
1689 },1634 },
1690 .struct_type => |struct_type| {1635 .struct_type => |struct_type| {
1691 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return 0;1636 if (struct_type.layout == .Packed) {
1692 if (struct_obj.layout != .Packed) {1637 if (opt_sema) |sema| try sema.resolveTypeLayout(ty);
1693 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;1638 return try struct_type.backingIntType(ip).*.toType().bitSizeAdvanced(mod, opt_sema);
1694 }1639 }
1695 if (opt_sema) |sema| _ = try sema.resolveTypeLayout(ty);1640 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
1696 assert(struct_obj.haveLayout());
1697 return try struct_obj.backing_int_ty.bitSizeAdvanced(mod, opt_sema);
1698 },1641 },
16991642
1700 .anon_struct_type => {1643 .anon_struct_type => {
1701 if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty);1644 if (opt_sema) |sema| try sema.resolveTypeFields(ty);
1702 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;1645 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
1703 },1646 },
17041647
1705 .union_type => |union_type| {1648 .union_type => |union_type| {
1706 if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty);1649 if (opt_sema) |sema| try sema.resolveTypeFields(ty);
1707 if (ty.containerLayout(mod) != .Packed) {1650 if (ty.containerLayout(mod) != .Packed) {
1708 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;1651 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
1709 }1652 }
...@@ -1749,13 +1692,7 @@ pub const Type = struct {...@@ -1749,13 +1692,7 @@ pub const Type = struct {
1749 pub fn layoutIsResolved(ty: Type, mod: *Module) bool {1692 pub fn layoutIsResolved(ty: Type, mod: *Module) bool {
1750 const ip = &mod.intern_pool;1693 const ip = &mod.intern_pool;
1751 return switch (ip.indexToKey(ty.toIntern())) {1694 return switch (ip.indexToKey(ty.toIntern())) {
1752 .struct_type => |struct_type| {1695 .struct_type => |struct_type| struct_type.haveLayout(ip),
1753 if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| {
1754 return struct_obj.haveLayout();
1755 } else {
1756 return true;
1757 }
1758 },
1759 .union_type => |union_type| union_type.haveLayout(ip),1696 .union_type => |union_type| union_type.haveLayout(ip),
1760 .array_type => |array_type| {1697 .array_type => |array_type| {
1761 if ((array_type.len + @intFromBool(array_type.sentinel != .none)) == 0) return true;1698 if ((array_type.len + @intFromBool(array_type.sentinel != .none)) == 0) return true;
...@@ -2020,10 +1957,7 @@ pub const Type = struct {...@@ -2020,10 +1957,7 @@ pub const Type = struct {
2020 pub fn containerLayout(ty: Type, mod: *Module) std.builtin.Type.ContainerLayout {1957 pub fn containerLayout(ty: Type, mod: *Module) std.builtin.Type.ContainerLayout {
2021 const ip = &mod.intern_pool;1958 const ip = &mod.intern_pool;
2022 return switch (ip.indexToKey(ty.toIntern())) {1959 return switch (ip.indexToKey(ty.toIntern())) {
2023 .struct_type => |struct_type| {1960 .struct_type => |struct_type| struct_type.layout,
2024 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return .Auto;
2025 return struct_obj.layout;
2026 },
2027 .anon_struct_type => .Auto,1961 .anon_struct_type => .Auto,
2028 .union_type => |union_type| union_type.flagsPtr(ip).layout,1962 .union_type => |union_type| union_type.flagsPtr(ip).layout,
2029 else => unreachable,1963 else => unreachable,
...@@ -2136,10 +2070,7 @@ pub const Type = struct {...@@ -2136,10 +2070,7 @@ pub const Type = struct {
2136 return switch (ip.indexToKey(ty.toIntern())) {2070 return switch (ip.indexToKey(ty.toIntern())) {
2137 .vector_type => |vector_type| vector_type.len,2071 .vector_type => |vector_type| vector_type.len,
2138 .array_type => |array_type| array_type.len,2072 .array_type => |array_type| array_type.len,
2139 .struct_type => |struct_type| {2073 .struct_type => |struct_type| struct_type.field_types.len,
2140 const struct_obj = ip.structPtrUnwrapConst(struct_type.index) orelse return 0;
2141 return struct_obj.fields.count();
2142 },
2143 .anon_struct_type => |tuple| tuple.types.len,2074 .anon_struct_type => |tuple| tuple.types.len,
21442075
2145 else => unreachable,2076 else => unreachable,
...@@ -2214,6 +2145,7 @@ pub const Type = struct {...@@ -2214,6 +2145,7 @@ pub const Type = struct {
22142145
2215 /// Asserts the type is an integer, enum, error set, or vector of one of them.2146 /// Asserts the type is an integer, enum, error set, or vector of one of them.
2216 pub fn intInfo(starting_ty: Type, mod: *Module) InternPool.Key.IntType {2147 pub fn intInfo(starting_ty: Type, mod: *Module) InternPool.Key.IntType {
2148 const ip = &mod.intern_pool;
2217 const target = mod.getTarget();2149 const target = mod.getTarget();
2218 var ty = starting_ty;2150 var ty = starting_ty;
22192151
...@@ -2233,13 +2165,9 @@ pub const Type = struct {...@@ -2233,13 +2165,9 @@ pub const Type = struct {
2233 .c_ulong_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulong) },2165 .c_ulong_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulong) },
2234 .c_longlong_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.longlong) },2166 .c_longlong_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.longlong) },
2235 .c_ulonglong_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulonglong) },2167 .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())) {
2237 .int_type => |int_type| return int_type,2169 .int_type => |int_type| return int_type,
2238 .struct_type => |struct_type| {2170 .struct_type => |t| ty = t.backingIntType(ip).*.toType(),
2239 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
2240 assert(struct_obj.layout == .Packed);
2241 ty = struct_obj.backing_int_ty;
2242 },
2243 .enum_type => |enum_type| ty = enum_type.tag_ty.toType(),2171 .enum_type => |enum_type| ty = enum_type.tag_ty.toType(),
2244 .vector_type => |vector_type| ty = vector_type.child.toType(),2172 .vector_type => |vector_type| ty = vector_type.child.toType(),
22452173
...@@ -2503,33 +2431,28 @@ pub const Type = struct {...@@ -2503,33 +2431,28 @@ pub const Type = struct {
2503 .generic_poison => unreachable,2431 .generic_poison => unreachable,
2504 },2432 },
2505 .struct_type => |struct_type| {2433 .struct_type => |struct_type| {
2506 if (mod.structPtrUnwrap(struct_type.index)) |s| {2434 assert(struct_type.haveFieldTypes(ip));
2507 assert(s.haveFieldTypes());2435 if (struct_type.knownNonOpv(ip))
2508 const field_vals = try mod.gpa.alloc(InternPool.Index, s.fields.count());2436 return null;
2509 defer mod.gpa.free(field_vals);2437 const field_vals = try mod.gpa.alloc(InternPool.Index, struct_type.field_types.len);
2510 for (field_vals, s.fields.values()) |*field_val, field| {2438 defer mod.gpa.free(field_vals);
2511 if (field.is_comptime) {2439 for (field_vals, 0..) |*field_val, i_usize| {
2512 field_val.* = field.default_val;2440 const i: u32 = @intCast(i_usize);
2513 continue;2441 if (struct_type.fieldIsComptime(ip, i)) {
2514 }2442 field_val.* = struct_type.field_inits.get(ip)[i];
2515 if (try field.ty.onePossibleValue(mod)) |field_opv| {2443 continue;
2516 field_val.* = try field_opv.intern(field.ty, mod);
2517 } else return null;
2518 }2444 }
25192445 const field_ty = struct_type.field_types.get(ip)[i].toType();
2520 // In this case the struct has no runtime-known fields and2446 if (try field_ty.onePossibleValue(mod)) |field_opv| {
2521 // therefore has one possible value.2447 field_val.* = try field_opv.intern(field_ty, mod);
2522 return (try mod.intern(.{ .aggregate = .{2448 } else return null;
2523 .ty = ty.toIntern(),
2524 .storage = .{ .elems = field_vals },
2525 } })).toValue();
2526 }2449 }
25272450
2528 // In this case the struct has no fields at all and2451 // In this case the struct has no runtime-known fields and
2529 // therefore has one possible value.2452 // therefore has one possible value.
2530 return (try mod.intern(.{ .aggregate = .{2453 return (try mod.intern(.{ .aggregate = .{
2531 .ty = ty.toIntern(),2454 .ty = ty.toIntern(),
2532 .storage = .{ .elems = &.{} },2455 .storage = .{ .elems = field_vals },
2533 } })).toValue();2456 } })).toValue();
2534 },2457 },
25352458
...@@ -2715,18 +2638,20 @@ pub const Type = struct {...@@ -2715,18 +2638,20 @@ pub const Type = struct {
2715 => true,2638 => true,
2716 },2639 },
2717 .struct_type => |struct_type| {2640 .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
2718 // A struct with no fields is not comptime-only.2646 // A struct with no fields is not comptime-only.
2719 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false;2647 return switch (struct_type.flagsPtr(ip).requires_comptime) {
2720 switch (struct_obj.requires_comptime) {2648 // Return false to avoid incorrect dependency loops.
2721 .wip, .unknown => {2649 // This will be handled correctly once merged with
2722 // Return false to avoid incorrect dependency loops.2650 // `Sema.typeRequiresComptime`.
2723 // This will be handled correctly once merged with2651 .wip, .unknown => false,
2724 // `Sema.typeRequiresComptime`.2652 .no => false,
2725 return false;2653 .yes => true,
2726 },2654 };
2727 .no => return false,
2728 .yes => return true,
2729 }
2730 },2655 },
27312656
2732 .anon_struct_type => |tuple| {2657 .anon_struct_type => |tuple| {
...@@ -2982,37 +2907,31 @@ pub const Type = struct {...@@ -2982,37 +2907,31 @@ pub const Type = struct {
2982 return enum_type.tagValueIndex(ip, int_tag);2907 return enum_type.tagValueIndex(ip, int_tag);
2983 }2908 }
29842909
2985 pub fn structFields(ty: Type, mod: *Module) Module.Struct.Fields {2910 /// Returns none in the case of a tuple which uses the integer index as the field name.
2986 switch (mod.intern_pool.indexToKey(ty.toIntern())) {2911 pub fn structFieldName(ty: Type, field_index: u32, mod: *Module) InternPool.OptionalNullTerminatedString {
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 {
2997 const ip = &mod.intern_pool;2912 const ip = &mod.intern_pool;
2998 return switch (ip.indexToKey(ty.toIntern())) {2913 return switch (ip.indexToKey(ty.toIntern())) {
2999 .struct_type => |struct_type| {2914 .struct_type => |struct_type| struct_type.fieldName(ip, field_index),
3000 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;2915 .anon_struct_type => |anon_struct| anon_struct.fieldName(ip, field_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],
3005 else => unreachable,2916 else => unreachable,
3006 };2917 };
3007 }2918 }
30082919
3009 pub fn structFieldCount(ty: Type, mod: *Module) usize {2920 /// When struct types have no field names, the names are implicitly understood to be
3010 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {2921 /// strings corresponding to the field indexes in declaration order. It used to be the
3011 .struct_type => |struct_type| {2922 /// case that a NullTerminatedString would be stored for each field in this case, however,
3012 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return 0;2923 /// now, callers must handle the possibility that there are no names stored at all.
3013 assert(struct_obj.haveFieldTypes());2924 /// Here we fake the previous behavior. Probably something better could be done by examining
3014 return struct_obj.fields.count();2925 /// all the callsites of this function.
3015 },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,
3016 .anon_struct_type => |anon_struct| anon_struct.types.len,2935 .anon_struct_type => |anon_struct| anon_struct.types.len,
3017 else => unreachable,2936 else => unreachable,
3018 };2937 };
...@@ -3022,11 +2941,7 @@ pub const Type = struct {...@@ -3022,11 +2941,7 @@ pub const Type = struct {
3022 pub fn structFieldType(ty: Type, index: usize, mod: *Module) Type {2941 pub fn structFieldType(ty: Type, index: usize, mod: *Module) Type {
3023 const ip = &mod.intern_pool;2942 const ip = &mod.intern_pool;
3024 return switch (ip.indexToKey(ty.toIntern())) {2943 return switch (ip.indexToKey(ty.toIntern())) {
3025 .struct_type => |struct_type| {2944 .struct_type => |struct_type| struct_type.field_types.get(ip)[index].toType(),
3026 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
3027 assert(struct_obj.haveFieldTypes());
3028 return struct_obj.fields.values()[index].ty;
3029 },
3030 .union_type => |union_type| {2945 .union_type => |union_type| {
3031 const union_obj = ip.loadUnionType(union_type);2946 const union_obj = ip.loadUnionType(union_type);
3032 return union_obj.field_types.get(ip)[index].toType();2947 return union_obj.field_types.get(ip)[index].toType();
...@@ -3036,13 +2951,14 @@ pub const Type = struct {...@@ -3036,13 +2951,14 @@ pub const Type = struct {
3036 };2951 };
3037 }2952 }
30382953
3039 pub fn structFieldAlign(ty: Type, index: usize, mod: *Module) u32 {2954 pub fn structFieldAlign(ty: Type, index: usize, mod: *Module) Alignment {
3040 const ip = &mod.intern_pool;2955 const ip = &mod.intern_pool;
3041 switch (ip.indexToKey(ty.toIntern())) {2956 switch (ip.indexToKey(ty.toIntern())) {
3042 .struct_type => |struct_type| {2957 .struct_type => |struct_type| {
3043 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;2958 assert(struct_type.layout != .Packed);
3044 assert(struct_obj.layout != .Packed);2959 const explicit_align = struct_type.fieldAlign(ip, index);
3045 return struct_obj.fields.values()[index].alignment(mod, struct_obj.layout);2960 const field_ty = struct_type.field_types.get(ip)[index].toType();
2961 return mod.structFieldAlignment(explicit_align, field_ty, struct_type.layout);
3046 },2962 },
3047 .anon_struct_type => |anon_struct| {2963 .anon_struct_type => |anon_struct| {
3048 return anon_struct.types.get(ip)[index].toType().abiAlignment(mod);2964 return anon_struct.types.get(ip)[index].toType().abiAlignment(mod);
...@@ -3059,8 +2975,7 @@ pub const Type = struct {...@@ -3059,8 +2975,7 @@ pub const Type = struct {
3059 const ip = &mod.intern_pool;2975 const ip = &mod.intern_pool;
3060 switch (ip.indexToKey(ty.toIntern())) {2976 switch (ip.indexToKey(ty.toIntern())) {
3061 .struct_type => |struct_type| {2977 .struct_type => |struct_type| {
3062 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;2978 const val = struct_type.fieldInit(ip, index);
3063 const val = struct_obj.fields.values()[index].default_val;
3064 // TODO: avoid using `unreachable` to indicate this.2979 // TODO: avoid using `unreachable` to indicate this.
3065 if (val == .none) return Value.@"unreachable";2980 if (val == .none) return Value.@"unreachable";
3066 return val.toValue();2981 return val.toValue();
...@@ -3079,12 +2994,10 @@ pub const Type = struct {...@@ -3079,12 +2994,10 @@ pub const Type = struct {
3079 const ip = &mod.intern_pool;2994 const ip = &mod.intern_pool;
3080 switch (ip.indexToKey(ty.toIntern())) {2995 switch (ip.indexToKey(ty.toIntern())) {
3081 .struct_type => |struct_type| {2996 .struct_type => |struct_type| {
3082 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;2997 if (struct_type.fieldIsComptime(ip, index)) {
3083 const field = struct_obj.fields.values()[index];2998 return struct_type.field_inits.get(ip)[index].toValue();
3084 if (field.is_comptime) {
3085 return field.default_val.toValue();
3086 } else {2999 } else {
3087 return field.ty.onePossibleValue(mod);3000 return struct_type.field_types.get(ip)[index].toType().onePossibleValue(mod);
3088 }3001 }
3089 },3002 },
3090 .anon_struct_type => |tuple| {3003 .anon_struct_type => |tuple| {
...@@ -3102,30 +3015,25 @@ pub const Type = struct {...@@ -3102,30 +3015,25 @@ pub const Type = struct {
3102 pub fn structFieldIsComptime(ty: Type, index: usize, mod: *Module) bool {3015 pub fn structFieldIsComptime(ty: Type, index: usize, mod: *Module) bool {
3103 const ip = &mod.intern_pool;3016 const ip = &mod.intern_pool;
3104 return switch (ip.indexToKey(ty.toIntern())) {3017 return switch (ip.indexToKey(ty.toIntern())) {
3105 .struct_type => |struct_type| {3018 .struct_type => |struct_type| struct_type.fieldIsComptime(ip, index),
3106 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
3107 if (struct_obj.layout == .Packed) return false;
3108 const field = struct_obj.fields.values()[index];
3109 return field.is_comptime;
3110 },
3111 .anon_struct_type => |anon_struct| anon_struct.values.get(ip)[index] != .none,3019 .anon_struct_type => |anon_struct| anon_struct.values.get(ip)[index] != .none,
3112 else => unreachable,3020 else => unreachable,
3113 };3021 };
3114 }3022 }
31153023
3116 pub fn packedStructFieldByteOffset(ty: Type, field_index: usize, mod: *Module) u32 {3024 pub fn packedStructFieldByteOffset(ty: Type, field_index: usize, mod: *Module) u32 {
3117 const struct_type = mod.intern_pool.indexToKey(ty.toIntern()).struct_type;3025 const ip = &mod.intern_pool;
3118 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;3026 const struct_type = ip.indexToKey(ty.toIntern()).struct_type;
3119 assert(struct_obj.layout == .Packed);3027 assert(struct_type.layout == .Packed);
3120 comptime assert(Type.packed_struct_layout_version == 2);3028 comptime assert(Type.packed_struct_layout_version == 2);
31213029
3122 var bit_offset: u16 = undefined;3030 var bit_offset: u16 = undefined;
3123 var elem_size_bits: u16 = undefined;3031 var elem_size_bits: u16 = undefined;
3124 var running_bits: u16 = 0;3032 var running_bits: u16 = 0;
3125 for (struct_obj.fields.values(), 0..) |f, i| {3033 for (struct_type.field_types.get(ip), 0..) |field_ty, i| {
3126 if (!f.ty.hasRuntimeBits(mod)) continue;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));
3129 if (i == field_index) {3037 if (i == field_index) {
3130 bit_offset = running_bits;3038 bit_offset = running_bits;
3131 elem_size_bits = field_bits;3039 elem_size_bits = field_bits;
...@@ -3141,68 +3049,19 @@ pub const Type = struct {...@@ -3141,68 +3049,19 @@ pub const Type = struct {
3141 offset: u64,3049 offset: u64,
3142 };3050 };
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
3186 /// Supports structs and unions.3052 /// Supports structs and unions.
3187 pub fn structFieldOffset(ty: Type, index: usize, mod: *Module) u64 {3053 pub fn structFieldOffset(ty: Type, index: usize, mod: *Module) u64 {
3188 const ip = &mod.intern_pool;3054 const ip = &mod.intern_pool;
3189 switch (ip.indexToKey(ty.toIntern())) {3055 switch (ip.indexToKey(ty.toIntern())) {
3190 .struct_type => |struct_type| {3056 .struct_type => |struct_type| {
3191 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;3057 assert(struct_type.haveLayout(ip));
3192 assert(struct_obj.haveLayout());3058 assert(struct_type.layout != .Packed);
3193 assert(struct_obj.layout != .Packed);3059 return struct_type.offsets.get(ip)[index];
3194 var it = ty.iterateStructOffsets(mod);
3195 while (it.next()) |field_offset| {
3196 if (index == field_offset.field)
3197 return field_offset.offset;
3198 }
3199
3200 return std.mem.alignForward(u64, it.offset, @max(it.big_align, 1));
3201 },3060 },
32023061
3203 .anon_struct_type => |tuple| {3062 .anon_struct_type => |tuple| {
3204 var offset: u64 = 0;3063 var offset: u64 = 0;
3205 var big_align: u32 = 0;3064 var big_align: Alignment = .none;
32063065
3207 for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, field_val, i| {3066 for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, field_val, i| {
3208 if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) {3067 if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) {
...@@ -3212,12 +3071,12 @@ pub const Type = struct {...@@ -3212,12 +3071,12 @@ pub const Type = struct {
3212 }3071 }
32133072
3214 const field_align = field_ty.toType().abiAlignment(mod);3073 const field_align = field_ty.toType().abiAlignment(mod);
3215 big_align = @max(big_align, field_align);3074 big_align = big_align.max(field_align);
3216 offset = std.mem.alignForward(u64, offset, field_align);3075 offset = field_align.forward(offset);
3217 if (i == index) return offset;3076 if (i == index) return offset;
3218 offset += field_ty.toType().abiSize(mod);3077 offset += field_ty.toType().abiSize(mod);
3219 }3078 }
3220 offset = std.mem.alignForward(u64, offset, @max(big_align, 1));3079 offset = big_align.max(.@"1").forward(offset);
3221 return offset;3080 return offset;
3222 },3081 },
32233082
...@@ -3226,9 +3085,9 @@ pub const Type = struct {...@@ -3226,9 +3085,9 @@ pub const Type = struct {
3226 return 0;3085 return 0;
3227 const union_obj = ip.loadUnionType(union_type);3086 const union_obj = ip.loadUnionType(union_type);
3228 const layout = mod.getUnionLayout(union_obj);3087 const layout = mod.getUnionLayout(union_obj);
3229 if (layout.tag_align >= layout.payload_align) {3088 if (layout.tag_align.compare(.gte, layout.payload_align)) {
3230 // {Tag, Payload}3089 // {Tag, Payload}
3231 return std.mem.alignForward(u64, layout.tag_size, layout.payload_align);3090 return layout.payload_align.forward(layout.tag_size);
3232 } else {3091 } else {
3233 // {Payload, Tag}3092 // {Payload, Tag}
3234 return 0;3093 return 0;
...@@ -3246,8 +3105,7 @@ pub const Type = struct {...@@ -3246,8 +3105,7 @@ pub const Type = struct {
3246 pub fn declSrcLocOrNull(ty: Type, mod: *Module) ?Module.SrcLoc {3105 pub fn declSrcLocOrNull(ty: Type, mod: *Module) ?Module.SrcLoc {
3247 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {3106 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
3248 .struct_type => |struct_type| {3107 .struct_type => |struct_type| {
3249 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;3108 return mod.declPtr(struct_type.decl.unwrap() orelse return null).srcLoc(mod);
3250 return struct_obj.srcLoc(mod);
3251 },3109 },
3252 .union_type => |union_type| {3110 .union_type => |union_type| {
3253 return mod.declPtr(union_type.decl).srcLoc(mod);3111 return mod.declPtr(union_type.decl).srcLoc(mod);
...@@ -3264,10 +3122,7 @@ pub const Type = struct {...@@ -3264,10 +3122,7 @@ pub const Type = struct {
32643122
3265 pub fn getOwnerDeclOrNull(ty: Type, mod: *Module) ?Module.Decl.Index {3123 pub fn getOwnerDeclOrNull(ty: Type, mod: *Module) ?Module.Decl.Index {
3266 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {3124 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
3267 .struct_type => |struct_type| {3125 .struct_type => |struct_type| struct_type.decl.unwrap(),
3268 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return null;
3269 return struct_obj.owner_decl;
3270 },
3271 .union_type => |union_type| union_type.decl,3126 .union_type => |union_type| union_type.decl,
3272 .opaque_type => |opaque_type| opaque_type.decl,3127 .opaque_type => |opaque_type| opaque_type.decl,
3273 .enum_type => |enum_type| enum_type.decl,3128 .enum_type => |enum_type| enum_type.decl,
...@@ -3280,10 +3135,12 @@ pub const Type = struct {...@@ -3280,10 +3135,12 @@ pub const Type = struct {
3280 }3135 }
32813136
3282 pub fn isTuple(ty: Type, mod: *Module) bool {3137 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())) {
3284 .struct_type => |struct_type| {3140 .struct_type => |struct_type| {
3285 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false;3141 if (struct_type.layout == .Packed) return false;
3286 return struct_obj.is_tuple;3142 if (struct_type.decl == .none) return false;
3143 return struct_type.flagsPtr(ip).is_tuple;
3287 },3144 },
3288 .anon_struct_type => |anon_struct| anon_struct.names.len == 0,3145 .anon_struct_type => |anon_struct| anon_struct.names.len == 0,
3289 else => false,3146 else => false,
...@@ -3299,10 +3156,12 @@ pub const Type = struct {...@@ -3299,10 +3156,12 @@ pub const Type = struct {
3299 }3156 }
33003157
3301 pub fn isTupleOrAnonStruct(ty: Type, mod: *Module) bool {3158 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())) {
3303 .struct_type => |struct_type| {3161 .struct_type => |struct_type| {
3304 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false;3162 if (struct_type.layout == .Packed) return false;
3305 return struct_obj.is_tuple;3163 if (struct_type.decl == .none) return false;
3164 return struct_type.flagsPtr(ip).is_tuple;
3306 },3165 },
3307 .anon_struct_type => true,3166 .anon_struct_type => true,
3308 else => false,3167 else => false,
...@@ -3391,3 +3250,7 @@ pub const Type = struct {...@@ -3391,3 +3250,7 @@ pub const Type = struct {
3391 /// to packed struct layout to find out all the places in the codebase you need to edit!3250 /// to packed struct layout to find out all the places in the codebase you need to edit!
3392 pub const packed_struct_layout_version = 2;3251 pub const packed_struct_layout_version = 2;
3393};3252};
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 {...@@ -462,7 +462,7 @@ pub const Value = struct {
462 if (opt_sema) |sema| try sema.resolveTypeLayout(ty.toType());462 if (opt_sema) |sema| try sema.resolveTypeLayout(ty.toType());
463 const x = switch (int.storage) {463 const x = switch (int.storage) {
464 else => unreachable,464 else => unreachable,
465 .lazy_align => ty.toType().abiAlignment(mod),465 .lazy_align => ty.toType().abiAlignment(mod).toByteUnits(0),
466 .lazy_size => ty.toType().abiSize(mod),466 .lazy_size => ty.toType().abiSize(mod),
467 };467 };
468 return BigIntMutable.init(&space.limbs, x).toConst();468 return BigIntMutable.init(&space.limbs, x).toConst();
...@@ -523,9 +523,9 @@ pub const Value = struct {...@@ -523,9 +523,9 @@ pub const Value = struct {
523 .u64 => |x| x,523 .u64 => |x| x,
524 .i64 => |x| std.math.cast(u64, x),524 .i64 => |x| std.math.cast(u64, x),
525 .lazy_align => |ty| if (opt_sema) |sema|525 .lazy_align => |ty| if (opt_sema) |sema|
526 (try ty.toType().abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar526 (try ty.toType().abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar.toByteUnits(0)
527 else527 else
528 ty.toType().abiAlignment(mod),528 ty.toType().abiAlignment(mod).toByteUnits(0),
529 .lazy_size => |ty| if (opt_sema) |sema|529 .lazy_size => |ty| if (opt_sema) |sema|
530 (try ty.toType().abiSizeAdvanced(mod, .{ .sema = sema })).scalar530 (try ty.toType().abiSizeAdvanced(mod, .{ .sema = sema })).scalar
531 else531 else
...@@ -569,9 +569,9 @@ pub const Value = struct {...@@ -569,9 +569,9 @@ pub const Value = struct {
569 .int => |int| switch (int.storage) {569 .int => |int| switch (int.storage) {
570 .big_int => |big_int| big_int.to(i64) catch unreachable,570 .big_int => |big_int| big_int.to(i64) catch unreachable,
571 .i64 => |x| x,571 .i64 => |x| x,
572 .u64 => |x| @as(i64, @intCast(x)),572 .u64 => |x| @intCast(x),
573 .lazy_align => |ty| @as(i64, @intCast(ty.toType().abiAlignment(mod))),573 .lazy_align => |ty| @intCast(ty.toType().abiAlignment(mod).toByteUnits(0)),
574 .lazy_size => |ty| @as(i64, @intCast(ty.toType().abiSize(mod))),574 .lazy_size => |ty| @intCast(ty.toType().abiSize(mod)),
575 },575 },
576 else => unreachable,576 else => unreachable,
577 },577 },
...@@ -612,10 +612,11 @@ pub const Value = struct {...@@ -612,10 +612,11 @@ pub const Value = struct {
612 const target = mod.getTarget();612 const target = mod.getTarget();
613 const endian = target.cpu.arch.endian();613 const endian = target.cpu.arch.endian();
614 if (val.isUndef(mod)) {614 if (val.isUndef(mod)) {
615 const size = @as(usize, @intCast(ty.abiSize(mod)));615 const size: usize = @intCast(ty.abiSize(mod));
616 @memset(buffer[0..size], 0xaa);616 @memset(buffer[0..size], 0xaa);
617 return;617 return;
618 }618 }
619 const ip = &mod.intern_pool;
619 switch (ty.zigTypeTag(mod)) {620 switch (ty.zigTypeTag(mod)) {
620 .Void => {},621 .Void => {},
621 .Bool => {622 .Bool => {
...@@ -656,40 +657,44 @@ pub const Value = struct {...@@ -656,40 +657,44 @@ pub const Value = struct {
656 const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8;657 const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8;
657 return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0);658 return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0);
658 },659 },
659 .Struct => switch (ty.containerLayout(mod)) {660 .Struct => {
660 .Auto => return error.IllDefinedMemoryLayout,661 const struct_type = mod.typeToStruct(ty) orelse return error.IllDefinedMemoryLayout;
661 .Extern => for (ty.structFields(mod).values(), 0..) |field, i| {662 switch (struct_type.layout) {
662 const off = @as(usize, @intCast(ty.structFieldOffset(i, mod)));663 .Auto => return error.IllDefinedMemoryLayout,
663 const field_val = switch (val.ip_index) {664 .Extern => for (0..struct_type.field_types.len) |i| {
664 .none => switch (val.tag()) {665 const off: usize = @intCast(ty.structFieldOffset(i, mod));
665 .bytes => {666 const field_val = switch (val.ip_index) {
666 buffer[off] = val.castTag(.bytes).?.data[i];667 .none => switch (val.tag()) {
667 continue;668 .bytes => {
668 },669 buffer[off] = val.castTag(.bytes).?.data[i];
669 .aggregate => val.castTag(.aggregate).?.data[i],670 continue;
670 .repeated => val.castTag(.repeated).?.data,671 },
671 else => unreachable,672 .aggregate => val.castTag(.aggregate).?.data[i],
672 },673 .repeated => val.castTag(.repeated).?.data,
673 else => switch (mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage) {674 else => unreachable,
674 .bytes => |bytes| {
675 buffer[off] = bytes[i];
676 continue;
677 },675 },
678 .elems => |elems| elems[i],676 else => switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
679 .repeated_elem => |elem| elem,677 .bytes => |bytes| {
680 }.toValue(),678 buffer[off] = bytes[i];
681 };679 continue;
682 try writeToMemory(field_val, field.ty, mod, buffer[off..]);680 },
683 },681 .elems => |elems| elems[i],
684 .Packed => {682 .repeated_elem => |elem| elem,
685 const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8;683 }.toValue(),
686 return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0);684 };
687 },685 const field_ty = struct_type.field_types.get(ip)[i].toType();
686 try writeToMemory(field_val, field_ty, mod, buffer[off..]);
687 },
688 .Packed => {
689 const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8;
690 return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0);
691 },
692 }
688 },693 },
689 .ErrorSet => {694 .ErrorSet => {
690 // TODO revisit this when we have the concept of the error tag type695 // TODO revisit this when we have the concept of the error tag type
691 const Int = u16;696 const Int = u16;
692 const name = switch (mod.intern_pool.indexToKey(val.toIntern())) {697 const name = switch (ip.indexToKey(val.toIntern())) {
693 .err => |err| err.name,698 .err => |err| err.name,
694 .error_union => |error_union| error_union.val.err_name,699 .error_union => |error_union| error_union.val.err_name,
695 else => unreachable,700 else => unreachable,
...@@ -790,24 +795,24 @@ pub const Value = struct {...@@ -790,24 +795,24 @@ pub const Value = struct {
790 bits += elem_bit_size;795 bits += elem_bit_size;
791 }796 }
792 },797 },
793 .Struct => switch (ty.containerLayout(mod)) {798 .Struct => {
794 .Auto => unreachable, // Sema is supposed to have emitted a compile error already799 const struct_type = ip.indexToKey(ty.toIntern()).struct_type;
795 .Extern => unreachable, // Handled in non-packed writeToMemory800 // Sema is supposed to have emitted a compile error already in the case of Auto,
796 .Packed => {801 // and Extern is handled in non-packed writeToMemory.
797 var bits: u16 = 0;802 assert(struct_type.layout == .Packed);
798 const fields = ty.structFields(mod).values();803 var bits: u16 = 0;
799 const storage = ip.indexToKey(val.toIntern()).aggregate.storage;804 const storage = ip.indexToKey(val.toIntern()).aggregate.storage;
800 for (fields, 0..) |field, i| {805 for (0..struct_type.field_types.len) |i| {
801 const field_bits = @as(u16, @intCast(field.ty.bitSize(mod)));806 const field_ty = struct_type.field_types.get(ip)[i].toType();
802 const field_val = switch (storage) {807 const field_bits: u16 = @intCast(field_ty.bitSize(mod));
803 .bytes => unreachable,808 const field_val = switch (storage) {
804 .elems => |elems| elems[i],809 .bytes => unreachable,
805 .repeated_elem => |elem| elem,810 .elems => |elems| elems[i],
806 };811 .repeated_elem => |elem| elem,
807 try field_val.toValue().writeToPackedMemory(field.ty, mod, buffer, bit_offset + bits);812 };
808 bits += field_bits;813 try field_val.toValue().writeToPackedMemory(field_ty, mod, buffer, bit_offset + bits);
809 }814 bits += field_bits;
810 },815 }
811 },816 },
812 .Union => {817 .Union => {
813 const union_obj = mod.typeToUnion(ty).?;818 const union_obj = mod.typeToUnion(ty).?;
...@@ -852,6 +857,7 @@ pub const Value = struct {...@@ -852,6 +857,7 @@ pub const Value = struct {
852 buffer: []const u8,857 buffer: []const u8,
853 arena: Allocator,858 arena: Allocator,
854 ) Allocator.Error!Value {859 ) Allocator.Error!Value {
860 const ip = &mod.intern_pool;
855 const target = mod.getTarget();861 const target = mod.getTarget();
856 const endian = target.cpu.arch.endian();862 const endian = target.cpu.arch.endian();
857 switch (ty.zigTypeTag(mod)) {863 switch (ty.zigTypeTag(mod)) {
...@@ -926,25 +932,29 @@ pub const Value = struct {...@@ -926,25 +932,29 @@ pub const Value = struct {
926 const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8;932 const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8;
927 return readFromPackedMemory(ty, mod, buffer[0..byte_count], 0, arena);933 return readFromPackedMemory(ty, mod, buffer[0..byte_count], 0, arena);
928 },934 },
929 .Struct => switch (ty.containerLayout(mod)) {935 .Struct => {
930 .Auto => unreachable, // Sema is supposed to have emitted a compile error already936 const struct_type = mod.typeToStruct(ty).?;
931 .Extern => {937 switch (struct_type.layout) {
932 const fields = ty.structFields(mod).values();938 .Auto => unreachable, // Sema is supposed to have emitted a compile error already
933 const field_vals = try arena.alloc(InternPool.Index, fields.len);939 .Extern => {
934 for (field_vals, fields, 0..) |*field_val, field, i| {940 const field_types = struct_type.field_types;
935 const off = @as(usize, @intCast(ty.structFieldOffset(i, mod)));941 const field_vals = try arena.alloc(InternPool.Index, field_types.len);
936 const sz = @as(usize, @intCast(field.ty.abiSize(mod)));942 for (field_vals, 0..) |*field_val, i| {
937 field_val.* = try (try readFromMemory(field.ty, mod, buffer[off..(off + sz)], arena)).intern(field.ty, mod);943 const field_ty = field_types.get(ip)[i].toType();
938 }944 const off: usize = @intCast(ty.structFieldOffset(i, mod));
939 return (try mod.intern(.{ .aggregate = .{945 const sz: usize = @intCast(field_ty.abiSize(mod));
940 .ty = ty.toIntern(),946 field_val.* = try (try readFromMemory(field_ty, mod, buffer[off..(off + sz)], arena)).intern(field_ty, mod);
941 .storage = .{ .elems = field_vals },947 }
942 } })).toValue();948 return (try mod.intern(.{ .aggregate = .{
943 },949 .ty = ty.toIntern(),
944 .Packed => {950 .storage = .{ .elems = field_vals },
945 const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8;951 } })).toValue();
946 return readFromPackedMemory(ty, mod, buffer[0..byte_count], 0, arena);952 },
947 },953 .Packed => {
954 const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8;
955 return readFromPackedMemory(ty, mod, buffer[0..byte_count], 0, arena);
956 },
957 }
948 },958 },
949 .ErrorSet => {959 .ErrorSet => {
950 // TODO revisit this when we have the concept of the error tag type960 // TODO revisit this when we have the concept of the error tag type
...@@ -992,6 +1002,7 @@ pub const Value = struct {...@@ -992,6 +1002,7 @@ pub const Value = struct {
992 bit_offset: usize,1002 bit_offset: usize,
993 arena: Allocator,1003 arena: Allocator,
994 ) Allocator.Error!Value {1004 ) Allocator.Error!Value {
1005 const ip = &mod.intern_pool;
995 const target = mod.getTarget();1006 const target = mod.getTarget();
996 const endian = target.cpu.arch.endian();1007 const endian = target.cpu.arch.endian();
997 switch (ty.zigTypeTag(mod)) {1008 switch (ty.zigTypeTag(mod)) {
...@@ -1070,23 +1081,22 @@ pub const Value = struct {...@@ -1070,23 +1081,22 @@ pub const Value = struct {
1070 .storage = .{ .elems = elems },1081 .storage = .{ .elems = elems },
1071 } })).toValue();1082 } })).toValue();
1072 },1083 },
1073 .Struct => switch (ty.containerLayout(mod)) {1084 .Struct => {
1074 .Auto => unreachable, // Sema is supposed to have emitted a compile error already1085 // Sema is supposed to have emitted a compile error already for Auto layout structs,
1075 .Extern => unreachable, // Handled by non-packed readFromMemory1086 // and Extern is handled by non-packed readFromMemory.
1076 .Packed => {1087 const struct_type = mod.typeToPackedStruct(ty).?;
1077 var bits: u16 = 0;1088 var bits: u16 = 0;
1078 const fields = ty.structFields(mod).values();1089 const field_vals = try arena.alloc(InternPool.Index, struct_type.field_types.len);
1079 const field_vals = try arena.alloc(InternPool.Index, fields.len);1090 for (field_vals, 0..) |*field_val, i| {
1080 for (fields, 0..) |field, i| {1091 const field_ty = struct_type.field_types.get(ip)[i].toType();
1081 const field_bits = @as(u16, @intCast(field.ty.bitSize(mod)));1092 const field_bits: u16 = @intCast(field_ty.bitSize(mod));
1082 field_vals[i] = try (try readFromPackedMemory(field.ty, mod, buffer, bit_offset + bits, arena)).intern(field.ty, mod);1093 field_val.* = try (try readFromPackedMemory(field_ty, mod, buffer, bit_offset + bits, arena)).intern(field_ty, mod);
1083 bits += field_bits;1094 bits += field_bits;
1084 }1095 }
1085 return (try mod.intern(.{ .aggregate = .{1096 return (try mod.intern(.{ .aggregate = .{
1086 .ty = ty.toIntern(),1097 .ty = ty.toIntern(),
1087 .storage = .{ .elems = field_vals },1098 .storage = .{ .elems = field_vals },
1088 } })).toValue();1099 } })).toValue();
1089 },
1090 },1100 },
1091 .Pointer => {1101 .Pointer => {
1092 assert(!ty.isSlice(mod)); // No well defined layout.1102 assert(!ty.isSlice(mod)); // No well defined layout.
...@@ -1105,18 +1115,18 @@ pub const Value = struct {...@@ -1105,18 +1115,18 @@ pub const Value = struct {
1105 pub fn toFloat(val: Value, comptime T: type, mod: *Module) T {1115 pub fn toFloat(val: Value, comptime T: type, mod: *Module) T {
1106 return switch (mod.intern_pool.indexToKey(val.toIntern())) {1116 return switch (mod.intern_pool.indexToKey(val.toIntern())) {
1107 .int => |int| switch (int.storage) {1117 .int => |int| switch (int.storage) {
1108 .big_int => |big_int| @as(T, @floatCast(bigIntToFloat(big_int.limbs, big_int.positive))),1118 .big_int => |big_int| @floatCast(bigIntToFloat(big_int.limbs, big_int.positive)),
1109 inline .u64, .i64 => |x| {1119 inline .u64, .i64 => |x| {
1110 if (T == f80) {1120 if (T == f80) {
1111 @panic("TODO we can't lower this properly on non-x86 llvm backend yet");1121 @panic("TODO we can't lower this properly on non-x86 llvm backend yet");
1112 }1122 }
1113 return @as(T, @floatFromInt(x));1123 return @floatFromInt(x);
1114 },1124 },
1115 .lazy_align => |ty| @as(T, @floatFromInt(ty.toType().abiAlignment(mod))),1125 .lazy_align => |ty| @floatFromInt(ty.toType().abiAlignment(mod).toByteUnits(0)),
1116 .lazy_size => |ty| @as(T, @floatFromInt(ty.toType().abiSize(mod))),1126 .lazy_size => |ty| @floatFromInt(ty.toType().abiSize(mod)),
1117 },1127 },
1118 .float => |float| switch (float.storage) {1128 .float => |float| switch (float.storage) {
1119 inline else => |x| @as(T, @floatCast(x)),1129 inline else => |x| @floatCast(x),
1120 },1130 },
1121 else => unreachable,1131 else => unreachable,
1122 };1132 };
...@@ -1255,7 +1265,8 @@ pub const Value = struct {...@@ -1255,7 +1265,8 @@ pub const Value = struct {
1255 .int => |int| switch (int.storage) {1265 .int => |int| switch (int.storage) {
1256 .big_int => |big_int| big_int.orderAgainstScalar(0),1266 .big_int => |big_int| big_int.orderAgainstScalar(0),
1257 inline .u64, .i64 => |x| std.math.order(x, 0),1267 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(
1259 mod,1270 mod,
1260 false,1271 false,
1261 if (opt_sema) |sema| .{ .sema = sema } else .eager,1272 if (opt_sema) |sema| .{ .sema = sema } else .eager,
...@@ -1510,33 +1521,38 @@ pub const Value = struct {...@@ -1510,33 +1521,38 @@ pub const Value = struct {
1510 /// Asserts the value is a single-item pointer to an array, or an array,1521 /// Asserts the value is a single-item pointer to an array, or an array,
1511 /// or an unknown-length pointer, and returns the element value at the index.1522 /// or an unknown-length pointer, and returns the element value at the index.
1512 pub fn elemValue(val: Value, mod: *Module, index: usize) Allocator.Error!Value {1523 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 {
1513 return switch (val.ip_index) {1529 return switch (val.ip_index) {
1514 .none => switch (val.tag()) {1530 .none => switch (val.tag()) {
1515 .bytes => try mod.intValue(Type.u8, val.castTag(.bytes).?.data[index]),1531 .bytes => try mod.intValue(Type.u8, val.castTag(.bytes).?.data[index]),
1516 .repeated => val.castTag(.repeated).?.data,1532 .repeated => val.castTag(.repeated).?.data,
1517 .aggregate => val.castTag(.aggregate).?.data[index],1533 .aggregate => val.castTag(.aggregate).?.data[index],
1518 .slice => val.castTag(.slice).?.data.ptr.elemValue(mod, index),1534 .slice => val.castTag(.slice).?.data.ptr.maybeElemValue(mod, index),
1519 else => unreachable,1535 else => null,
1520 },1536 },
1521 else => switch (mod.intern_pool.indexToKey(val.toIntern())) {1537 else => switch (mod.intern_pool.indexToKey(val.toIntern())) {
1522 .undef => |ty| (try mod.intern(.{1538 .undef => |ty| (try mod.intern(.{
1523 .undef = ty.toType().elemType2(mod).toIntern(),1539 .undef = ty.toType().elemType2(mod).toIntern(),
1524 })).toValue(),1540 })).toValue(),
1525 .ptr => |ptr| switch (ptr.addr) {1541 .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),
1527 .mut_decl => |mut_decl| (try mod.declPtr(mut_decl.decl).internValue(mod))1543 .mut_decl => |mut_decl| (try mod.declPtr(mut_decl.decl).internValue(mod))
1528 .toValue().elemValue(mod, index),1544 .toValue().maybeElemValue(mod, index),
1529 .int, .eu_payload => unreachable,1545 .int, .eu_payload => null,
1530 .opt_payload => |base| base.toValue().elemValue(mod, index),1546 .opt_payload => |base| base.toValue().maybeElemValue(mod, index),
1531 .comptime_field => |field_val| field_val.toValue().elemValue(mod, index),1547 .comptime_field => |field_val| field_val.toValue().maybeElemValue(mod, index),
1532 .elem => |elem| elem.base.toValue().elemValue(mod, index + @as(usize, @intCast(elem.index))),1548 .elem => |elem| elem.base.toValue().maybeElemValue(mod, index + @as(usize, @intCast(elem.index))),
1533 .field => |field| if (field.base.toValue().pointerDecl(mod)) |decl_index| {1549 .field => |field| if (field.base.toValue().pointerDecl(mod)) |decl_index| {
1534 const base_decl = mod.declPtr(decl_index);1550 const base_decl = mod.declPtr(decl_index);
1535 const field_val = try base_decl.val.fieldValue(mod, @as(usize, @intCast(field.index)));1551 const field_val = try base_decl.val.fieldValue(mod, @as(usize, @intCast(field.index)));
1536 return field_val.elemValue(mod, index);1552 return field_val.maybeElemValue(mod, index);
1537 } else unreachable,1553 } else null,
1538 },1554 },
1539 .opt => |opt| opt.val.toValue().elemValue(mod, index),1555 .opt => |opt| opt.val.toValue().maybeElemValue(mod, index),
1540 .aggregate => |aggregate| {1556 .aggregate => |aggregate| {
1541 const len = mod.intern_pool.aggregateTypeLen(aggregate.ty);1557 const len = mod.intern_pool.aggregateTypeLen(aggregate.ty);
1542 if (index < len) return switch (aggregate.storage) {1558 if (index < len) return switch (aggregate.storage) {
...@@ -1550,7 +1566,7 @@ pub const Value = struct {...@@ -1550,7 +1566,7 @@ pub const Value = struct {
1550 assert(index == len);1566 assert(index == len);
1551 return mod.intern_pool.indexToKey(aggregate.ty).array_type.sentinel.toValue();1567 return mod.intern_pool.indexToKey(aggregate.ty).array_type.sentinel.toValue();
1552 },1568 },
1553 else => unreachable,1569 else => null,
1554 },1570 },
1555 };1571 };
1556 }1572 }
...@@ -1875,9 +1891,9 @@ pub const Value = struct {...@@ -1875,9 +1891,9 @@ pub const Value = struct {
1875 },1891 },
1876 inline .u64, .i64 => |x| floatFromIntInner(x, float_ty, mod),1892 inline .u64, .i64 => |x| floatFromIntInner(x, float_ty, mod),
1877 .lazy_align => |ty| if (opt_sema) |sema| {1893 .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);
1879 } else {1895 } else {
1880 return floatFromIntInner(ty.toType().abiAlignment(mod), float_ty, mod);1896 return floatFromIntInner(ty.toType().abiAlignment(mod).toByteUnits(0), float_ty, mod);
1881 },1897 },
1882 .lazy_size => |ty| if (opt_sema) |sema| {1898 .lazy_size => |ty| if (opt_sema) |sema| {
1883 return floatFromIntInner((try ty.toType().abiSizeAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod);1899 return floatFromIntInner((try ty.toType().abiSizeAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod);
...@@ -1892,11 +1908,11 @@ pub const Value = struct {...@@ -1892,11 +1908,11 @@ pub const Value = struct {
1892 fn floatFromIntInner(x: anytype, dest_ty: Type, mod: *Module) !Value {1908 fn floatFromIntInner(x: anytype, dest_ty: Type, mod: *Module) !Value {
1893 const target = mod.getTarget();1909 const target = mod.getTarget();
1894 const storage: InternPool.Key.Float.Storage = switch (dest_ty.floatBits(target)) {1910 const storage: InternPool.Key.Float.Storage = switch (dest_ty.floatBits(target)) {
1895 16 => .{ .f16 = @as(f16, @floatFromInt(x)) },1911 16 => .{ .f16 = @floatFromInt(x) },
1896 32 => .{ .f32 = @as(f32, @floatFromInt(x)) },1912 32 => .{ .f32 = @floatFromInt(x) },
1897 64 => .{ .f64 = @as(f64, @floatFromInt(x)) },1913 64 => .{ .f64 = @floatFromInt(x) },
1898 80 => .{ .f80 = @as(f80, @floatFromInt(x)) },1914 80 => .{ .f80 = @floatFromInt(x) },
1899 128 => .{ .f128 = @as(f128, @floatFromInt(x)) },1915 128 => .{ .f128 = @floatFromInt(x) },
1900 else => unreachable,1916 else => unreachable,
1901 };1917 };
1902 return (try mod.intern(.{ .float = .{1918 return (try mod.intern(.{ .float = .{
test/behavior/align.zig+55
...@@ -619,3 +619,58 @@ test "sub-aligned pointer field access" {...@@ -619,3 +619,58 @@ test "sub-aligned pointer field access" {
619 .Little => try expect(x == 0x09080706),619 .Little => try expect(x == 0x09080706),
620 }620 }
621}621}
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" {...@@ -18,24 +18,13 @@ test "@alignOf(T) before referencing T" {
18}18}
1919
20test "comparison of @alignOf(T) against zero" {20test "comparison of @alignOf(T) against zero" {
21 {21 const T = struct { x: u32 };
22 const T = struct { x: u32 };22 try expect(!(@alignOf(T) == 0));
23 try expect(!(@alignOf(T) == 0));23 try expect(@alignOf(T) != 0);
24 try expect(@alignOf(T) != 0);24 try expect(!(@alignOf(T) < 0));
25 try expect(!(@alignOf(T) < 0));25 try expect(!(@alignOf(T) <= 0));
26 try expect(!(@alignOf(T) <= 0));26 try expect(@alignOf(T) > 0);
27 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 }
39}28}
4029
41test "correct alignment for elements and slices of aligned array" {30test "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" {...@@ -37,7 +37,7 @@ test "switch on empty tagged union" {
37test "empty union" {37test "empty union" {
38 const U = union {};38 const U = union {};
39 try expect(@sizeOf(U) == 0);39 try expect(@sizeOf(U) == 0);
40 try expect(@alignOf(U) == 0);40 try expect(@alignOf(U) == 1);
41}41}
4242
43test "empty extern union" {43test "empty extern union" {