| author | |
| committer | |
| log | a8d2ed806558cc1472f3a532169a4994abe17833 |
| tree | d41c8344573283da5e5be48e06d4c73662e25ddc |
| parent | 0345d7866347c9066b0646f9e46be9a068dcfaa3 |
| parent | 221295b7db97c78ffce39e64dd6cafd8ad0b3f9a |
| signature |
compiler: move struct types into InternPool proper41 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( |
| 4881 | 4884 | ||
| 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; |
| 4912 | 4918 | ||
| 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, |
| 4918 | 4924 | } | |
| 4919 | if (!is_comptime) { | 4925 | } else { |
| 4920 | known_non_opv = known_non_opv or | 4926 | 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 or | 4928 | 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 | } |
| 4956 | 4963 | ||
| 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 } }; |
| 4959 | 4967 | ||
| 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 | }); |
| 4986 | 4997 | ||
| 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.Index | 3 | //! * Module.Namespace has a pointer to Module.File |
| 4 | //! * type_opaque via Module.Namespace.Index and Module.Decl.Index | 4 | //! * Module.Decl has a pointer to Module.CaptureScope |
| 5 | 5 | ||
| 6 | /// Maps `Key` to `Index`. `Key` objects are not stored anywhere; they are | 6 | /// Maps `Key` to `Index`. `Key` objects are not stored anywhere; they are |
| 7 | /// constructed lazily. | 7 | /// constructed lazily. |
| ... | @@ -39,17 +39,11 @@ allocated_namespaces: std.SegmentedList(Module.Namespace, 0) = .{}, | ... | @@ -39,17 +39,11 @@ allocated_namespaces: std.SegmentedList(Module.Namespace, 0) = .{}, |
| 39 | /// Same pattern as with `decls_free_list`. | 39 | /// Same pattern as with `decls_free_list`. |
| 40 | namespaces_free_list: std.ArrayListUnmanaged(Module.Namespace.Index) = .{}, | 40 | namespaces_free_list: std.ArrayListUnmanaged(Module.Namespace.Index) = .{}, |
| 41 | 41 | ||
| 42 | /// Struct objects are stored in this data structure because: | ||
| 43 | /// * They contain pointers such as the field maps. | ||
| 44 | /// * They need to be mutated after creation. | ||
| 45 | allocated_structs: std.SegmentedList(Module.Struct, 0) = .{}, | ||
| 46 | /// When a Struct object is freed from `allocated_structs`, it is pushed into this stack. | ||
| 47 | structs_free_list: std.ArrayListUnmanaged(Module.Struct.Index) = .{}, | ||
| 48 | |||
| 49 | /// Some types such as enums, structs, and unions need to store mappings from field names | 42 | /// Some types such as enums, structs, and unions need to store mappings from field names |
| 50 | /// to field index, or value to field index. In such cases, they will store the underlying | 43 | /// to field index, or value to field index. In such cases, they will store the underlying |
| 51 | /// field names and values directly, relying on one of these maps, stored separately, | 44 | /// field names and values directly, relying on one of these maps, stored separately, |
| 52 | /// to provide lookup. | 45 | /// to provide lookup. |
| 46 | /// These are not serialized; it is computed upon deserialization. | ||
| 53 | maps: std.ArrayListUnmanaged(FieldMap) = .{}, | 47 | maps: std.ArrayListUnmanaged(FieldMap) = .{}, |
| 54 | 48 | ||
| 55 | /// Used for finding the index inside `string_bytes`. | 49 | /// Used for finding the index inside `string_bytes`. |
| ... | @@ -365,11 +359,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 | }; |
| 367 | 361 | ||
| 368 | pub const StructType = extern struct { | 362 | /// Although packed structs and non-packed structs are encoded differently, |
| 369 | /// The `none` tag is used to represent a struct with no fields. | 363 | /// this struct is used for both categories since they share some common |
| 370 | index: Module.Struct.OptionalIndex, | 364 | /// functionality. |
| 371 | /// May be `none` if the struct has no declarations. | 365 | pub const StructType = struct { |
| 366 | extra_index: u32, | ||
| 367 | /// `none` when the struct is `@TypeOf(.{})`. | ||
| 368 | decl: Module.Decl.OptionalIndex, | ||
| 369 | /// `none` when the struct has no declarations. | ||
| 372 | namespace: Module.Namespace.OptionalIndex, | 370 | namespace: Module.Namespace.OptionalIndex, |
| 371 | /// Index of the struct_decl ZIR instruction. | ||
| 372 | zir_index: Zir.Inst.Index, | ||
| 373 | layout: std.builtin.Type.ContainerLayout, | ||
| 374 | field_names: NullTerminatedString.Slice, | ||
| 375 | field_types: Index.Slice, | ||
| 376 | field_inits: Index.Slice, | ||
| 377 | field_aligns: Alignment.Slice, | ||
| 378 | runtime_order: RuntimeOrder.Slice, | ||
| 379 | comptime_bits: ComptimeBits, | ||
| 380 | offsets: Offsets, | ||
| 381 | names_map: 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 | }; |
| 374 | 648 | ||
| 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 | }; |
| 386 | 671 | ||
| 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)), |
| 897 | 1182 | ||
| 898 | .int => |int| { | 1183 | .int => |int| { |
| ... | @@ -969,11 +1254,11 @@ pub const Key = union(enum) { | ... | @@ -969,11 +1254,11 @@ pub const Key = union(enum) { |
| 969 | 1254 | ||
| 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 | }; |
| 1435 | 1720 | ||
| 1721 | pub const RequiresComptime = enum(u2) { no, yes, unknown, wip }; | ||
| 1722 | |||
| 1436 | // Unlike `Tag.TypeUnion` which is an encoding, and `Key.UnionType` which is a | 1723 | // Unlike `Tag.TypeUnion` which is an encoding, and `Key.UnionType` which is a |
| 1437 | // minimal hashmap key, this type is a convenience type that contains info | 1724 | // 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 | }; |
| 1476 | 1763 | ||
| 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.OptionalIndex | 2532 | /// 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 no | 2535 | /// 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 | }; |
| 2643 | 3015 | ||
| 2644 | /// State that is mutable during semantic analysis. This data is not used for | 3016 | /// 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) { |
| 2764 | 3136 | ||
| 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. |
| 2766 | pub const Alignment = enum(u6) { | 3138 | pub 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 | _, |
| 2769 | 3147 | ||
| 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 | } |
| 2776 | 3154 | ||
| 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 | } |
| 2783 | 3161 | ||
| ... | @@ -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 | } |
| 2794 | 3172 | ||
| 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 | } |
| 2799 | 3191 | ||
| 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 is | 3257 | /// 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, |
| 2806 | 3263 | ||
| 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 | }; |
| 2815 | 3289 | ||
| 2816 | /// Used for non-sentineled arrays that have length fitting in u32, as well as | 3290 | /// 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); |
| 3067 | 3541 | ||
| 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); |
| 3073 | 3544 | ||
| ... | @@ -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 | }, |
| 3150 | 3621 | ||
| 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 | else | 3627 | .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 | } }, |
| 3167 | 3655 | ||
| 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) }, |
| 3171 | 3661 | ||
| 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 rather | 3951 | => .{ .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 | } }, |
| 3470 | 3955 | ||
| 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 the | 3974 | // 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 | }, |
| 3482 | 3985 | ||
| ... | @@ -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 | } |
| 3605 | 4108 | ||
| 4109 | fn 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 | |||
| 4180 | fn 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 | |||
| 3606 | fn extraFuncType(ip: *const InternPool, extra_index: u32) Key.FuncType { | 4212 | fn 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 | }, |
| 3879 | 4486 | ||
| 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() instead | 4488 | .anon_struct_type => unreachable, // use getAnonStructType() instead |
| 3894 | |||
| 3895 | .union_type => unreachable, // use getUnionType() instead | 4489 | .union_type => unreachable, // use getUnionType() instead |
| 3896 | 4490 | ||
| 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 | } |
| 4637 | 5228 | ||
| 5229 | pub 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 | |||
| 5243 | pub 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 | |||
| 4638 | pub const AnonStructTypeInit = struct { | 5361 | pub 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; |
| 4999 | 5722 | ||
| 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(); |
| 5002 | 5726 | ||
| 5003 | try addStringsToMap(ip, gpa, names_map, names); | 5727 | addStringsToMap(ip, names_map, names); |
| 5004 | 5728 | ||
| 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 | } |
| 5316 | 6030 | ||
| 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); |
| 5372 | 6083 | ||
| 5373 | const names_map = try ip.addMap(gpa); | 6084 | const names_map = try ip.addMap(gpa, enum_type.fields_len); |
| 5374 | 6085 | ||
| 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); |
| 5414 | 6125 | ||
| 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 | }; |
| 5420 | 6131 | ||
| ... | @@ -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 |
| 5484 | 6195 | ||
| 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); |
| 5489 | 6200 | ||
| 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); |
| 5519 | 6230 | ||
| 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 { |
| 5553 | 6264 | ||
| 5554 | fn addStringsToMap( | 6265 | fn 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 | } |
| 5567 | 6277 | ||
| 5568 | fn addIndexesToMap( | 6278 | fn 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 | } |
| 5581 | 6290 | ||
| 5582 | fn addMap(ip: *InternPool, gpa: Allocator) Allocator.Error!MapIndex { | 6291 | fn 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 | } |
| 5587 | 6298 | ||
| ... | @@ -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)), |
| 5638 | 6350 | ||
| 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 | } |
| 6208 | 6920 | ||
| 6209 | pub fn indexToStructType(ip: *const InternPool, val: Index) Module.Struct.OptionalIndex { | ||
| 6210 | assert(val != .none); | ||
| 6211 | const tags = ip.items.items(.tag); | ||
| 6212 | if (tags[@intFromEnum(val)] != .type_struct) return .none; | ||
| 6213 | const datas = ip.items.items(.data); | ||
| 6214 | return @as(Module.Struct.Index, @enumFromInt(datas[@intFromEnum(val)])).toOptional(); | ||
| 6215 | } | ||
| 6216 | |||
| 6217 | pub fn indexToUnionType(ip: *const InternPool, val: Index) Module.Union.OptionalIndex { | ||
| 6218 | assert(val != .none); | ||
| 6219 | const tags = ip.items.items(.tag); | ||
| 6220 | switch (tags[@intFromEnum(val)]) { | ||
| 6221 | .type_union => {}, | ||
| 6222 | else => return .none, | ||
| 6223 | } | ||
| 6224 | const datas = ip.items.items(.data); | ||
| 6225 | return @as(Module.Union.Index, @enumFromInt(datas[@intFromEnum(val)])).toOptional(); | ||
| 6226 | } | ||
| 6227 | |||
| 6228 | pub fn indexToFuncType(ip: *const InternPool, val: Index) ?Key.FuncType { | 6921 | pub 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); |
| 6344 | 7034 | ||
| 6345 | // TODO: map overhead size is not taken into account | 7035 | // 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; |
| 6347 | 7037 | ||
| 6348 | std.debug.print( | 7038 | std.debug.print( |
| 6349 | \\InternPool size: {d} bytes | 7039 | \\InternPool size: {d} bytes |
| 6350 | \\ {d} items: {d} bytes | 7040 | \\ {d} items: {d} bytes |
| 6351 | \\ {d} extra: {d} bytes | 7041 | \\ {d} extra: {d} bytes |
| 6352 | \\ {d} limbs: {d} bytes | 7042 | \\ {d} limbs: {d} bytes |
| 6353 | \\ {d} structs: {d} bytes | ||
| 6354 | \\ {d} decls: {d} bytes | 7043 | \\ {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 | } |
| 6679 | 7391 | ||
| 6680 | pub fn structPtr(ip: *InternPool, index: Module.Struct.Index) *Module.Struct { | ||
| 6681 | return ip.allocated_structs.at(@intFromEnum(index)); | ||
| 6682 | } | ||
| 6683 | |||
| 6684 | pub fn structPtrConst(ip: *const InternPool, index: Module.Struct.Index) *const Module.Struct { | ||
| 6685 | return ip.allocated_structs.at(@intFromEnum(index)); | ||
| 6686 | } | ||
| 6687 | |||
| 6688 | pub fn structPtrUnwrapConst(ip: *const InternPool, index: Module.Struct.OptionalIndex) ?*const Module.Struct { | ||
| 6689 | return structPtrConst(ip, index.unwrap() orelse return null); | ||
| 6690 | } | ||
| 6691 | |||
| 6692 | pub fn declPtr(ip: *InternPool, index: Module.Decl.Index) *Module.Decl { | 7392 | pub 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 | } |
| 6703 | 7403 | ||
| 6704 | pub fn createStruct( | ||
| 6705 | ip: *InternPool, | ||
| 6706 | gpa: Allocator, | ||
| 6707 | initialization: Module.Struct, | ||
| 6708 | ) Allocator.Error!Module.Struct.Index { | ||
| 6709 | if (ip.structs_free_list.popOrNull()) |index| { | ||
| 6710 | ip.allocated_structs.at(@intFromEnum(index)).* = initialization; | ||
| 6711 | return index; | ||
| 6712 | } | ||
| 6713 | const ptr = try ip.allocated_structs.addOne(gpa); | ||
| 6714 | ptr.* = initialization; | ||
| 6715 | return @enumFromInt(ip.allocated_structs.len - 1); | ||
| 6716 | } | ||
| 6717 | |||
| 6718 | pub fn destroyStruct(ip: *InternPool, gpa: Allocator, index: Module.Struct.Index) void { | ||
| 6719 | ip.structPtr(index).* = undefined; | ||
| 6720 | ip.structs_free_list.append(gpa, index) catch { | ||
| 6721 | // In order to keep `destroyStruct` a non-fallible function, we ignore memory | ||
| 6722 | // allocation failures here, instead leaking the Struct until garbage collection. | ||
| 6723 | }; | ||
| 6724 | } | ||
| 6725 | |||
| 6726 | pub fn createDecl( | 7404 | pub 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 { |
| 7056 | 7736 | ||
| 7057 | pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 { | 7737 | pub 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 { |
| 7066 | 7746 | ||
| 7067 | pub fn aggregateTypeLenIncludingSentinel(ip: *const InternPool, ty: Index) u64 { | 7747 | pub 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, |
| 7306 | 7988 | ||
| ... | @@ -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 reuse | 8211 | // Here we could add the index to a free-list for reuse, but since |
| 8212 | // there is so little garbage created this way it's not worth it. | ||
| 7530 | } | 8213 | } |
| 7531 | } | 8214 | } |
| 8215 | |||
| 8216 | pub fn anonStructFieldTypes(ip: *const InternPool, i: Index) []const Index { | ||
| 8217 | return ip.indexToKey(i).anon_struct_type.types; | ||
| 8218 | } | ||
| 8219 | |||
| 8220 | pub 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. | ||
| 8225 | pub 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. | ||
| 8233 | pub 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 |
| 105 | 105 | ||
| 106 | /// To be eliminated in a future commit by moving more data into InternPool. | 106 | /// To be eliminated in a future commit by moving more data into InternPool. |
| 107 | /// Current uses that must be eliminated: | 107 | /// Current uses that must be eliminated: |
| 108 | /// * Struct comptime_args | ||
| 109 | /// * Struct optimized_order | ||
| 110 | /// * comptime pointer mutation | 108 | /// * comptime pointer mutation |
| 111 | /// This memory lives until the Module is destroyed. | 109 | /// This memory lives until the Module is destroyed. |
| 112 | tmp_hack_arena: std.heap.ArenaAllocator, | 110 | tmp_hack_arena: std.heap.ArenaAllocator, |
| ... | @@ -678,14 +676,10 @@ pub const Decl = struct { | ... | @@ -678,14 +676,10 @@ pub const Decl = struct { |
| 678 | 676 | ||
| 679 | /// If the Decl owns its value and it is a struct, return it, | 677 | /// If the Decl owns its value and it is a struct, return it, |
| 680 | /// otherwise null. | 678 | /// otherwise null. |
| 681 | pub fn getOwnedStruct(decl: Decl, mod: *Module) ?*Struct { | 679 | pub fn getOwnedStruct(decl: Decl, mod: *Module) ?InternPool.Key.StructType { |
| 682 | return mod.structPtrUnwrap(decl.getOwnedStructIndex(mod)); | 680 | if (!decl.owns_tv) return null; |
| 683 | } | 681 | if (decl.val.ip_index == .none) return null; |
| 684 | 682 | return mod.typeToStruct(decl.val.toType()); | |
| 685 | pub fn getOwnedStructIndex(decl: Decl, mod: *Module) Struct.OptionalIndex { | ||
| 686 | if (!decl.owns_tv) return .none; | ||
| 687 | if (decl.val.ip_index == .none) return .none; | ||
| 688 | return mod.intern_pool.indexToStructType(decl.val.toIntern()); | ||
| 689 | } | 683 | } |
| 690 | 684 | ||
| 691 | /// If the Decl owns its value and it is a union, return it, | 685 | /// If the Decl owns its value and it is a union, return it, |
| ... | @@ -795,9 +789,10 @@ pub const Decl = struct { | ... | @@ -795,9 +789,10 @@ pub const Decl = struct { |
| 795 | return decl.getExternDecl(mod) != .none; | 789 | return decl.getExternDecl(mod) != .none; |
| 796 | } | 790 | } |
| 797 | 791 | ||
| 798 | pub fn getAlignment(decl: Decl, mod: *Module) u32 { | 792 | pub fn getAlignment(decl: Decl, mod: *Module) Alignment { |
| 799 | assert(decl.has_tv); | 793 | assert(decl.has_tv); |
| 800 | return @as(u32, @intCast(decl.alignment.toByteUnitsOptional() orelse decl.ty.abiAlignment(mod))); | 794 | if (decl.alignment != .none) return decl.alignment; |
| 795 | return decl.ty.abiAlignment(mod); | ||
| 801 | } | 796 | } |
| 802 | }; | 797 | }; |
| 803 | 798 | ||
| ... | @@ -806,218 +801,6 @@ pub const EmitH = struct { | ... | @@ -806,218 +801,6 @@ pub const EmitH = struct { |
| 806 | fwd_decl: ArrayListUnmanaged(u8) = .{}, | 801 | fwd_decl: ArrayListUnmanaged(u8) = .{}, |
| 807 | }; | 802 | }; |
| 808 | 803 | ||
| 809 | pub const PropertyBoolean = enum { no, yes, unknown, wip }; | ||
| 810 | |||
| 811 | /// Represents the data that a struct declaration provides. | ||
| 812 | pub const Struct = struct { | ||
| 813 | /// Set of field names in declaration order. | ||
| 814 | fields: Fields, | ||
| 815 | /// Represents the declarations inside this struct. | ||
| 816 | namespace: Namespace.Index, | ||
| 817 | /// The Decl that corresponds to the struct itself. | ||
| 818 | owner_decl: Decl.Index, | ||
| 819 | /// Index of the struct_decl ZIR instruction. | ||
| 820 | zir_index: Zir.Inst.Index, | ||
| 821 | /// Indexes into `fields` sorted to be most memory efficient. | ||
| 822 | optimized_order: ?[*]u32 = null, | ||
| 823 | layout: std.builtin.Type.ContainerLayout, | ||
| 824 | /// If the layout is not packed, this is the noreturn type. | ||
| 825 | /// If the layout is packed, this is the backing integer type of the packed struct. | ||
| 826 | /// Whether zig chooses this type or the user specifies it, it is stored here. | ||
| 827 | /// This will be set to the noreturn type until status is `have_layout`. | ||
| 828 | backing_int_ty: Type = Type.noreturn, | ||
| 829 | status: enum { | ||
| 830 | none, | ||
| 831 | field_types_wip, | ||
| 832 | have_field_types, | ||
| 833 | layout_wip, | ||
| 834 | have_layout, | ||
| 835 | fully_resolved_wip, | ||
| 836 | // The types and all its fields have had their layout resolved. Even through pointer, | ||
| 837 | // which `have_layout` does not ensure. | ||
| 838 | fully_resolved, | ||
| 839 | }, | ||
| 840 | /// If true, has more than one possible value. However it may still be non-runtime type | ||
| 841 | /// if it is a comptime-only type. | ||
| 842 | /// If false, resolving the fields is necessary to determine whether the type has only | ||
| 843 | /// one possible value. | ||
| 844 | known_non_opv: bool, | ||
| 845 | requires_comptime: PropertyBoolean = .unknown, | ||
| 846 | have_field_inits: bool = false, | ||
| 847 | is_tuple: bool, | ||
| 848 | assumed_runtime_bits: bool = false, | ||
| 849 | |||
| 850 | pub const Index = enum(u32) { | ||
| 851 | _, | ||
| 852 | |||
| 853 | pub fn toOptional(i: Index) OptionalIndex { | ||
| 854 | return @as(OptionalIndex, @enumFromInt(@intFromEnum(i))); | ||
| 855 | } | ||
| 856 | }; | ||
| 857 | |||
| 858 | pub const OptionalIndex = enum(u32) { | ||
| 859 | none = std.math.maxInt(u32), | ||
| 860 | _, | ||
| 861 | |||
| 862 | pub fn init(oi: ?Index) OptionalIndex { | ||
| 863 | return @as(OptionalIndex, @enumFromInt(@intFromEnum(oi orelse return .none))); | ||
| 864 | } | ||
| 865 | |||
| 866 | pub fn unwrap(oi: OptionalIndex) ?Index { | ||
| 867 | if (oi == .none) return null; | ||
| 868 | return @as(Index, @enumFromInt(@intFromEnum(oi))); | ||
| 869 | } | ||
| 870 | }; | ||
| 871 | |||
| 872 | pub const Fields = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, Field); | ||
| 873 | |||
| 874 | /// The `Type` and `Value` memory is owned by the arena of the Struct's owner_decl. | ||
| 875 | pub const Field = struct { | ||
| 876 | /// Uses `noreturn` to indicate `anytype`. | ||
| 877 | /// undefined until `status` is >= `have_field_types`. | ||
| 878 | ty: Type, | ||
| 879 | /// Uses `none` to indicate no default. | ||
| 880 | default_val: InternPool.Index, | ||
| 881 | /// Zero means to use the ABI alignment of the type. | ||
| 882 | abi_align: Alignment, | ||
| 883 | /// undefined until `status` is `have_layout`. | ||
| 884 | offset: u32, | ||
| 885 | /// If true then `default_val` is the comptime field value. | ||
| 886 | is_comptime: bool, | ||
| 887 | |||
| 888 | /// Returns the field alignment. If the struct is packed, returns 0. | ||
| 889 | /// Keep implementation in sync with `Sema.structFieldAlignment`. | ||
| 890 | pub fn alignment( | ||
| 891 | field: Field, | ||
| 892 | mod: *Module, | ||
| 893 | layout: std.builtin.Type.ContainerLayout, | ||
| 894 | ) u32 { | ||
| 895 | if (field.abi_align.toByteUnitsOptional()) |abi_align| { | ||
| 896 | assert(layout != .Packed); | ||
| 897 | return @as(u32, @intCast(abi_align)); | ||
| 898 | } | ||
| 899 | |||
| 900 | const target = mod.getTarget(); | ||
| 901 | |||
| 902 | switch (layout) { | ||
| 903 | .Packed => return 0, | ||
| 904 | .Auto => { | ||
| 905 | if (target.ofmt == .c) { | ||
| 906 | return alignmentExtern(field, mod); | ||
| 907 | } else { | ||
| 908 | return field.ty.abiAlignment(mod); | ||
| 909 | } | ||
| 910 | }, | ||
| 911 | .Extern => return alignmentExtern(field, mod), | ||
| 912 | } | ||
| 913 | } | ||
| 914 | |||
| 915 | pub fn alignmentExtern(field: Field, mod: *Module) u32 { | ||
| 916 | // This logic is duplicated in Type.abiAlignmentAdvanced. | ||
| 917 | const ty_abi_align = field.ty.abiAlignment(mod); | ||
| 918 | |||
| 919 | if (field.ty.isAbiInt(mod) and field.ty.intInfo(mod).bits >= 128) { | ||
| 920 | // The C ABI requires 128 bit integer fields of structs | ||
| 921 | // to be 16-bytes aligned. | ||
| 922 | return @max(ty_abi_align, 16); | ||
| 923 | } | ||
| 924 | |||
| 925 | return ty_abi_align; | ||
| 926 | } | ||
| 927 | }; | ||
| 928 | |||
| 929 | /// Used in `optimized_order` to indicate field that is not present in the | ||
| 930 | /// runtime version of the struct. | ||
| 931 | pub const omitted_field = std.math.maxInt(u32); | ||
| 932 | |||
| 933 | pub fn getFullyQualifiedName(s: *Struct, mod: *Module) !InternPool.NullTerminatedString { | ||
| 934 | return mod.declPtr(s.owner_decl).getFullyQualifiedName(mod); | ||
| 935 | } | ||
| 936 | |||
| 937 | pub fn srcLoc(s: Struct, mod: *Module) SrcLoc { | ||
| 938 | return mod.declPtr(s.owner_decl).srcLoc(mod); | ||
| 939 | } | ||
| 940 | |||
| 941 | pub fn haveFieldTypes(s: Struct) bool { | ||
| 942 | return switch (s.status) { | ||
| 943 | .none, | ||
| 944 | .field_types_wip, | ||
| 945 | => false, | ||
| 946 | .have_field_types, | ||
| 947 | .layout_wip, | ||
| 948 | .have_layout, | ||
| 949 | .fully_resolved_wip, | ||
| 950 | .fully_resolved, | ||
| 951 | => true, | ||
| 952 | }; | ||
| 953 | } | ||
| 954 | |||
| 955 | pub fn haveLayout(s: Struct) bool { | ||
| 956 | return switch (s.status) { | ||
| 957 | .none, | ||
| 958 | .field_types_wip, | ||
| 959 | .have_field_types, | ||
| 960 | .layout_wip, | ||
| 961 | => false, | ||
| 962 | .have_layout, | ||
| 963 | .fully_resolved_wip, | ||
| 964 | .fully_resolved, | ||
| 965 | => true, | ||
| 966 | }; | ||
| 967 | } | ||
| 968 | |||
| 969 | pub fn packedFieldBitOffset(s: Struct, mod: *Module, index: usize) u16 { | ||
| 970 | assert(s.layout == .Packed); | ||
| 971 | assert(s.haveLayout()); | ||
| 972 | var bit_sum: u64 = 0; | ||
| 973 | for (s.fields.values(), 0..) |field, i| { | ||
| 974 | if (i == index) { | ||
| 975 | return @as(u16, @intCast(bit_sum)); | ||
| 976 | } | ||
| 977 | bit_sum += field.ty.bitSize(mod); | ||
| 978 | } | ||
| 979 | unreachable; // index out of bounds | ||
| 980 | } | ||
| 981 | |||
| 982 | pub const RuntimeFieldIterator = struct { | ||
| 983 | module: *Module, | ||
| 984 | struct_obj: *const Struct, | ||
| 985 | index: u32 = 0, | ||
| 986 | |||
| 987 | pub const FieldAndIndex = struct { | ||
| 988 | field: Field, | ||
| 989 | index: u32, | ||
| 990 | }; | ||
| 991 | |||
| 992 | pub fn next(it: *RuntimeFieldIterator) ?FieldAndIndex { | ||
| 993 | const mod = it.module; | ||
| 994 | while (true) { | ||
| 995 | var i = it.index; | ||
| 996 | it.index += 1; | ||
| 997 | if (it.struct_obj.fields.count() <= i) | ||
| 998 | return null; | ||
| 999 | |||
| 1000 | if (it.struct_obj.optimized_order) |some| { | ||
| 1001 | i = some[i]; | ||
| 1002 | if (i == Module.Struct.omitted_field) return null; | ||
| 1003 | } | ||
| 1004 | const field = it.struct_obj.fields.values()[i]; | ||
| 1005 | |||
| 1006 | if (!field.is_comptime and field.ty.hasRuntimeBits(mod)) { | ||
| 1007 | return FieldAndIndex{ .index = i, .field = field }; | ||
| 1008 | } | ||
| 1009 | } | ||
| 1010 | } | ||
| 1011 | }; | ||
| 1012 | |||
| 1013 | pub fn runtimeFieldIterator(s: *const Struct, module: *Module) RuntimeFieldIterator { | ||
| 1014 | return .{ | ||
| 1015 | .struct_obj = s, | ||
| 1016 | .module = module, | ||
| 1017 | }; | ||
| 1018 | } | ||
| 1019 | }; | ||
| 1020 | |||
| 1021 | pub const DeclAdapter = struct { | 804 | pub const DeclAdapter = struct { |
| 1022 | mod: *Module, | 805 | mod: *Module, |
| 1023 | 806 | ||
| ... | @@ -2893,20 +2676,10 @@ pub fn namespacePtr(mod: *Module, index: Namespace.Index) *Namespace { | ... | @@ -2893,20 +2676,10 @@ pub fn namespacePtr(mod: *Module, index: Namespace.Index) *Namespace { |
| 2893 | return mod.intern_pool.namespacePtr(index); | 2676 | return mod.intern_pool.namespacePtr(index); |
| 2894 | } | 2677 | } |
| 2895 | 2678 | ||
| 2896 | pub fn structPtr(mod: *Module, index: Struct.Index) *Struct { | ||
| 2897 | return mod.intern_pool.structPtr(index); | ||
| 2898 | } | ||
| 2899 | |||
| 2900 | pub fn namespacePtrUnwrap(mod: *Module, index: Namespace.OptionalIndex) ?*Namespace { | 2679 | pub fn namespacePtrUnwrap(mod: *Module, index: Namespace.OptionalIndex) ?*Namespace { |
| 2901 | return mod.namespacePtr(index.unwrap() orelse return null); | 2680 | return mod.namespacePtr(index.unwrap() orelse return null); |
| 2902 | } | 2681 | } |
| 2903 | 2682 | ||
| 2904 | /// This one accepts an index from the InternPool and asserts that it is not | ||
| 2905 | /// the anonymous empty struct type. | ||
| 2906 | pub fn structPtrUnwrap(mod: *Module, index: Struct.OptionalIndex) ?*Struct { | ||
| 2907 | return mod.structPtr(index.unwrap() orelse return null); | ||
| 2908 | } | ||
| 2909 | |||
| 2910 | /// Returns true if and only if the Decl is the top level struct associated with a File. | 2683 | /// Returns true if and only if the Decl is the top level struct associated with a File. |
| 2911 | pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool { | 2684 | pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool { |
| 2912 | const decl = mod.declPtr(decl_index); | 2685 | const decl = mod.declPtr(decl_index); |
| ... | @@ -3351,11 +3124,11 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void { | ... | @@ -3351,11 +3124,11 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void { |
| 3351 | 3124 | ||
| 3352 | if (!decl.owns_tv) continue; | 3125 | if (!decl.owns_tv) continue; |
| 3353 | 3126 | ||
| 3354 | if (decl.getOwnedStruct(mod)) |struct_obj| { | 3127 | if (decl.getOwnedStruct(mod)) |struct_type| { |
| 3355 | struct_obj.zir_index = inst_map.get(struct_obj.zir_index) orelse { | 3128 | struct_type.setZirIndex(ip, inst_map.get(struct_type.zir_index) orelse { |
| 3356 | try file.deleted_decls.append(gpa, decl_index); | 3129 | try file.deleted_decls.append(gpa, decl_index); |
| 3357 | continue; | 3130 | continue; |
| 3358 | }; | 3131 | }); |
| 3359 | } | 3132 | } |
| 3360 | 3133 | ||
| 3361 | if (decl.getOwnedUnion(mod)) |union_type| { | 3134 | if (decl.getOwnedUnion(mod)) |union_type| { |
| ... | @@ -3870,36 +3643,16 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { | ... | @@ -3870,36 +3643,16 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { |
| 3870 | const new_decl = mod.declPtr(new_decl_index); | 3643 | const new_decl = mod.declPtr(new_decl_index); |
| 3871 | errdefer @panic("TODO error handling"); | 3644 | errdefer @panic("TODO error handling"); |
| 3872 | 3645 | ||
| 3873 | const struct_index = try mod.createStruct(.{ | ||
| 3874 | .owner_decl = new_decl_index, | ||
| 3875 | .fields = .{}, | ||
| 3876 | .zir_index = undefined, // set below | ||
| 3877 | .layout = .Auto, | ||
| 3878 | .status = .none, | ||
| 3879 | .known_non_opv = undefined, | ||
| 3880 | .is_tuple = undefined, // set below | ||
| 3881 | .namespace = new_namespace_index, | ||
| 3882 | }); | ||
| 3883 | errdefer mod.destroyStruct(struct_index); | ||
| 3884 | |||
| 3885 | const struct_ty = try mod.intern_pool.get(gpa, .{ .struct_type = .{ | ||
| 3886 | .index = struct_index.toOptional(), | ||
| 3887 | .namespace = new_namespace_index.toOptional(), | ||
| 3888 | } }); | ||
| 3889 | // TODO: figure out InternPool removals for incremental compilation | ||
| 3890 | //errdefer mod.intern_pool.remove(struct_ty); | ||
| 3891 | |||
| 3892 | new_namespace.ty = struct_ty.toType(); | ||
| 3893 | file.root_decl = new_decl_index.toOptional(); | 3646 | file.root_decl = new_decl_index.toOptional(); |
| 3894 | 3647 | ||
| 3895 | new_decl.name = try file.fullyQualifiedName(mod); | 3648 | new_decl.name = try file.fullyQualifiedName(mod); |
| 3649 | new_decl.name_fully_qualified = true; | ||
| 3896 | new_decl.src_line = 0; | 3650 | new_decl.src_line = 0; |
| 3897 | new_decl.is_pub = true; | 3651 | new_decl.is_pub = true; |
| 3898 | new_decl.is_exported = false; | 3652 | new_decl.is_exported = false; |
| 3899 | new_decl.has_align = false; | 3653 | new_decl.has_align = false; |
| 3900 | new_decl.has_linksection_or_addrspace = false; | 3654 | new_decl.has_linksection_or_addrspace = false; |
| 3901 | new_decl.ty = Type.type; | 3655 | new_decl.ty = Type.type; |
| 3902 | new_decl.val = struct_ty.toValue(); | ||
| 3903 | new_decl.alignment = .none; | 3656 | new_decl.alignment = .none; |
| 3904 | new_decl.@"linksection" = .none; | 3657 | new_decl.@"linksection" = .none; |
| 3905 | new_decl.has_tv = true; | 3658 | new_decl.has_tv = true; |
| ... | @@ -3907,75 +3660,76 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { | ... | @@ -3907,75 +3660,76 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { |
| 3907 | new_decl.alive = true; // This Decl corresponds to a File and is therefore always alive. | 3660 | new_decl.alive = true; // This Decl corresponds to a File and is therefore always alive. |
| 3908 | new_decl.analysis = .in_progress; | 3661 | new_decl.analysis = .in_progress; |
| 3909 | new_decl.generation = mod.generation; | 3662 | new_decl.generation = mod.generation; |
| 3910 | new_decl.name_fully_qualified = true; | ||
| 3911 | 3663 | ||
| 3912 | if (file.status == .success_zir) { | 3664 | if (file.status != .success_zir) { |
| 3913 | assert(file.zir_loaded); | 3665 | new_decl.analysis = .file_failure; |
| 3914 | const main_struct_inst = Zir.main_struct_inst; | 3666 | return; |
| 3915 | const struct_obj = mod.structPtr(struct_index); | 3667 | } |
| 3916 | struct_obj.zir_index = main_struct_inst; | 3668 | assert(file.zir_loaded); |
| 3917 | const extended = file.zir.instructions.items(.data)[main_struct_inst].extended; | ||
| 3918 | const small = @as(Zir.Inst.StructDecl.Small, @bitCast(extended.small)); | ||
| 3919 | struct_obj.is_tuple = small.is_tuple; | ||
| 3920 | |||
| 3921 | var sema_arena = std.heap.ArenaAllocator.init(gpa); | ||
| 3922 | defer sema_arena.deinit(); | ||
| 3923 | const sema_arena_allocator = sema_arena.allocator(); | ||
| 3924 | |||
| 3925 | var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa); | ||
| 3926 | defer comptime_mutable_decls.deinit(); | ||
| 3927 | |||
| 3928 | var sema: Sema = .{ | ||
| 3929 | .mod = mod, | ||
| 3930 | .gpa = gpa, | ||
| 3931 | .arena = sema_arena_allocator, | ||
| 3932 | .code = file.zir, | ||
| 3933 | .owner_decl = new_decl, | ||
| 3934 | .owner_decl_index = new_decl_index, | ||
| 3935 | .func_index = .none, | ||
| 3936 | .func_is_naked = false, | ||
| 3937 | .fn_ret_ty = Type.void, | ||
| 3938 | .fn_ret_ty_ies = null, | ||
| 3939 | .owner_func_index = .none, | ||
| 3940 | .comptime_mutable_decls = &comptime_mutable_decls, | ||
| 3941 | }; | ||
| 3942 | defer sema.deinit(); | ||
| 3943 | 3669 | ||
| 3944 | if (sema.analyzeStructDecl(new_decl, main_struct_inst, struct_index)) |_| { | 3670 | var sema_arena = std.heap.ArenaAllocator.init(gpa); |
| 3945 | for (comptime_mutable_decls.items) |decl_index| { | 3671 | defer sema_arena.deinit(); |
| 3946 | const decl = mod.declPtr(decl_index); | 3672 | const sema_arena_allocator = sema_arena.allocator(); |
| 3947 | _ = try decl.internValue(mod); | ||
| 3948 | } | ||
| 3949 | new_decl.analysis = .complete; | ||
| 3950 | } else |err| switch (err) { | ||
| 3951 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3952 | error.AnalysisFail => {}, | ||
| 3953 | } | ||
| 3954 | 3673 | ||
| 3955 | if (mod.comp.whole_cache_manifest) |whole_cache_manifest| { | 3674 | var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa); |
| 3956 | const source = file.getSource(gpa) catch |err| { | 3675 | defer comptime_mutable_decls.deinit(); |
| 3957 | try reportRetryableFileError(mod, file, "unable to load source: {s}", .{@errorName(err)}); | ||
| 3958 | return error.AnalysisFail; | ||
| 3959 | }; | ||
| 3960 | 3676 | ||
| 3961 | const resolved_path = std.fs.path.resolve( | 3677 | var sema: Sema = .{ |
| 3962 | gpa, | 3678 | .mod = mod, |
| 3963 | if (file.pkg.root_src_directory.path) |pkg_path| | 3679 | .gpa = gpa, |
| 3964 | &[_][]const u8{ pkg_path, file.sub_file_path } | 3680 | .arena = sema_arena_allocator, |
| 3965 | else | 3681 | .code = file.zir, |
| 3966 | &[_][]const u8{file.sub_file_path}, | 3682 | .owner_decl = new_decl, |
| 3967 | ) catch |err| { | 3683 | .owner_decl_index = new_decl_index, |
| 3968 | try reportRetryableFileError(mod, file, "unable to resolve path: {s}", .{@errorName(err)}); | 3684 | .func_index = .none, |
| 3969 | return error.AnalysisFail; | 3685 | .func_is_naked = false, |
| 3970 | }; | 3686 | .fn_ret_ty = Type.void, |
| 3971 | errdefer gpa.free(resolved_path); | 3687 | .fn_ret_ty_ies = null, |
| 3688 | .owner_func_index = .none, | ||
| 3689 | .comptime_mutable_decls = &comptime_mutable_decls, | ||
| 3690 | }; | ||
| 3691 | defer sema.deinit(); | ||
| 3972 | 3692 | ||
| 3973 | mod.comp.whole_cache_manifest_mutex.lock(); | 3693 | const main_struct_inst = Zir.main_struct_inst; |
| 3974 | defer mod.comp.whole_cache_manifest_mutex.unlock(); | 3694 | const struct_ty = sema.getStructType( |
| 3975 | try whole_cache_manifest.addFilePostContents(resolved_path, source.bytes, source.stat); | 3695 | new_decl_index, |
| 3976 | } | 3696 | new_namespace_index, |
| 3977 | } else { | 3697 | main_struct_inst, |
| 3978 | new_decl.analysis = .file_failure; | 3698 | ) catch |err| switch (err) { |
| 3699 | error.OutOfMemory => return error.OutOfMemory, | ||
| 3700 | }; | ||
| 3701 | // TODO: figure out InternPool removals for incremental compilation | ||
| 3702 | //errdefer ip.remove(struct_ty); | ||
| 3703 | for (comptime_mutable_decls.items) |decl_index| { | ||
| 3704 | const decl = mod.declPtr(decl_index); | ||
| 3705 | _ = try decl.internValue(mod); | ||
| 3706 | } | ||
| 3707 | |||
| 3708 | new_namespace.ty = struct_ty.toType(); | ||
| 3709 | new_decl.val = struct_ty.toValue(); | ||
| 3710 | new_decl.analysis = .complete; | ||
| 3711 | |||
| 3712 | if (mod.comp.whole_cache_manifest) |whole_cache_manifest| { | ||
| 3713 | const source = file.getSource(gpa) catch |err| { | ||
| 3714 | try reportRetryableFileError(mod, file, "unable to load source: {s}", .{@errorName(err)}); | ||
| 3715 | return error.AnalysisFail; | ||
| 3716 | }; | ||
| 3717 | |||
| 3718 | const resolved_path = std.fs.path.resolve( | ||
| 3719 | gpa, | ||
| 3720 | if (file.pkg.root_src_directory.path) |pkg_path| | ||
| 3721 | &[_][]const u8{ pkg_path, file.sub_file_path } | ||
| 3722 | else | ||
| 3723 | &[_][]const u8{file.sub_file_path}, | ||
| 3724 | ) catch |err| { | ||
| 3725 | try reportRetryableFileError(mod, file, "unable to resolve path: {s}", .{@errorName(err)}); | ||
| 3726 | return error.AnalysisFail; | ||
| 3727 | }; | ||
| 3728 | errdefer gpa.free(resolved_path); | ||
| 3729 | |||
| 3730 | mod.comp.whole_cache_manifest_mutex.lock(); | ||
| 3731 | defer mod.comp.whole_cache_manifest_mutex.unlock(); | ||
| 3732 | try whole_cache_manifest.addFilePostContents(resolved_path, source.bytes, source.stat); | ||
| 3979 | } | 3733 | } |
| 3980 | } | 3734 | } |
| 3981 | 3735 | ||
| ... | @@ -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(); |
| 4057 | 3811 | ||
| 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 | } | ||
| 4070 | 3813 | ||
| 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 | } |
| 5243 | 4986 | ||
| 5244 | pub fn createStruct(mod: *Module, initialization: Struct) Allocator.Error!Struct.Index { | ||
| 5245 | return mod.intern_pool.createStruct(mod.gpa, initialization); | ||
| 5246 | } | ||
| 5247 | |||
| 5248 | pub fn destroyStruct(mod: *Module, index: Struct.Index) void { | ||
| 5249 | return mod.intern_pool.destroyStruct(mod.gpa, index); | ||
| 5250 | } | ||
| 5251 | |||
| 5252 | pub fn allocateNewDecl( | 4987 | pub 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! |
| 6202 | 5937 | ||
| 6203 | pub fn ptrType(mod: *Module, info: InternPool.Key.PtrType) Allocator.Error!Type { | 5938 | pub 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); | ||
| 6206 | 5940 | ||
| 6207 | if (info.flags.size == .C) canon_info.flags.is_allowzero = true; | 5941 | if (info.flags.size == .C) canon_info.flags.is_allowzero = true; |
| 6208 | 5942 | ||
| ... | @@ -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 the | 5944 | // type, we change it to 0 here. If this causes an assertion trip because the |
| 6211 | // pointee type needs to be resolved more, that needs to be done before calling | 5945 | // 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 | } |
| 6218 | 5952 | ||
| 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 type | 5955 | // 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. |
| 6642 | pub fn typeToStruct(mod: *Module, ty: Type) ?*Struct { | 6376 | pub 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 | |||
| 6384 | pub 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 | } |
| 6647 | 6391 | ||
| 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. |
| 6649 | pub fn typeToUnion(mod: *Module, ty: Type) ?InternPool.UnionType { | 6393 | pub 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 | } |
| 6657 | 6401 | ||
| 6658 | pub fn typeToFunc(mod: *Module, ty: Type) ?InternPool.Key.FuncType { | 6402 | pub 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] |
| 6741 | 6485 | ||
| 6742 | pub const UnionLayout = struct { | 6486 | pub 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; |
| 6765 | 6509 | ||
| 6766 | const field_align = u.fieldAlign(ip, @intCast(i)).toByteUnitsOptional() orelse | 6510 | const explicit_align = u.fieldAlign(ip, @intCast(i)); |
| 6511 | const field_align = if (explicit_align != .none) | ||
| 6512 | explicit_align | ||
| 6513 | else | ||
| 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's | 6541 | // 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 | } |
| 6835 | 6581 | ||
| 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 u64 | 6583 | pub fn unionAbiAlignment(mod: *Module, u: InternPool.UnionType) Alignment { |
| 6838 | pub fn unionAbiAlignment(mod: *Module, u: InternPool.UnionType) u32 { | ||
| 6839 | const ip = &mod.intern_pool; | 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; |
| 6845 | 6590 | ||
| 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 u64 | 6600 | pub fn unionFieldNormalAlignment(mod: *Module, u: InternPool.UnionType, field_index: u32) Alignment { |
| 6856 | pub fn unionFieldNormalAlignment(mod: *Module, u: InternPool.UnionType, field_index: u32) u32 { | ||
| 6857 | const ip = &mod.intern_pool; | 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. | ||
| 6618 | pub 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. | ||
| 6641 | pub 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 | ||
| 6657 | pub 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); |
| 2223 | 2223 | ||
| 2224 | const struct_ty = mod.typeToStruct(container_ty) orelse break :msg msg; | 2224 | const struct_type = mod.typeToStruct(container_ty) orelse break :msg msg; |
| 2225 | const default_value_src = mod.fieldSrcLoc(struct_ty.owner_decl, .{ | 2225 | const default_value_src = mod.fieldSrcLoc(struct_type.decl.unwrap().?, .{ |
| 2226 | .index = field_index, | 2226 | .index = field_index, |
| 2227 | .range = .value, | 2227 | .range = .value, |
| 2228 | }); | 2228 | }); |
| ... | @@ -2504,23 +2504,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 | } |
| 2511 | 2509 | ||
| 2512 | fn validateAlign( | 2510 | fn validateAlign( |
| 2513 | sema: *Sema, | 2511 | sema: *Sema, |
| 2514 | block: *Block, | 2512 | block: *Block, |
| 2515 | src: LazySrcLoc, | 2513 | src: LazySrcLoc, |
| 2516 | alignment: u32, | 2514 | alignment: u64, |
| 2517 | ) !void { | 2515 | ) !Alignment { |
| 2518 | if (alignment == 0) return sema.fail(block, src, "alignment must be >= 1", .{}); | 2516 | 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 | |||
| 2521 | fn 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 | } |
| 2525 | 2535 | ||
| 2526 | pub fn resolveAlign( | 2536 | pub 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); |
| 2621 | 2631 | ||
| 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 | } |
| 2722 | 2732 | ||
| 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 | } |
| 2803 | 2813 | ||
| 2804 | pub fn analyzeStructDecl( | 2814 | pub 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); |
| 2815 | 2826 | ||
| 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 | } |
| 2839 | 2849 | ||
| 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 | } |
| 2842 | 2868 | ||
| 2843 | fn zirStructDecl( | 2869 | fn 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); |
| 2876 | 2902 | ||
| 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 compilation | 2911 | // TODO: figure out InternPool removals for incremental compilation |
| 2901 | //errdefer mod.intern_pool.remove(struct_ty); | 2912 | //errdefer ip.remove(struct_ty); |
| 2902 | 2913 | ||
| 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(); |
| 2906 | 2917 | ||
| 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; |
| 3197 | 3207 | ||
| 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 | else | 3259 | 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 | } |
| 3499 | 3509 | ||
| 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 in | 3518 | // 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 | } |
| 3512 | 3523 | ||
| ... | @@ -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 |
| 3810 | 3821 | ||
| 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); |
| 3814 | 3825 | ||
| 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); |
| 3973 | 3984 | ||
| 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); |
| 4095 | 4106 | ||
| 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 implicit | 4699 | // 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; |
| 4693 | 4705 | ||
| 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 | } |
| 4724 | 4735 | ||
| 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)); |
| 4753 | 4765 | ||
| 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( |
| 4830 | 4843 | ||
| 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 | } |
| 4854 | 4866 | ||
| 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( |
| 5255 | fn failWithBadStructFieldAccess( | 5268 | fn 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; |
| 5264 | 5277 | const decl = mod.declPtr(struct_type.decl.unwrap().?); | |
| 5265 | const fqn = try struct_obj.getFullyQualifiedName(mod); | 5278 | const fqn = try decl.getFullyQualifiedName(mod); |
| 5266 | 5279 | ||
| 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 |
| 5787 | 5800 | ||
| 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 | } |
| 5794 | 5805 | ||
| 5795 | fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 5806 | fn 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 | } |
| 8639 | 8650 | ||
| 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/6597 | 8718 | // 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( |
| 8825 | 8836 | ||
| 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 emit | 10797 | // 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 | } |
| 13032 | 13039 | ||
| 13033 | fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 13040 | fn 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); |
| 13767 | 13774 | ||
| 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); |
| 14032 | 14039 | ||
| 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); |
| 15980 | 15987 | ||
| 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 alignment | 16888 | .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 | }; |
| 17201 | 17208 | ||
| 17202 | // Build our ?[]const Error value | 17209 | // 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 alignment | 17356 | .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 |
| 17461 | 17468 | ||
| 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 | }; |
| 17466 | 17473 | ||
| 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 alignment | 17500 | .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 | }; |
| 17579 | 17586 | ||
| 17580 | try sema.resolveTypeLayout(ty); // Getting alignment requires type layout | 17587 | try sema.resolveTypeLayout(ty); // Getting alignment requires type layout |
| 17581 | const layout = ty.containerLayout(mod); | ||
| 17582 | 17588 | ||
| 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 | |
| 17650 | 17656 | 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 dupe | 17657 | // 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 | }; |
| 17679 | 17686 | ||
| 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 | null | 17688 | const default_val_ptr = try sema.optRefValue(block, field_ty, opt_default_val); |
| 17682 | else | 17689 | 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 | }; | ||
| 17686 | 17697 | ||
| 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 alignment | 17728 | .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 |
| 17733 | 17744 | ||
| 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 | } }); |
| 17743 | 17752 | ||
| ... | @@ -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 | }; |
| 17756 | 17765 | ||
| 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 alignment | 17874 | .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 |
| 18433 | 18444 | ||
| 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; |
| 18931 | 18941 | ||
| 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 | } |
| 18990 | 19000 | ||
| 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( |
| 19226 | 19236 | ||
| 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; |
| 19297 | 19306 | ||
| 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 | } |
| 19314 | 19324 | ||
| 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( |
| 19502 | 19513 | ||
| 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; |
| 19518 | 19529 | ||
| 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( |
| 19640 | 19651 | ||
| 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( |
| 19648 | 19659 | ||
| 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 | } |
| 19663 | 19674 | ||
| 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( |
| 19749 | 19760 | ||
| 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) orelse | 19863 | 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 | ); |
| 20179 | 20190 | ||
| 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 | ).?); |
| 20193 | 20206 | ||
| ... | @@ -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 | ).?); |
| 20210 | 20224 | ||
| ... | @@ -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 | ).?); |
| 20248 | 20270 | ||
| ... | @@ -20307,7 +20329,7 @@ fn zirReify( | ... | @@ -20307,7 +20329,7 @@ fn zirReify( |
| 20307 | } | 20329 | } |
| 20308 | } | 20330 | } |
| 20309 | 20331 | ||
| 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 | ).?); |
| 20335 | 20360 | ||
| ... | @@ -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 | ).?); |
| 20355 | 20381 | ||
| ... | @@ -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 | ).?); |
| 20369 | 20397 | ||
| ... | @@ -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 | ).?); |
| 20393 | 20422 | ||
| ... | @@ -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 | ).?); |
| 20424 | 20458 | ||
| ... | @@ -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 | ).?); |
| 20452 | 20490 | ||
| ... | @@ -20496,11 +20534,13 @@ fn zirReify( | ... | @@ -20496,11 +20534,13 @@ fn zirReify( |
| 20496 | 20534 | ||
| 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 | ).?); |
| 20506 | 20546 | ||
| ... | @@ -20515,7 +20555,7 @@ fn zirReify( | ... | @@ -20515,7 +20555,7 @@ fn zirReify( |
| 20515 | }); | 20555 | }); |
| 20516 | } | 20556 | } |
| 20517 | 20557 | ||
| 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 | } |
| 20530 | 20570 | ||
| 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 | ).?); |
| 20552 | 20593 | ||
| ... | @@ -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 | ).?); |
| 20610 | 20655 | ||
| ... | @@ -20644,14 +20689,17 @@ fn zirReify( | ... | @@ -20644,14 +20689,17 @@ fn zirReify( |
| 20644 | 20689 | ||
| 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 | ).?); |
| 20657 | 20705 | ||
| ... | @@ -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 | ).?); |
| 20834 | 20888 | ||
| ... | @@ -20844,15 +20898,9 @@ fn zirReify( | ... | @@ -20844,15 +20898,9 @@ fn zirReify( |
| 20844 | } | 20898 | } |
| 20845 | 20899 | ||
| 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) orelse | 20905 | 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 | ).?); |
| 20876 | 20927 | ||
| ... | @@ -20931,6 +20982,8 @@ fn reifyStruct( | ... | @@ -20931,6 +20982,8 @@ fn reifyStruct( |
| 20931 | .Auto => {}, | 20982 | .Auto => {}, |
| 20932 | }; | 20983 | }; |
| 20933 | 20984 | ||
| 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 an | 20988 | // 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 | } |
| 20948 | 21001 | ||
| 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 compilation | 21019 | // 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; | ||
| 20976 | 21022 | ||
| 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(); | ||
| 20980 | 21025 | ||
| 20981 | // Fields | 21026 | // 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 | ).?); |
| 21003 | 21050 | ||
| ... | @@ -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 | } |
| 21041 | 21088 | ||
| ... | @@ -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 | } |
| 21053 | 21100 | ||
| 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 | }; | ||
| 21061 | 21105 | ||
| 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 | } |
| 21108 | 21152 | ||
| 21109 | if (layout == .Packed) { | 21153 | if (layout == .Packed) { |
| 21110 | struct_obj.status = .layout_wip; | 21154 | for (0..struct_type.field_types.len) |index| { |
| 21111 | 21155 | 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 | } |
| 21122 | 21165 | ||
| 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 | } |
| 21127 | 21170 | ||
| 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 | } |
| 21138 | 21180 | ||
| 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 | } |
| 21478 | 21522 | ||
| 21479 | fn ptrFromIntVal(sema: *Sema, block: *Block, operand_src: LazySrcLoc, operand_val: Value, ptr_ty: Type, ptr_align: u32) !Value { | 21523 | fn 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)}); |
| 21486 | 21537 | ||
| 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 | } |
| 21797 | 21848 | ||
| 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 first | 21933 | // 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 | } |
| 21930 | 21992 | ||
| 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 instructions | 22012 | // 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); |
| 22006 | 22072 | ||
| 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 | }); |
| 22286 | 22352 | ||
| 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 | } |
| 22301 | 22368 | ||
| 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; |
| 22547 | 22615 | ||
| 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); |
| 22550 | 22618 | ||
| 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 | } |
| 23729 | 23797 | ||
| 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); |
| 23732 | 23800 | ||
| 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); |
| 23735 | 23803 | ||
| 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; |
| 24271 | 24339 | ||
| 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; |
| 24282 | 24350 | ||
| 24283 | // ok1: dest >= src + len | 24351 | // 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; |
| 24557 | 24617 | ||
| 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; |
| 25239 | 25299 | ||
| 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 | }); |
| 25246 | 25307 | ||
| 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); |
| 26088 | 26149 | ||
| 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( |
| 26108 | 26169 | ||
| 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) orelse | 26362 | 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]; | ||
| 26305 | 26365 | ||
| 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); |
| 26530 | 26591 | ||
| 26531 | try sema.resolveTypeFields(struct_ty); | 26592 | try sema.resolveTypeFields(struct_ty); |
| 26532 | try sema.resolveStructLayout(struct_ty); | 26593 | try sema.resolveStructLayout(struct_ty); |
| 26533 | 26594 | ||
| 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 | } |
| 26545 | 26606 | ||
| 26546 | const struct_obj = mod.typeToStruct(struct_ty).?; | 26607 | const struct_type = mod.typeToStruct(struct_ty).?; |
| 26547 | 26608 | ||
| 26548 | const field_index_big = struct_obj.fields.getIndex(field_name) orelse | 26609 | 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); | ||
| 26551 | 26611 | ||
| 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 | } |
| 26569 | 26630 | ||
| 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); |
| 26574 | 26635 | ||
| 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( |
| 26583 | 26644 | ||
| 26584 | const target = mod.getTarget(); | 26645 | const target = mod.getTarget(); |
| 26585 | 26646 | ||
| 26586 | const parent_align = struct_ptr_ty_info.flags.alignment.toByteUnitsOptional() orelse | 26647 | const parent_align = if (struct_ptr_ty_info.flags.alignment != .none) |
| 26648 | struct_ptr_ty_info.flags.alignment | ||
| 26649 | else | ||
| 26587 | try sema.typeAbiAlignment(struct_ptr_ty_info.child.toType()); | 26650 | try sema.typeAbiAlignment(struct_ptr_ty_info.child.toType()); |
| 26588 | 26651 | ||
| 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); |
| 26591 | 26654 | ||
| 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; | ||
| 26595 | 26659 | ||
| 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; |
| 26602 | 26666 | ||
| ... | @@ -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 | } |
| 26609 | 26673 | ||
| 26610 | ptr_ty_data.flags.alignment = Alignment.fromByteUnits(parent_align); | 26674 | ptr_ty_data.flags.alignment = parent_align; |
| 26611 | 26675 | ||
| 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 stores | 26677 | // 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 not | 26681 | // targets before adding the necessary complications to this code. This will not |
| 26618 | // cause miscompilations; it only means the field pointer uses bit masking when it | 26682 | // 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 and | 26684 | 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, in | 26698 | // 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 alignment | 26707 | // 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 | } |
| 26645 | 26718 | ||
| 26646 | const ptr_field_ty = try mod.ptrType(ptr_ty_data); | 26719 | const ptr_field_ty = try sema.ptrType(ptr_ty_data); |
| 26647 | 26720 | ||
| 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); |
| 26682 | 26756 | ||
| 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]; | ||
| 26693 | 26762 | ||
| 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 | } |
| 26697 | 26768 | ||
| 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 | } |
| 26705 | 26778 | ||
| 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 | } |
| 26793 | 26867 | ||
| 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 | } |
| 26797 | 26872 | ||
| ... | @@ -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 | } |
| 26975 | 27054 | ||
| ... | @@ -27194,7 +27273,7 @@ fn tupleFieldPtr( | ... | @@ -27194,7 +27273,7 @@ fn tupleFieldPtr( |
| 27194 | } | 27273 | } |
| 27195 | 27274 | ||
| 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); |
| 27266 | 27345 | ||
| 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 | } |
| 27270 | 27350 | ||
| ... | @@ -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, |
| 28272 | 28352 | ||
| ... | @@ -28312,6 +28392,11 @@ const InMemoryCoercionResult = union(enum) { | ... | @@ -28312,6 +28392,11 @@ const InMemoryCoercionResult = union(enum) { |
| 28312 | wanted: u64, | 28392 | wanted: u64, |
| 28313 | }; | 28393 | }; |
| 28314 | 28394 | ||
| 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 or | 29218 | 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() orelse | 29221 | 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()); | ||
| 29138 | 29225 | ||
| 29139 | const dest_align = dest_info.flags.alignment.toByteUnitsOptional() orelse | 29226 | 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()); | ||
| 29141 | 29230 | ||
| 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; |
| 30380 | 30469 | ||
| 30381 | const inst_align = inst_info.flags.alignment.toByteUnitsOptional() orelse | 30470 | const inst_align = if (inst_info.flags.alignment != .none) |
| 30471 | inst_info.flags.alignment | ||
| 30472 | else | ||
| 30382 | inst_info.child.toType().abiAlignment(mod); | 30473 | inst_info.child.toType().abiAlignment(mod); |
| 30383 | 30474 | ||
| 30384 | const dest_align = dest_info.flags.alignment.toByteUnitsOptional() orelse | 30475 | const dest_align = if (dest_info.flags.alignment != .none) |
| 30476 | dest_info.flags.alignment | ||
| 30477 | else | ||
| 30385 | dest_info.child.toType().abiAlignment(mod); | 30478 | dest_info.child.toType().abiAlignment(mod); |
| 30386 | 30479 | ||
| 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 | else | 30691 | 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 | else | 30697 | 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 | } |
| 30871 | 30964 | ||
| 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); |
| 30876 | 30969 | ||
| ... | @@ -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 | else | 30984 | 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 | }; |
| 30910 | 31000 | ||
| 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; |
| 30930 | 31021 | ||
| 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 location | 31024 | 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 | } |
| 30950 | 31041 | ||
| ... | @@ -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 | else | 31097 | 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 | }; |
| 31017 | 31102 | ||
| ... | @@ -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", .{}); |
| 31020 | 31105 | ||
| 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 | }; |
| 31031 | 31116 | ||
| 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); |
| 31033 | 31118 | ||
| 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 | }; |
| 31043 | 31128 | ||
| 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); |
| 31060 | 31145 | ||
| 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; |
| 31063 | 31149 | ||
| 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 | }; |
| 31069 | 31155 | ||
| 31070 | const field_src = inst_src; // TODO better source location | 31156 | 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 |
| 31229 | 31315 | ||
| 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( |
| 31283 | 31369 | ||
| 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; |
| 31667 | 31753 | ||
| 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); |
| 31887 | 31973 | ||
| 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 | } |
| 31948 | 32034 | ||
| 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 | } |
| 33182 | 33268 | ||
| 33183 | // Note that the align can be always non-zero; Module.ptrType will canonicalize it | 33269 | // 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() orelse | 33271 | 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() orelse | 33275 | |
| 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( |
| 33208 | 33299 | ||
| 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 | }, |
| 33213 | 33304 | ||
| 33214 | .ptr => { | 33305 | .ptr => { |
| ... | @@ -33260,12 +33351,17 @@ fn resolvePeerTypesInner( | ... | @@ -33260,12 +33351,17 @@ fn resolvePeerTypesInner( |
| 33260 | } }; | 33351 | } }; |
| 33261 | 33352 | ||
| 33262 | // Note that the align can be always non-zero; Type.ptr will canonicalize it | 33353 | // 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() orelse | 33355 | if (ptr_info.flags.alignment != .none) |
| 33265 | ptr_info.child.toType().abiAlignment(mod), | 33356 | ptr_info.flags.alignment |
| 33266 | peer_info.flags.alignment.toByteUnitsOptional() orelse | 33357 | 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 | ); | ||
| 33269 | 33365 | ||
| 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 | } |
| 33515 | 33611 | ||
| 33516 | return .{ .success = try mod.ptrType(opt_ptr_info.?) }; | 33612 | return .{ .success = try sema.ptrType(opt_ptr_info.?) }; |
| 33517 | }, | 33613 | }, |
| 33518 | 33614 | ||
| 33519 | .func => { | 33615 | .func => { |
| ... | @@ -33802,8 +33898,9 @@ fn resolvePeerTypesInner( | ... | @@ -33802,8 +33898,9 @@ fn resolvePeerTypesInner( |
| 33802 | } | 33898 | } |
| 33803 | 33899 | ||
| 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 | } |
| 34192 | 34289 | ||
| 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. | ||
| 34292 | pub 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 | |||
| 34193 | fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { | 34347 | fn 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 | }; | ||
| 34214 | 34356 | ||
| 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 | } | ||
| 34226 | 34361 | ||
| 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); | ||
| 34230 | 34372 | ||
| 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); |
| 34233 | 34375 | ||
| 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 | } |
| 34243 | 34386 | ||
| 34244 | if (struct_obj.layout == .Auto and !struct_obj.is_tuple and | 34387 | 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 | } | ||
| 34248 | 34402 | ||
| 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 | else | 34406 | 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; | ||
| 34255 | 34426 | ||
| 34256 | const AlignSortContext = struct { | 34427 | const AlignSortContext = struct { |
| 34257 | struct_obj: *Module.Struct, | 34428 | aligns: []const Alignment, |
| 34258 | sema: *Sema, | ||
| 34259 | 34429 | ||
| 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 anything | 34461 | |
| 34462 | // Calculate size, alignment, and field offsets. | ||
| 34463 | const offsets = struct_type.offsets.get(ip); | ||
| 34464 | var it = struct_type.iterateRuntimeOrder(ip); | ||
| 34465 | var offset: u64 = 0; | ||
| 34466 | while (it.next()) |i| { | ||
| 34467 | offsets[i] = @intCast(aligns[i].forward(offset)); | ||
| 34468 | offset = offsets[i] + sizes[i]; | ||
| 34469 | } | ||
| 34470 | struct_type.size(ip).* = @intCast(big_align.forward(offset)); | ||
| 34471 | const flags = struct_type.flagsPtr(ip); | ||
| 34472 | flags.alignment = big_align; | ||
| 34473 | flags.layout_resolved = true; | ||
| 34474 | _ = try sema.typeRequiresComptime(ty); | ||
| 34276 | } | 34475 | } |
| 34277 | 34476 | ||
| 34278 | fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!void { | 34477 | fn 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; | ||
| 34280 | 34480 | ||
| 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); |
| 34288 | 34483 | ||
| 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); |
| 34293 | 34532 | ||
| ... | @@ -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; |
| 34302 | 34541 | ||
| 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 | }; |
| 34348 | 34553 | ||
| 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 | } |
| 34388 | 34569 | ||
| ... | @@ -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); |
| 34533 | 34714 | ||
| 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).?; |
| 34537 | 34718 | ||
| 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 | } | ||
| 34542 | 34721 | ||
| 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 to | 34723 | // 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; | ||
| 34549 | 34725 | ||
| 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 | } |
| 34560 | 34731 | ||
| 34561 | fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void { | 34732 | fn 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 { |
| 34591 | 34762 | ||
| 34592 | pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void { | 34763 | pub 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(); | ||
| 34594 | 34767 | ||
| 34595 | switch (ty.toIntern()) { | 34768 | switch (ty_ip) { |
| 34596 | .var_args_param_type => unreachable, | 34769 | .var_args_param_type => unreachable, |
| 34597 | 34770 | ||
| 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, |
| 34675 | 34848 | ||
| 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 |
| 34716 | 34884 | ||
| 34717 | fn resolveTypeFieldsStruct( | 34885 | fn 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); | ||
| 34752 | 34920 | ||
| 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 | } |
| 34757 | 34923 | ||
| 34758 | fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Key.UnionType) CompileError!void { | 34924 | fn 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 | } |
| 34938 | 35104 | ||
| 34939 | fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void { | 35105 | fn 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; |
| 34979 | 35152 | ||
| 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; |
| 34987 | 35160 | return; | |
| 34988 | const decl = mod.declPtr(decl_index); | 35161 | }, |
| 34989 | 35162 | }; | |
| 34990 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); | ||
| 34991 | defer analysis_arena.deinit(); | ||
| 34992 | 35163 | ||
| 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); |
| 35023 | 35194 | ||
| 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; | ||
| 35035 | 35205 | ||
| 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; |
| 35058 | 35228 | ||
| 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_comment | 35236 | 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; |
| 35074 | 35246 | ||
| 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 | s | 35249 | const field_name = try ip.getOrPutString(gpa, field_name_zir); |
| 35078 | else | 35250 | if (struct_type.addFieldName(ip, field_name)) |other_index| { |
| 35079 | try std.fmt.allocPrint(sema.arena, "{d}", .{field_i})); | 35251 | const msg = msg: { |
| 35080 | 35252 | 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); | ||
| 35087 | 35255 | ||
| 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 | }; | ||
| 35103 | 35264 | ||
| 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 | } |
| 35154 | 35316 | ||
| 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; | ||
| 35157 | 35318 | ||
| 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); | ||
| 35194 | 35356 | ||
| 35195 | try sema.explainWhyTypeIsNotExtern(msg, ty_src, field.ty, .struct_field); | 35357 | try sema.explainWhyTypeIsNotExtern(msg, ty_src, field_ty, .struct_field); |
| 35196 | 35358 | ||
| 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); | ||
| 35209 | 35372 | ||
| 35210 | try sema.explainWhyTypeIsNotPacked(msg, ty_src, field.ty); | 35373 | try sema.explainWhyTypeIsNotPacked(msg, ty_src, field_ty); |
| 35211 | 35374 | ||
| 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 | } |
| 35217 | 35382 | ||
| 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 | } |
| 35234 | 35400 | ||
| 35235 | extra_index += zir_field.init_body_len; | 35401 | extra_index += zir_field.init_body_len; |
| 35236 | } | 35402 | } |
| 35237 | 35403 | ||
| 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. | ||
| 35239 | 35406 | ||
| 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 | } |
| 35281 | 35447 | ||
| 35282 | fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.UnionType) CompileError!void { | 35448 | fn 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 { |
| 36081 | 36249 | ||
| 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 | } | ||
| 36105 | 36252 | ||
| 36106 | // In this case the struct has no runtime-known fields and | 36253 | if (struct_type.field_types.len == 0) { |
| 36254 | // In this case the struct has no fields at all and | ||
| 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 | } |
| 36113 | 36261 | ||
| 36114 | // In this case the struct has no fields at all and | 36262 | const field_vals = try sema.arena.alloc( |
| 36263 | InternPool.Index, | ||
| 36264 | struct_type.field_types.len, | ||
| 36265 | ); | ||
| 36266 | for (field_vals, 0..) |*field_val, i| { | ||
| 36267 | if (struct_type.fieldIsComptime(ip, i)) { | ||
| 36268 | field_val.* = struct_type.field_inits.get(ip)[i]; | ||
| 36269 | continue; | ||
| 36270 | } | ||
| 36271 | const field_ty = struct_type.field_types.get(ip)[i].toType(); | ||
| 36272 | if (field_ty.eql(ty, mod)) { | ||
| 36273 | const msg = try Module.ErrorMsg.create( | ||
| 36274 | sema.gpa, | ||
| 36275 | mod.declPtr(struct_type.decl.unwrap().?).srcLoc(mod), | ||
| 36276 | "struct '{}' depends on itself", | ||
| 36277 | .{ty.fmt(mod)}, | ||
| 36278 | ); | ||
| 36279 | try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{}); | ||
| 36280 | return sema.failWithOwnedErrorMsg(null, msg); | ||
| 36281 | } | ||
| 36282 | if (try sema.typeHasOnePossibleValue(field_ty)) |field_opv| { | ||
| 36283 | field_val.* = try field_opv.intern(field_ty, mod); | ||
| 36284 | } else return null; | ||
| 36285 | } | ||
| 36286 | |||
| 36287 | // In this case the struct has no runtime-known fields and | ||
| 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 | }, |
| 36121 | 36294 | ||
| ... | @@ -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); |
| 36268 | 36441 | ||
| 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; |
| 36584 | 36761 | ||
| 36585 | try sema.resolveTypeFieldsStruct(ty, struct_obj); | 36762 | try sema.resolveTypeFieldsStruct(ty.toIntern(), struct_type); |
| 36763 | |||
| 36764 | struct_type.flagsPtr(ip).requires_comptime = .wip; | ||
| 36586 | 36765 | ||
| 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 | } |
| 36675 | 36859 | ||
| 36676 | fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!u32 { | 36860 | fn 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 | } |
| 36679 | 36863 | ||
| 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 u64 | 36866 | fn unionFieldAlignment(sema: *Sema, u: InternPool.UnionType, field_index: u32) !Alignment { |
| 36683 | fn unionFieldAlignment(sema: *Sema, u: InternPool.UnionType, field_index: u32) !u32 { | ||
| 36684 | const mod = sema.mod; | 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 | } |
| 36691 | 36875 | ||
| 36692 | /// Keep implementation in sync with `Module.Struct.Field.alignment`. | 36876 | /// Keep implementation in sync with `Module.structFieldAlignment`. |
| 36693 | fn structFieldAlignment(sema: *Sema, field: Module.Struct.Field, layout: std.builtin.Type.ContainerLayout) !u32 { | 36877 | fn 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 | // extern | 36891 | // 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) orelse | 36946 | 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 | } |
| 36765 | 36950 | ||
| ... | @@ -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 { |
| 37381 | 37560 | ||
| 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 { |
| 37391 | 37570 | ||
| 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 on | 37585 | // 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 | |||
| 37656 | fn 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( |
| 135 | 135 | ||
| 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 panic | 139 | 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 panic | 158 | 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(", "); |
| 433 | 438 | ||
| 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 | }; |
| 2846 | 2849 |
src/arch/aarch64/CodeGen.zig+20-27| ... | @@ -23,6 +23,7 @@ const DW = std.dwarf; | ... | @@ -23,6 +23,7 @@ const DW = std.dwarf; |
| 23 | const leb128 = std.leb; | 23 | const leb128 = std.leb; |
| 24 | const log = std.log.scoped(.codegen); | 24 | const log = std.log.scoped(.codegen); |
| 25 | const build_options = @import("build_options"); | 25 | const build_options = @import("build_options"); |
| 26 | const Alignment = InternPool.Alignment; | ||
| 26 | 27 | ||
| 27 | const CodeGenError = codegen.CodeGenError; | 28 | const CodeGenError = codegen.CodeGenError; |
| 28 | const Result = codegen.Result; | 29 | const Result = codegen.Result; |
| ... | @@ -506,11 +507,9 @@ fn gen(self: *Self) !void { | ... | @@ -506,11 +507,9 @@ fn gen(self: *Self) !void { |
| 506 | // (or w0 when pointer size is 32 bits). As this register | 507 | // (or w0 when pointer size is 32 bits). As this register |
| 507 | // might get overwritten along the way, save the address | 508 | // might get overwritten along the way, save the address |
| 508 | // to the stack. | 509 | // to the stack. |
| 509 | const ptr_bits = self.target.ptrBitWidth(); | ||
| 510 | const ptr_bytes = @divExact(ptr_bits, 8); | ||
| 511 | const ret_ptr_reg = self.registerAlias(.x0, Type.usize); | 510 | const ret_ptr_reg = self.registerAlias(.x0, Type.usize); |
| 512 | 511 | ||
| 513 | const stack_offset = try self.allocMem(ptr_bytes, ptr_bytes, null); | 512 | const stack_offset = try self.allocMem(8, .@"8", null); |
| 514 | 513 | ||
| 515 | try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = ret_ptr_reg }); | 514 | try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = ret_ptr_reg }); |
| 516 | self.ret_mcv = MCValue{ .stack_offset = stack_offset }; | 515 | self.ret_mcv = MCValue{ .stack_offset = stack_offset }; |
| ... | @@ -998,11 +997,11 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { | ... | @@ -998,11 +997,11 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { |
| 998 | fn allocMem( | 997 | fn allocMem( |
| 999 | self: *Self, | 998 | self: *Self, |
| 1000 | abi_size: u32, | 999 | abi_size: u32, |
| 1001 | abi_align: u32, | 1000 | abi_align: Alignment, |
| 1002 | maybe_inst: ?Air.Inst.Index, | 1001 | maybe_inst: ?Air.Inst.Index, |
| 1003 | ) !u32 { | 1002 | ) !u32 { |
| 1004 | assert(abi_size > 0); | 1003 | assert(abi_size > 0); |
| 1005 | assert(abi_align > 0); | 1004 | assert(abi_align != .none); |
| 1006 | 1005 | ||
| 1007 | // In order to efficiently load and store stack items that fit | 1006 | // In order to efficiently load and store stack items that fit |
| 1008 | // into registers, we bump up the alignment to the next power of | 1007 | // into registers, we bump up the alignment to the next power of |
| ... | @@ -1010,10 +1009,10 @@ fn allocMem( | ... | @@ -1010,10 +1009,10 @@ fn allocMem( |
| 1010 | const adjusted_align = if (abi_size > 8) | 1009 | const adjusted_align = if (abi_size > 8) |
| 1011 | abi_align | 1010 | abi_align |
| 1012 | else | 1011 | else |
| 1013 | std.math.ceilPowerOfTwoAssert(u32, abi_size); | 1012 | Alignment.fromNonzeroByteUnits(std.math.ceilPowerOfTwoAssert(u64, abi_size)); |
| 1014 | 1013 | ||
| 1015 | // TODO find a free slot instead of always appending | 1014 | // TODO find a free slot instead of always appending |
| 1016 | const offset = mem.alignForward(u32, self.next_stack_offset, adjusted_align) + abi_size; | 1015 | const offset: u32 = @intCast(adjusted_align.forward(self.next_stack_offset) + abi_size); |
| 1017 | self.next_stack_offset = offset; | 1016 | self.next_stack_offset = offset; |
| 1018 | self.max_end_stack = @max(self.max_end_stack, self.next_stack_offset); | 1017 | self.max_end_stack = @max(self.max_end_stack, self.next_stack_offset); |
| 1019 | 1018 | ||
| ... | @@ -1515,12 +1514,9 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1515,12 +1514,9 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1515 | const len = try self.resolveInst(bin_op.rhs); | 1514 | const len = try self.resolveInst(bin_op.rhs); |
| 1516 | const len_ty = self.typeOf(bin_op.rhs); | 1515 | const len_ty = self.typeOf(bin_op.rhs); |
| 1517 | 1516 | ||
| 1518 | const ptr_bits = self.target.ptrBitWidth(); | 1517 | const stack_offset = try self.allocMem(16, .@"8", inst); |
| 1519 | const ptr_bytes = @divExact(ptr_bits, 8); | ||
| 1520 | |||
| 1521 | const stack_offset = try self.allocMem(ptr_bytes * 2, ptr_bytes * 2, inst); | ||
| 1522 | try self.genSetStack(ptr_ty, stack_offset, ptr); | 1518 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 1523 | try self.genSetStack(len_ty, stack_offset - ptr_bytes, len); | 1519 | try self.genSetStack(len_ty, stack_offset - 8, len); |
| 1524 | break :result MCValue{ .stack_offset = stack_offset }; | 1520 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1525 | }; | 1521 | }; |
| 1526 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1522 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| ... | @@ -3285,9 +3281,9 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3285,9 +3281,9 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 3285 | break :result MCValue{ .register = reg }; | 3281 | break :result MCValue{ .register = reg }; |
| 3286 | } | 3282 | } |
| 3287 | 3283 | ||
| 3288 | const optional_abi_size = @as(u32, @intCast(optional_ty.abiSize(mod))); | 3284 | const optional_abi_size: u32 = @intCast(optional_ty.abiSize(mod)); |
| 3289 | const optional_abi_align = optional_ty.abiAlignment(mod); | 3285 | const optional_abi_align = optional_ty.abiAlignment(mod); |
| 3290 | const offset = @as(u32, @intCast(payload_ty.abiSize(mod))); | 3286 | const offset: u32 = @intCast(payload_ty.abiSize(mod)); |
| 3291 | 3287 | ||
| 3292 | const stack_offset = try self.allocMem(optional_abi_size, optional_abi_align, inst); | 3288 | const stack_offset = try self.allocMem(optional_abi_size, optional_abi_align, inst); |
| 3293 | try self.genSetStack(payload_ty, stack_offset, operand); | 3289 | try self.genSetStack(payload_ty, stack_offset, operand); |
| ... | @@ -3376,7 +3372,7 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3376,7 +3372,7 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3376 | fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { | 3372 | fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 3377 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3373 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3378 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 3374 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 3379 | const ptr_bits = self.target.ptrBitWidth(); | 3375 | const ptr_bits = 64; |
| 3380 | const ptr_bytes = @divExact(ptr_bits, 8); | 3376 | const ptr_bytes = @divExact(ptr_bits, 8); |
| 3381 | const mcv = try self.resolveInst(ty_op.operand); | 3377 | const mcv = try self.resolveInst(ty_op.operand); |
| 3382 | switch (mcv) { | 3378 | switch (mcv) { |
| ... | @@ -3400,7 +3396,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3400,7 +3396,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 3400 | fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { | 3396 | fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3401 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3397 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3402 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 3398 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 3403 | const ptr_bits = self.target.ptrBitWidth(); | 3399 | const ptr_bits = 64; |
| 3404 | const ptr_bytes = @divExact(ptr_bits, 8); | 3400 | const ptr_bytes = @divExact(ptr_bits, 8); |
| 3405 | const mcv = try self.resolveInst(ty_op.operand); | 3401 | const mcv = try self.resolveInst(ty_op.operand); |
| 3406 | switch (mcv) { | 3402 | switch (mcv) { |
| ... | @@ -4272,8 +4268,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -4272,8 +4268,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4272 | if (info.return_value == .stack_offset) { | 4268 | if (info.return_value == .stack_offset) { |
| 4273 | log.debug("airCall: return by reference", .{}); | 4269 | log.debug("airCall: return by reference", .{}); |
| 4274 | const ret_ty = fn_ty.fnReturnType(mod); | 4270 | const ret_ty = fn_ty.fnReturnType(mod); |
| 4275 | const ret_abi_size = @as(u32, @intCast(ret_ty.abiSize(mod))); | 4271 | const ret_abi_size: u32 = @intCast(ret_ty.abiSize(mod)); |
| 4276 | const ret_abi_align = @as(u32, @intCast(ret_ty.abiAlignment(mod))); | 4272 | const ret_abi_align = ret_ty.abiAlignment(mod); |
| 4277 | const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst); | 4273 | const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst); |
| 4278 | 4274 | ||
| 4279 | const ret_ptr_reg = self.registerAlias(.x0, Type.usize); | 4275 | const ret_ptr_reg = self.registerAlias(.x0, Type.usize); |
| ... | @@ -5939,11 +5935,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5939,11 +5935,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 5939 | const ptr = try self.resolveInst(ty_op.operand); | 5935 | const ptr = try self.resolveInst(ty_op.operand); |
| 5940 | const array_ty = ptr_ty.childType(mod); | 5936 | const array_ty = ptr_ty.childType(mod); |
| 5941 | const array_len = @as(u32, @intCast(array_ty.arrayLen(mod))); | 5937 | const array_len = @as(u32, @intCast(array_ty.arrayLen(mod))); |
| 5942 | 5938 | const ptr_bytes = 8; | |
| 5943 | const ptr_bits = self.target.ptrBitWidth(); | 5939 | const stack_offset = try self.allocMem(ptr_bytes * 2, .@"8", inst); |
| 5944 | const ptr_bytes = @divExact(ptr_bits, 8); | ||
| 5945 | |||
| 5946 | const stack_offset = try self.allocMem(ptr_bytes * 2, ptr_bytes * 2, inst); | ||
| 5947 | try self.genSetStack(ptr_ty, stack_offset, ptr); | 5940 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 5948 | try self.genSetStack(Type.usize, stack_offset - ptr_bytes, .{ .immediate = array_len }); | 5941 | try self.genSetStack(Type.usize, stack_offset - ptr_bytes, .{ .immediate = array_len }); |
| 5949 | break :result MCValue{ .stack_offset = stack_offset }; | 5942 | break :result MCValue{ .stack_offset = stack_offset }; |
| ... | @@ -6254,7 +6247,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6254,7 +6247,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6254 | 6247 | ||
| 6255 | // We round up NCRN only for non-Apple platforms which allow the 16-byte aligned | 6248 | // We round up NCRN only for non-Apple platforms which allow the 16-byte aligned |
| 6256 | // values to spread across odd-numbered registers. | 6249 | // values to spread across odd-numbered registers. |
| 6257 | if (ty.toType().abiAlignment(mod) == 16 and !self.target.isDarwin()) { | 6250 | if (ty.toType().abiAlignment(mod) == .@"16" and !self.target.isDarwin()) { |
| 6258 | // Round up NCRN to the next even number | 6251 | // Round up NCRN to the next even number |
| 6259 | ncrn += ncrn % 2; | 6252 | ncrn += ncrn % 2; |
| 6260 | } | 6253 | } |
| ... | @@ -6272,7 +6265,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6272,7 +6265,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6272 | ncrn = 8; | 6265 | ncrn = 8; |
| 6273 | // TODO Apple allows the arguments on the stack to be non-8-byte aligned provided | 6266 | // TODO Apple allows the arguments on the stack to be non-8-byte aligned provided |
| 6274 | // that the entire stack space consumed by the arguments is 8-byte aligned. | 6267 | // that the entire stack space consumed by the arguments is 8-byte aligned. |
| 6275 | if (ty.toType().abiAlignment(mod) == 8) { | 6268 | if (ty.toType().abiAlignment(mod) == .@"8") { |
| 6276 | if (nsaa % 8 != 0) { | 6269 | if (nsaa % 8 != 0) { |
| 6277 | nsaa += 8 - (nsaa % 8); | 6270 | nsaa += 8 - (nsaa % 8); |
| 6278 | } | 6271 | } |
| ... | @@ -6312,10 +6305,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6312,10 +6305,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6312 | 6305 | ||
| 6313 | for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| { | 6306 | for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| { |
| 6314 | if (ty.toType().abiSize(mod) > 0) { | 6307 | if (ty.toType().abiSize(mod) > 0) { |
| 6315 | const param_size = @as(u32, @intCast(ty.toType().abiSize(mod))); | 6308 | const param_size: u32 = @intCast(ty.toType().abiSize(mod)); |
| 6316 | const param_alignment = ty.toType().abiAlignment(mod); | 6309 | const param_alignment = ty.toType().abiAlignment(mod); |
| 6317 | 6310 | ||
| 6318 | stack_offset = std.mem.alignForward(u32, stack_offset, param_alignment); | 6311 | stack_offset = @intCast(param_alignment.forward(stack_offset)); |
| 6319 | result_arg.* = .{ .stack_argument_offset = stack_offset }; | 6312 | result_arg.* = .{ .stack_argument_offset = stack_offset }; |
| 6320 | stack_offset += param_size; | 6313 | stack_offset += param_size; |
| 6321 | } else { | 6314 | } else { |
src/arch/arm/CodeGen.zig+13-12| ... | @@ -23,6 +23,7 @@ const DW = std.dwarf; | ... | @@ -23,6 +23,7 @@ const DW = std.dwarf; |
| 23 | const leb128 = std.leb; | 23 | const leb128 = std.leb; |
| 24 | const log = std.log.scoped(.codegen); | 24 | const log = std.log.scoped(.codegen); |
| 25 | const build_options = @import("build_options"); | 25 | const build_options = @import("build_options"); |
| 26 | const Alignment = InternPool.Alignment; | ||
| 26 | 27 | ||
| 27 | const Result = codegen.Result; | 28 | const Result = codegen.Result; |
| 28 | const CodeGenError = codegen.CodeGenError; | 29 | const CodeGenError = codegen.CodeGenError; |
| ... | @@ -508,7 +509,7 @@ fn gen(self: *Self) !void { | ... | @@ -508,7 +509,7 @@ fn gen(self: *Self) !void { |
| 508 | // The address of where to store the return value is in | 509 | // The address of where to store the return value is in |
| 509 | // r0. As this register might get overwritten along the | 510 | // r0. As this register might get overwritten along the |
| 510 | // way, save the address to the stack. | 511 | // way, save the address to the stack. |
| 511 | const stack_offset = try self.allocMem(4, 4, null); | 512 | const stack_offset = try self.allocMem(4, .@"4", null); |
| 512 | 513 | ||
| 513 | try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = .r0 }); | 514 | try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = .r0 }); |
| 514 | self.ret_mcv = MCValue{ .stack_offset = stack_offset }; | 515 | self.ret_mcv = MCValue{ .stack_offset = stack_offset }; |
| ... | @@ -986,14 +987,14 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { | ... | @@ -986,14 +987,14 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { |
| 986 | fn allocMem( | 987 | fn allocMem( |
| 987 | self: *Self, | 988 | self: *Self, |
| 988 | abi_size: u32, | 989 | abi_size: u32, |
| 989 | abi_align: u32, | 990 | abi_align: Alignment, |
| 990 | maybe_inst: ?Air.Inst.Index, | 991 | maybe_inst: ?Air.Inst.Index, |
| 991 | ) !u32 { | 992 | ) !u32 { |
| 992 | assert(abi_size > 0); | 993 | assert(abi_size > 0); |
| 993 | assert(abi_align > 0); | 994 | assert(abi_align != .none); |
| 994 | 995 | ||
| 995 | // TODO find a free slot instead of always appending | 996 | // TODO find a free slot instead of always appending |
| 996 | const offset = mem.alignForward(u32, self.next_stack_offset, abi_align) + abi_size; | 997 | const offset: u32 = @intCast(abi_align.forward(self.next_stack_offset) + abi_size); |
| 997 | self.next_stack_offset = offset; | 998 | self.next_stack_offset = offset; |
| 998 | self.max_end_stack = @max(self.max_end_stack, self.next_stack_offset); | 999 | self.max_end_stack = @max(self.max_end_stack, self.next_stack_offset); |
| 999 | 1000 | ||
| ... | @@ -1490,7 +1491,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1490,7 +1491,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1490 | const len = try self.resolveInst(bin_op.rhs); | 1491 | const len = try self.resolveInst(bin_op.rhs); |
| 1491 | const len_ty = self.typeOf(bin_op.rhs); | 1492 | const len_ty = self.typeOf(bin_op.rhs); |
| 1492 | 1493 | ||
| 1493 | const stack_offset = try self.allocMem(8, 4, inst); | 1494 | const stack_offset = try self.allocMem(8, .@"4", inst); |
| 1494 | try self.genSetStack(ptr_ty, stack_offset, ptr); | 1495 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 1495 | try self.genSetStack(len_ty, stack_offset - 4, len); | 1496 | try self.genSetStack(len_ty, stack_offset - 4, len); |
| 1496 | break :result MCValue{ .stack_offset = stack_offset }; | 1497 | break :result MCValue{ .stack_offset = stack_offset }; |
| ... | @@ -4251,8 +4252,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -4251,8 +4252,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4251 | const r0_lock: ?RegisterLock = if (info.return_value == .stack_offset) blk: { | 4252 | const r0_lock: ?RegisterLock = if (info.return_value == .stack_offset) blk: { |
| 4252 | log.debug("airCall: return by reference", .{}); | 4253 | log.debug("airCall: return by reference", .{}); |
| 4253 | const ret_ty = fn_ty.fnReturnType(mod); | 4254 | const ret_ty = fn_ty.fnReturnType(mod); |
| 4254 | const ret_abi_size = @as(u32, @intCast(ret_ty.abiSize(mod))); | 4255 | const ret_abi_size: u32 = @intCast(ret_ty.abiSize(mod)); |
| 4255 | const ret_abi_align = @as(u32, @intCast(ret_ty.abiAlignment(mod))); | 4256 | const ret_abi_align = ret_ty.abiAlignment(mod); |
| 4256 | const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst); | 4257 | const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst); |
| 4257 | 4258 | ||
| 4258 | const ptr_ty = try mod.singleMutPtrType(ret_ty); | 4259 | const ptr_ty = try mod.singleMutPtrType(ret_ty); |
| ... | @@ -5896,7 +5897,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5896,7 +5897,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 5896 | const array_ty = ptr_ty.childType(mod); | 5897 | const array_ty = ptr_ty.childType(mod); |
| 5897 | const array_len = @as(u32, @intCast(array_ty.arrayLen(mod))); | 5898 | const array_len = @as(u32, @intCast(array_ty.arrayLen(mod))); |
| 5898 | 5899 | ||
| 5899 | const stack_offset = try self.allocMem(8, 8, inst); | 5900 | const stack_offset = try self.allocMem(8, .@"8", inst); |
| 5900 | try self.genSetStack(ptr_ty, stack_offset, ptr); | 5901 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 5901 | try self.genSetStack(Type.usize, stack_offset - 4, .{ .immediate = array_len }); | 5902 | try self.genSetStack(Type.usize, stack_offset - 4, .{ .immediate = array_len }); |
| 5902 | break :result MCValue{ .stack_offset = stack_offset }; | 5903 | break :result MCValue{ .stack_offset = stack_offset }; |
| ... | @@ -6201,7 +6202,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6201,7 +6202,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6201 | } | 6202 | } |
| 6202 | 6203 | ||
| 6203 | for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| { | 6204 | for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| { |
| 6204 | if (ty.toType().abiAlignment(mod) == 8) | 6205 | if (ty.toType().abiAlignment(mod) == .@"8") |
| 6205 | ncrn = std.mem.alignForward(usize, ncrn, 2); | 6206 | ncrn = std.mem.alignForward(usize, ncrn, 2); |
| 6206 | 6207 | ||
| 6207 | const param_size = @as(u32, @intCast(ty.toType().abiSize(mod))); | 6208 | const param_size = @as(u32, @intCast(ty.toType().abiSize(mod))); |
| ... | @@ -6216,7 +6217,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6216,7 +6217,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6216 | return self.fail("TODO MCValues split between registers and stack", .{}); | 6217 | return self.fail("TODO MCValues split between registers and stack", .{}); |
| 6217 | } else { | 6218 | } else { |
| 6218 | ncrn = 4; | 6219 | ncrn = 4; |
| 6219 | if (ty.toType().abiAlignment(mod) == 8) | 6220 | if (ty.toType().abiAlignment(mod) == .@"8") |
| 6220 | nsaa = std.mem.alignForward(u32, nsaa, 8); | 6221 | nsaa = std.mem.alignForward(u32, nsaa, 8); |
| 6221 | 6222 | ||
| 6222 | result_arg.* = .{ .stack_argument_offset = nsaa }; | 6223 | result_arg.* = .{ .stack_argument_offset = nsaa }; |
| ... | @@ -6252,10 +6253,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6252,10 +6253,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6252 | 6253 | ||
| 6253 | for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| { | 6254 | for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| { |
| 6254 | if (ty.toType().abiSize(mod) > 0) { | 6255 | if (ty.toType().abiSize(mod) > 0) { |
| 6255 | const param_size = @as(u32, @intCast(ty.toType().abiSize(mod))); | 6256 | const param_size: u32 = @intCast(ty.toType().abiSize(mod)); |
| 6256 | const param_alignment = ty.toType().abiAlignment(mod); | 6257 | const param_alignment = ty.toType().abiAlignment(mod); |
| 6257 | 6258 | ||
| 6258 | stack_offset = std.mem.alignForward(u32, stack_offset, param_alignment); | 6259 | stack_offset = @intCast(param_alignment.forward(stack_offset)); |
| 6259 | result_arg.* = .{ .stack_argument_offset = stack_offset }; | 6260 | result_arg.* = .{ .stack_argument_offset = stack_offset }; |
| 6260 | stack_offset += param_size; | 6261 | stack_offset += param_size; |
| 6261 | } else { | 6262 | } else { |
src/arch/arm/abi.zig+2-2| ... | @@ -47,7 +47,7 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class { | ... | @@ -47,7 +47,7 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class { |
| 47 | const field_ty = ty.structFieldType(i, mod); | 47 | const field_ty = ty.structFieldType(i, mod); |
| 48 | const field_alignment = ty.structFieldAlign(i, mod); | 48 | const field_alignment = ty.structFieldAlign(i, mod); |
| 49 | const field_size = field_ty.bitSize(mod); | 49 | const field_size = field_ty.bitSize(mod); |
| 50 | if (field_size > 32 or field_alignment > 32) { | 50 | if (field_size > 32 or field_alignment.compare(.gt, .@"32")) { |
| 51 | return Class.arrSize(bit_size, 64); | 51 | return Class.arrSize(bit_size, 64); |
| 52 | } | 52 | } |
| 53 | } | 53 | } |
| ... | @@ -66,7 +66,7 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class { | ... | @@ -66,7 +66,7 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class { |
| 66 | 66 | ||
| 67 | for (union_obj.field_types.get(ip), 0..) |field_ty, field_index| { | 67 | for (union_obj.field_types.get(ip), 0..) |field_ty, field_index| { |
| 68 | if (field_ty.toType().bitSize(mod) > 32 or | 68 | if (field_ty.toType().bitSize(mod) > 32 or |
| 69 | mod.unionFieldNormalAlignment(union_obj, @intCast(field_index)) > 32) | 69 | mod.unionFieldNormalAlignment(union_obj, @intCast(field_index)).compare(.gt, .@"32")) |
| 70 | { | 70 | { |
| 71 | return Class.arrSize(bit_size, 64); | 71 | return Class.arrSize(bit_size, 64); |
| 72 | } | 72 | } |
src/arch/riscv64/CodeGen.zig+9-10| ... | @@ -23,6 +23,7 @@ const leb128 = std.leb; | ... | @@ -23,6 +23,7 @@ const leb128 = std.leb; |
| 23 | const log = std.log.scoped(.codegen); | 23 | const log = std.log.scoped(.codegen); |
| 24 | const build_options = @import("build_options"); | 24 | const build_options = @import("build_options"); |
| 25 | const codegen = @import("../../codegen.zig"); | 25 | const codegen = @import("../../codegen.zig"); |
| 26 | const Alignment = InternPool.Alignment; | ||
| 26 | 27 | ||
| 27 | const CodeGenError = codegen.CodeGenError; | 28 | const CodeGenError = codegen.CodeGenError; |
| 28 | const Result = codegen.Result; | 29 | const Result = codegen.Result; |
| ... | @@ -53,7 +54,7 @@ ret_mcv: MCValue, | ... | @@ -53,7 +54,7 @@ ret_mcv: MCValue, |
| 53 | fn_type: Type, | 54 | fn_type: Type, |
| 54 | arg_index: usize, | 55 | arg_index: usize, |
| 55 | src_loc: Module.SrcLoc, | 56 | src_loc: Module.SrcLoc, |
| 56 | stack_align: u32, | 57 | stack_align: Alignment, |
| 57 | 58 | ||
| 58 | /// MIR Instructions | 59 | /// MIR Instructions |
| 59 | mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, | 60 | mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, |
| ... | @@ -788,11 +789,10 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { | ... | @@ -788,11 +789,10 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { |
| 788 | try table.ensureUnusedCapacity(self.gpa, additional_count); | 789 | try table.ensureUnusedCapacity(self.gpa, additional_count); |
| 789 | } | 790 | } |
| 790 | 791 | ||
| 791 | fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 { | 792 | fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: Alignment) !u32 { |
| 792 | if (abi_align > self.stack_align) | 793 | self.stack_align = self.stack_align.max(abi_align); |
| 793 | self.stack_align = abi_align; | ||
| 794 | // TODO find a free slot instead of always appending | 794 | // TODO find a free slot instead of always appending |
| 795 | const offset = mem.alignForward(u32, self.next_stack_offset, abi_align); | 795 | const offset: u32 = @intCast(abi_align.forward(self.next_stack_offset)); |
| 796 | self.next_stack_offset = offset + abi_size; | 796 | self.next_stack_offset = offset + abi_size; |
| 797 | if (self.next_stack_offset > self.max_end_stack) | 797 | if (self.next_stack_offset > self.max_end_stack) |
| 798 | self.max_end_stack = self.next_stack_offset; | 798 | self.max_end_stack = self.next_stack_offset; |
| ... | @@ -822,8 +822,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { | ... | @@ -822,8 +822,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 822 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); | 822 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); |
| 823 | }; | 823 | }; |
| 824 | const abi_align = elem_ty.abiAlignment(mod); | 824 | const abi_align = elem_ty.abiAlignment(mod); |
| 825 | if (abi_align > self.stack_align) | 825 | self.stack_align = self.stack_align.max(abi_align); |
| 826 | self.stack_align = abi_align; | ||
| 827 | 826 | ||
| 828 | if (reg_ok) { | 827 | if (reg_ok) { |
| 829 | // Make sure the type can fit in a register before we try to allocate one. | 828 | // Make sure the type can fit in a register before we try to allocate one. |
| ... | @@ -2602,7 +2601,7 @@ const CallMCValues = struct { | ... | @@ -2602,7 +2601,7 @@ const CallMCValues = struct { |
| 2602 | args: []MCValue, | 2601 | args: []MCValue, |
| 2603 | return_value: MCValue, | 2602 | return_value: MCValue, |
| 2604 | stack_byte_count: u32, | 2603 | stack_byte_count: u32, |
| 2605 | stack_align: u32, | 2604 | stack_align: Alignment, |
| 2606 | 2605 | ||
| 2607 | fn deinit(self: *CallMCValues, func: *Self) void { | 2606 | fn deinit(self: *CallMCValues, func: *Self) void { |
| 2608 | func.gpa.free(self.args); | 2607 | func.gpa.free(self.args); |
| ... | @@ -2632,7 +2631,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -2632,7 +2631,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 2632 | assert(result.args.len == 0); | 2631 | assert(result.args.len == 0); |
| 2633 | result.return_value = .{ .unreach = {} }; | 2632 | result.return_value = .{ .unreach = {} }; |
| 2634 | result.stack_byte_count = 0; | 2633 | result.stack_byte_count = 0; |
| 2635 | result.stack_align = 1; | 2634 | result.stack_align = .@"1"; |
| 2636 | return result; | 2635 | return result; |
| 2637 | }, | 2636 | }, |
| 2638 | .Unspecified, .C => { | 2637 | .Unspecified, .C => { |
| ... | @@ -2671,7 +2670,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -2671,7 +2670,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 2671 | } | 2670 | } |
| 2672 | 2671 | ||
| 2673 | result.stack_byte_count = next_stack_offset; | 2672 | result.stack_byte_count = next_stack_offset; |
| 2674 | result.stack_align = 16; | 2673 | result.stack_align = .@"16"; |
| 2675 | }, | 2674 | }, |
| 2676 | else => return self.fail("TODO implement function parameters for {} on riscv64", .{cc}), | 2675 | else => return self.fail("TODO implement function parameters for {} on riscv64", .{cc}), |
| 2677 | } | 2676 | } |
src/arch/sparc64/CodeGen.zig+14-21| ... | @@ -24,6 +24,7 @@ const CodeGenError = codegen.CodeGenError; | ... | @@ -24,6 +24,7 @@ const CodeGenError = codegen.CodeGenError; |
| 24 | const Result = @import("../../codegen.zig").Result; | 24 | const Result = @import("../../codegen.zig").Result; |
| 25 | const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; | 25 | const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; |
| 26 | const Endian = std.builtin.Endian; | 26 | const Endian = std.builtin.Endian; |
| 27 | const Alignment = InternPool.Alignment; | ||
| 27 | 28 | ||
| 28 | const build_options = @import("build_options"); | 29 | const build_options = @import("build_options"); |
| 29 | 30 | ||
| ... | @@ -62,7 +63,7 @@ ret_mcv: MCValue, | ... | @@ -62,7 +63,7 @@ ret_mcv: MCValue, |
| 62 | fn_type: Type, | 63 | fn_type: Type, |
| 63 | arg_index: usize, | 64 | arg_index: usize, |
| 64 | src_loc: Module.SrcLoc, | 65 | src_loc: Module.SrcLoc, |
| 65 | stack_align: u32, | 66 | stack_align: Alignment, |
| 66 | 67 | ||
| 67 | /// MIR Instructions | 68 | /// MIR Instructions |
| 68 | mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, | 69 | mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, |
| ... | @@ -227,7 +228,7 @@ const CallMCValues = struct { | ... | @@ -227,7 +228,7 @@ const CallMCValues = struct { |
| 227 | args: []MCValue, | 228 | args: []MCValue, |
| 228 | return_value: MCValue, | 229 | return_value: MCValue, |
| 229 | stack_byte_count: u32, | 230 | stack_byte_count: u32, |
| 230 | stack_align: u32, | 231 | stack_align: Alignment, |
| 231 | 232 | ||
| 232 | fn deinit(self: *CallMCValues, func: *Self) void { | 233 | fn deinit(self: *CallMCValues, func: *Self) void { |
| 233 | func.gpa.free(self.args); | 234 | func.gpa.free(self.args); |
| ... | @@ -424,7 +425,7 @@ fn gen(self: *Self) !void { | ... | @@ -424,7 +425,7 @@ fn gen(self: *Self) !void { |
| 424 | 425 | ||
| 425 | // Backpatch stack offset | 426 | // Backpatch stack offset |
| 426 | const total_stack_size = self.max_end_stack + abi.stack_reserved_area; | 427 | const total_stack_size = self.max_end_stack + abi.stack_reserved_area; |
| 427 | const stack_size = mem.alignForward(u32, total_stack_size, self.stack_align); | 428 | const stack_size = self.stack_align.forward(total_stack_size); |
| 428 | if (math.cast(i13, stack_size)) |size| { | 429 | if (math.cast(i13, stack_size)) |size| { |
| 429 | self.mir_instructions.set(save_inst, .{ | 430 | self.mir_instructions.set(save_inst, .{ |
| 430 | .tag = .save, | 431 | .tag = .save, |
| ... | @@ -880,11 +881,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -880,11 +881,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 880 | const ptr = try self.resolveInst(ty_op.operand); | 881 | const ptr = try self.resolveInst(ty_op.operand); |
| 881 | const array_ty = ptr_ty.childType(mod); | 882 | const array_ty = ptr_ty.childType(mod); |
| 882 | const array_len = @as(u32, @intCast(array_ty.arrayLen(mod))); | 883 | const array_len = @as(u32, @intCast(array_ty.arrayLen(mod))); |
| 883 | 884 | const ptr_bytes = 8; | |
| 884 | const ptr_bits = self.target.ptrBitWidth(); | 885 | const stack_offset = try self.allocMem(inst, ptr_bytes * 2, .@"8"); |
| 885 | const ptr_bytes = @divExact(ptr_bits, 8); | ||
| 886 | |||
| 887 | const stack_offset = try self.allocMem(inst, ptr_bytes * 2, ptr_bytes * 2); | ||
| 888 | try self.genSetStack(ptr_ty, stack_offset, ptr); | 886 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 889 | try self.genSetStack(Type.usize, stack_offset - ptr_bytes, .{ .immediate = array_len }); | 887 | try self.genSetStack(Type.usize, stack_offset - ptr_bytes, .{ .immediate = array_len }); |
| 890 | break :result MCValue{ .stack_offset = stack_offset }; | 888 | break :result MCValue{ .stack_offset = stack_offset }; |
| ... | @@ -2438,11 +2436,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2438,11 +2436,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 2438 | const ptr_ty = self.typeOf(bin_op.lhs); | 2436 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 2439 | const len = try self.resolveInst(bin_op.rhs); | 2437 | const len = try self.resolveInst(bin_op.rhs); |
| 2440 | const len_ty = self.typeOf(bin_op.rhs); | 2438 | const len_ty = self.typeOf(bin_op.rhs); |
| 2441 | 2439 | const ptr_bytes = 8; | |
| 2442 | const ptr_bits = self.target.ptrBitWidth(); | 2440 | const stack_offset = try self.allocMem(inst, ptr_bytes * 2, .@"8"); |
| 2443 | const ptr_bytes = @divExact(ptr_bits, 8); | ||
| 2444 | |||
| 2445 | const stack_offset = try self.allocMem(inst, ptr_bytes * 2, ptr_bytes * 2); | ||
| 2446 | try self.genSetStack(ptr_ty, stack_offset, ptr); | 2441 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 2447 | try self.genSetStack(len_ty, stack_offset - ptr_bytes, len); | 2442 | try self.genSetStack(len_ty, stack_offset - ptr_bytes, len); |
| 2448 | break :result MCValue{ .stack_offset = stack_offset }; | 2443 | break :result MCValue{ .stack_offset = stack_offset }; |
| ... | @@ -2782,11 +2777,10 @@ fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { | ... | @@ -2782,11 +2777,10 @@ fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { |
| 2782 | return result_index; | 2777 | return result_index; |
| 2783 | } | 2778 | } |
| 2784 | 2779 | ||
| 2785 | fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 { | 2780 | fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: Alignment) !u32 { |
| 2786 | if (abi_align > self.stack_align) | 2781 | self.stack_align = self.stack_align.max(abi_align); |
| 2787 | self.stack_align = abi_align; | ||
| 2788 | // TODO find a free slot instead of always appending | 2782 | // TODO find a free slot instead of always appending |
| 2789 | const offset = mem.alignForward(u32, self.next_stack_offset, abi_align) + abi_size; | 2783 | const offset: u32 = @intCast(abi_align.forward(self.next_stack_offset) + abi_size); |
| 2790 | self.next_stack_offset = offset; | 2784 | self.next_stack_offset = offset; |
| 2791 | if (self.next_stack_offset > self.max_end_stack) | 2785 | if (self.next_stack_offset > self.max_end_stack) |
| 2792 | self.max_end_stack = self.next_stack_offset; | 2786 | self.max_end_stack = self.next_stack_offset; |
| ... | @@ -2825,8 +2819,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { | ... | @@ -2825,8 +2819,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 2825 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); | 2819 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); |
| 2826 | }; | 2820 | }; |
| 2827 | const abi_align = elem_ty.abiAlignment(mod); | 2821 | const abi_align = elem_ty.abiAlignment(mod); |
| 2828 | if (abi_align > self.stack_align) | 2822 | self.stack_align = self.stack_align.max(abi_align); |
| 2829 | self.stack_align = abi_align; | ||
| 2830 | 2823 | ||
| 2831 | if (reg_ok) { | 2824 | if (reg_ok) { |
| 2832 | // Make sure the type can fit in a register before we try to allocate one. | 2825 | // Make sure the type can fit in a register before we try to allocate one. |
| ... | @@ -4479,7 +4472,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) | ... | @@ -4479,7 +4472,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) |
| 4479 | assert(result.args.len == 0); | 4472 | assert(result.args.len == 0); |
| 4480 | result.return_value = .{ .unreach = {} }; | 4473 | result.return_value = .{ .unreach = {} }; |
| 4481 | result.stack_byte_count = 0; | 4474 | result.stack_byte_count = 0; |
| 4482 | result.stack_align = 1; | 4475 | result.stack_align = .@"1"; |
| 4483 | return result; | 4476 | return result; |
| 4484 | }, | 4477 | }, |
| 4485 | .Unspecified, .C => { | 4478 | .Unspecified, .C => { |
| ... | @@ -4521,7 +4514,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) | ... | @@ -4521,7 +4514,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) |
| 4521 | } | 4514 | } |
| 4522 | 4515 | ||
| 4523 | result.stack_byte_count = next_stack_offset; | 4516 | result.stack_byte_count = next_stack_offset; |
| 4524 | result.stack_align = 16; | 4517 | result.stack_align = .@"16"; |
| 4525 | 4518 | ||
| 4526 | if (ret_ty.zigTypeTag(mod) == .NoReturn) { | 4519 | if (ret_ty.zigTypeTag(mod) == .NoReturn) { |
| 4527 | result.return_value = .{ .unreach = {} }; | 4520 | result.return_value = .{ .unreach = {} }; |
src/arch/wasm/CodeGen.zig+88-75| ... | @@ -25,6 +25,7 @@ const target_util = @import("../../target.zig"); | ... | @@ -25,6 +25,7 @@ const target_util = @import("../../target.zig"); |
| 25 | const Mir = @import("Mir.zig"); | 25 | const Mir = @import("Mir.zig"); |
| 26 | const Emit = @import("Emit.zig"); | 26 | const Emit = @import("Emit.zig"); |
| 27 | const abi = @import("abi.zig"); | 27 | const abi = @import("abi.zig"); |
| 28 | const Alignment = InternPool.Alignment; | ||
| 28 | const errUnionPayloadOffset = codegen.errUnionPayloadOffset; | 29 | const errUnionPayloadOffset = codegen.errUnionPayloadOffset; |
| 29 | const errUnionErrorOffset = codegen.errUnionErrorOffset; | 30 | const errUnionErrorOffset = codegen.errUnionErrorOffset; |
| 30 | 31 | ||
| ... | @@ -709,7 +710,7 @@ stack_size: u32 = 0, | ... | @@ -709,7 +710,7 @@ stack_size: u32 = 0, |
| 709 | /// tool-conventions: https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md | 710 | /// tool-conventions: https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md |
| 710 | /// and also what the llvm backend will emit. | 711 | /// and also what the llvm backend will emit. |
| 711 | /// However, local variables or the usage of `@setAlignStack` can overwrite this default. | 712 | /// However, local variables or the usage of `@setAlignStack` can overwrite this default. |
| 712 | stack_alignment: u32 = 16, | 713 | stack_alignment: Alignment = .@"16", |
| 713 | 714 | ||
| 714 | // For each individual Wasm valtype we store a seperate free list which | 715 | // For each individual Wasm valtype we store a seperate free list which |
| 715 | // allows us to re-use locals that are no longer used. e.g. a temporary local. | 716 | // allows us to re-use locals that are no longer used. e.g. a temporary local. |
| ... | @@ -991,6 +992,7 @@ fn addExtraAssumeCapacity(func: *CodeGen, extra: anytype) error{OutOfMemory}!u32 | ... | @@ -991,6 +992,7 @@ fn addExtraAssumeCapacity(func: *CodeGen, extra: anytype) error{OutOfMemory}!u32 |
| 991 | /// Using a given `Type`, returns the corresponding type | 992 | /// Using a given `Type`, returns the corresponding type |
| 992 | fn typeToValtype(ty: Type, mod: *Module) wasm.Valtype { | 993 | fn typeToValtype(ty: Type, mod: *Module) wasm.Valtype { |
| 993 | const target = mod.getTarget(); | 994 | const target = mod.getTarget(); |
| 995 | const ip = &mod.intern_pool; | ||
| 994 | return switch (ty.zigTypeTag(mod)) { | 996 | return switch (ty.zigTypeTag(mod)) { |
| 995 | .Float => switch (ty.floatBits(target)) { | 997 | .Float => switch (ty.floatBits(target)) { |
| 996 | 16 => wasm.Valtype.i32, // stored/loaded as u16 | 998 | 16 => wasm.Valtype.i32, // stored/loaded as u16 |
| ... | @@ -1005,12 +1007,12 @@ fn typeToValtype(ty: Type, mod: *Module) wasm.Valtype { | ... | @@ -1005,12 +1007,12 @@ fn typeToValtype(ty: Type, mod: *Module) wasm.Valtype { |
| 1005 | if (info.bits > 32 and info.bits <= 128) break :blk wasm.Valtype.i64; | 1007 | if (info.bits > 32 and info.bits <= 128) break :blk wasm.Valtype.i64; |
| 1006 | break :blk wasm.Valtype.i32; // represented as pointer to stack | 1008 | break :blk wasm.Valtype.i32; // represented as pointer to stack |
| 1007 | }, | 1009 | }, |
| 1008 | .Struct => switch (ty.containerLayout(mod)) { | 1010 | .Struct => { |
| 1009 | .Packed => { | 1011 | if (mod.typeToPackedStruct(ty)) |packed_struct| { |
| 1010 | const struct_obj = mod.typeToStruct(ty).?; | 1012 | return typeToValtype(packed_struct.backingIntType(ip).toType(), mod); |
| 1011 | return typeToValtype(struct_obj.backing_int_ty, mod); | 1013 | } else { |
| 1012 | }, | 1014 | return wasm.Valtype.i32; |
| 1013 | else => wasm.Valtype.i32, | 1015 | } |
| 1014 | }, | 1016 | }, |
| 1015 | .Vector => switch (determineSimdStoreStrategy(ty, mod)) { | 1017 | .Vector => switch (determineSimdStoreStrategy(ty, mod)) { |
| 1016 | .direct => wasm.Valtype.v128, | 1018 | .direct => wasm.Valtype.v128, |
| ... | @@ -1285,12 +1287,12 @@ fn genFunc(func: *CodeGen) InnerError!void { | ... | @@ -1285,12 +1287,12 @@ fn genFunc(func: *CodeGen) InnerError!void { |
| 1285 | // store stack pointer so we can restore it when we return from the function | 1287 | // store stack pointer so we can restore it when we return from the function |
| 1286 | try prologue.append(.{ .tag = .local_tee, .data = .{ .label = func.initial_stack_value.local.value } }); | 1288 | try prologue.append(.{ .tag = .local_tee, .data = .{ .label = func.initial_stack_value.local.value } }); |
| 1287 | // get the total stack size | 1289 | // get the total stack size |
| 1288 | const aligned_stack = std.mem.alignForward(u32, func.stack_size, func.stack_alignment); | 1290 | const aligned_stack = func.stack_alignment.forward(func.stack_size); |
| 1289 | try prologue.append(.{ .tag = .i32_const, .data = .{ .imm32 = @as(i32, @intCast(aligned_stack)) } }); | 1291 | try prologue.append(.{ .tag = .i32_const, .data = .{ .imm32 = @intCast(aligned_stack) } }); |
| 1290 | // substract it from the current stack pointer | 1292 | // subtract it from the current stack pointer |
| 1291 | try prologue.append(.{ .tag = .i32_sub, .data = .{ .tag = {} } }); | 1293 | try prologue.append(.{ .tag = .i32_sub, .data = .{ .tag = {} } }); |
| 1292 | // Get negative stack aligment | 1294 | // Get negative stack aligment |
| 1293 | try prologue.append(.{ .tag = .i32_const, .data = .{ .imm32 = @as(i32, @intCast(func.stack_alignment)) * -1 } }); | 1295 | try prologue.append(.{ .tag = .i32_const, .data = .{ .imm32 = @as(i32, @intCast(func.stack_alignment.toByteUnitsOptional().?)) * -1 } }); |
| 1294 | // Bitwise-and the value to get the new stack pointer to ensure the pointers are aligned with the abi alignment | 1296 | // Bitwise-and the value to get the new stack pointer to ensure the pointers are aligned with the abi alignment |
| 1295 | try prologue.append(.{ .tag = .i32_and, .data = .{ .tag = {} } }); | 1297 | try prologue.append(.{ .tag = .i32_and, .data = .{ .tag = {} } }); |
| 1296 | // store the current stack pointer as the bottom, which will be used to calculate all stack pointer offsets | 1298 | // store the current stack pointer as the bottom, which will be used to calculate all stack pointer offsets |
| ... | @@ -1438,7 +1440,7 @@ fn lowerArg(func: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value: | ... | @@ -1438,7 +1440,7 @@ fn lowerArg(func: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value: |
| 1438 | }); | 1440 | }); |
| 1439 | try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{ | 1441 | try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{ |
| 1440 | .offset = value.offset(), | 1442 | .offset = value.offset(), |
| 1441 | .alignment = scalar_type.abiAlignment(mod), | 1443 | .alignment = @intCast(scalar_type.abiAlignment(mod).toByteUnitsOptional().?), |
| 1442 | }); | 1444 | }); |
| 1443 | } | 1445 | } |
| 1444 | }, | 1446 | }, |
| ... | @@ -1527,11 +1529,9 @@ fn allocStack(func: *CodeGen, ty: Type) !WValue { | ... | @@ -1527,11 +1529,9 @@ fn allocStack(func: *CodeGen, ty: Type) !WValue { |
| 1527 | }; | 1529 | }; |
| 1528 | const abi_align = ty.abiAlignment(mod); | 1530 | const abi_align = ty.abiAlignment(mod); |
| 1529 | 1531 | ||
| 1530 | if (abi_align > func.stack_alignment) { | 1532 | func.stack_alignment = func.stack_alignment.max(abi_align); |
| 1531 | func.stack_alignment = abi_align; | ||
| 1532 | } | ||
| 1533 | 1533 | ||
| 1534 | const offset = std.mem.alignForward(u32, func.stack_size, abi_align); | 1534 | const offset: u32 = @intCast(abi_align.forward(func.stack_size)); |
| 1535 | defer func.stack_size = offset + abi_size; | 1535 | defer func.stack_size = offset + abi_size; |
| 1536 | 1536 | ||
| 1537 | return WValue{ .stack_offset = .{ .value = offset, .references = 1 } }; | 1537 | return WValue{ .stack_offset = .{ .value = offset, .references = 1 } }; |
| ... | @@ -1560,11 +1560,9 @@ fn allocStackPtr(func: *CodeGen, inst: Air.Inst.Index) !WValue { | ... | @@ -1560,11 +1560,9 @@ fn allocStackPtr(func: *CodeGen, inst: Air.Inst.Index) !WValue { |
| 1560 | pointee_ty.fmt(mod), pointee_ty.abiSize(mod), | 1560 | pointee_ty.fmt(mod), pointee_ty.abiSize(mod), |
| 1561 | }); | 1561 | }); |
| 1562 | }; | 1562 | }; |
| 1563 | if (abi_alignment > func.stack_alignment) { | 1563 | func.stack_alignment = func.stack_alignment.max(abi_alignment); |
| 1564 | func.stack_alignment = abi_alignment; | ||
| 1565 | } | ||
| 1566 | 1564 | ||
| 1567 | const offset = std.mem.alignForward(u32, func.stack_size, abi_alignment); | 1565 | const offset: u32 = @intCast(abi_alignment.forward(func.stack_size)); |
| 1568 | defer func.stack_size = offset + abi_size; | 1566 | defer func.stack_size = offset + abi_size; |
| 1569 | 1567 | ||
| 1570 | return WValue{ .stack_offset = .{ .value = offset, .references = 1 } }; | 1568 | return WValue{ .stack_offset = .{ .value = offset, .references = 1 } }; |
| ... | @@ -1749,10 +1747,8 @@ fn isByRef(ty: Type, mod: *Module) bool { | ... | @@ -1749,10 +1747,8 @@ fn isByRef(ty: Type, mod: *Module) bool { |
| 1749 | return ty.hasRuntimeBitsIgnoreComptime(mod); | 1747 | return ty.hasRuntimeBitsIgnoreComptime(mod); |
| 1750 | }, | 1748 | }, |
| 1751 | .Struct => { | 1749 | .Struct => { |
| 1752 | if (mod.typeToStruct(ty)) |struct_obj| { | 1750 | if (mod.typeToPackedStruct(ty)) |packed_struct| { |
| 1753 | if (struct_obj.layout == .Packed and struct_obj.haveFieldTypes()) { | 1751 | return isByRef(packed_struct.backingIntType(ip).toType(), mod); |
| 1754 | return isByRef(struct_obj.backing_int_ty, mod); | ||
| 1755 | } | ||
| 1756 | } | 1752 | } |
| 1757 | return ty.hasRuntimeBitsIgnoreComptime(mod); | 1753 | return ty.hasRuntimeBitsIgnoreComptime(mod); |
| 1758 | }, | 1754 | }, |
| ... | @@ -2120,7 +2116,7 @@ fn airRet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -2120,7 +2116,7 @@ fn airRet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2120 | }); | 2116 | }); |
| 2121 | try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{ | 2117 | try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{ |
| 2122 | .offset = operand.offset(), | 2118 | .offset = operand.offset(), |
| 2123 | .alignment = scalar_type.abiAlignment(mod), | 2119 | .alignment = @intCast(scalar_type.abiAlignment(mod).toByteUnitsOptional().?), |
| 2124 | }); | 2120 | }); |
| 2125 | }, | 2121 | }, |
| 2126 | else => try func.emitWValue(operand), | 2122 | else => try func.emitWValue(operand), |
| ... | @@ -2385,19 +2381,19 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE | ... | @@ -2385,19 +2381,19 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE |
| 2385 | }, | 2381 | }, |
| 2386 | .Vector => switch (determineSimdStoreStrategy(ty, mod)) { | 2382 | .Vector => switch (determineSimdStoreStrategy(ty, mod)) { |
| 2387 | .unrolled => { | 2383 | .unrolled => { |
| 2388 | const len = @as(u32, @intCast(abi_size)); | 2384 | const len: u32 = @intCast(abi_size); |
| 2389 | return func.memcpy(lhs, rhs, .{ .imm32 = len }); | 2385 | return func.memcpy(lhs, rhs, .{ .imm32 = len }); |
| 2390 | }, | 2386 | }, |
| 2391 | .direct => { | 2387 | .direct => { |
| 2392 | try func.emitWValue(lhs); | 2388 | try func.emitWValue(lhs); |
| 2393 | try func.lowerToStack(rhs); | 2389 | try func.lowerToStack(rhs); |
| 2394 | // TODO: Add helper functions for simd opcodes | 2390 | // TODO: Add helper functions for simd opcodes |
| 2395 | const extra_index = @as(u32, @intCast(func.mir_extra.items.len)); | 2391 | const extra_index: u32 = @intCast(func.mir_extra.items.len); |
| 2396 | // stores as := opcode, offset, alignment (opcode::memarg) | 2392 | // stores as := opcode, offset, alignment (opcode::memarg) |
| 2397 | try func.mir_extra.appendSlice(func.gpa, &[_]u32{ | 2393 | try func.mir_extra.appendSlice(func.gpa, &[_]u32{ |
| 2398 | std.wasm.simdOpcode(.v128_store), | 2394 | std.wasm.simdOpcode(.v128_store), |
| 2399 | offset + lhs.offset(), | 2395 | offset + lhs.offset(), |
| 2400 | ty.abiAlignment(mod), | 2396 | @intCast(ty.abiAlignment(mod).toByteUnits(0)), |
| 2401 | }); | 2397 | }); |
| 2402 | return func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); | 2398 | return func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); |
| 2403 | }, | 2399 | }, |
| ... | @@ -2451,7 +2447,10 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE | ... | @@ -2451,7 +2447,10 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE |
| 2451 | // store rhs value at stack pointer's location in memory | 2447 | // store rhs value at stack pointer's location in memory |
| 2452 | try func.addMemArg( | 2448 | try func.addMemArg( |
| 2453 | Mir.Inst.Tag.fromOpcode(opcode), | 2449 | Mir.Inst.Tag.fromOpcode(opcode), |
| 2454 | .{ .offset = offset + lhs.offset(), .alignment = ty.abiAlignment(mod) }, | 2450 | .{ |
| 2451 | .offset = offset + lhs.offset(), | ||
| 2452 | .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?), | ||
| 2453 | }, | ||
| 2455 | ); | 2454 | ); |
| 2456 | } | 2455 | } |
| 2457 | 2456 | ||
| ... | @@ -2510,7 +2509,7 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu | ... | @@ -2510,7 +2509,7 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu |
| 2510 | try func.mir_extra.appendSlice(func.gpa, &[_]u32{ | 2509 | try func.mir_extra.appendSlice(func.gpa, &[_]u32{ |
| 2511 | std.wasm.simdOpcode(.v128_load), | 2510 | std.wasm.simdOpcode(.v128_load), |
| 2512 | offset + operand.offset(), | 2511 | offset + operand.offset(), |
| 2513 | ty.abiAlignment(mod), | 2512 | @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?), |
| 2514 | }); | 2513 | }); |
| 2515 | try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); | 2514 | try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); |
| 2516 | return WValue{ .stack = {} }; | 2515 | return WValue{ .stack = {} }; |
| ... | @@ -2526,7 +2525,10 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu | ... | @@ -2526,7 +2525,10 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu |
| 2526 | 2525 | ||
| 2527 | try func.addMemArg( | 2526 | try func.addMemArg( |
| 2528 | Mir.Inst.Tag.fromOpcode(opcode), | 2527 | Mir.Inst.Tag.fromOpcode(opcode), |
| 2529 | .{ .offset = offset + operand.offset(), .alignment = ty.abiAlignment(mod) }, | 2528 | .{ |
| 2529 | .offset = offset + operand.offset(), | ||
| 2530 | .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?), | ||
| 2531 | }, | ||
| 2530 | ); | 2532 | ); |
| 2531 | 2533 | ||
| 2532 | return WValue{ .stack = {} }; | 2534 | return WValue{ .stack = {} }; |
| ... | @@ -3023,10 +3025,10 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue | ... | @@ -3023,10 +3025,10 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue |
| 3023 | else => blk: { | 3025 | else => blk: { |
| 3024 | const layout: Module.UnionLayout = parent_ty.unionGetLayout(mod); | 3026 | const layout: Module.UnionLayout = parent_ty.unionGetLayout(mod); |
| 3025 | if (layout.payload_size == 0) break :blk 0; | 3027 | if (layout.payload_size == 0) break :blk 0; |
| 3026 | if (layout.payload_align > layout.tag_align) break :blk 0; | 3028 | if (layout.payload_align.compare(.gt, layout.tag_align)) break :blk 0; |
| 3027 | 3029 | ||
| 3028 | // tag is stored first so calculate offset from where payload starts | 3030 | // tag is stored first so calculate offset from where payload starts |
| 3029 | break :blk @as(u32, @intCast(std.mem.alignForward(u64, layout.tag_size, layout.tag_align))); | 3031 | break :blk layout.tag_align.forward(layout.tag_size); |
| 3030 | }, | 3032 | }, |
| 3031 | }, | 3033 | }, |
| 3032 | .Pointer => switch (parent_ty.ptrSize(mod)) { | 3034 | .Pointer => switch (parent_ty.ptrSize(mod)) { |
| ... | @@ -3103,8 +3105,12 @@ fn toTwosComplement(value: anytype, bits: u7) std.meta.Int(.unsigned, @typeInfo( | ... | @@ -3103,8 +3105,12 @@ fn toTwosComplement(value: anytype, bits: u7) std.meta.Int(.unsigned, @typeInfo( |
| 3103 | return @as(WantedT, @intCast(result)); | 3105 | return @as(WantedT, @intCast(result)); |
| 3104 | } | 3106 | } |
| 3105 | 3107 | ||
| 3108 | /// This function is intended to assert that `isByRef` returns `false` for `ty`. | ||
| 3109 | /// However such an assertion fails on the behavior tests currently. | ||
| 3106 | fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { | 3110 | fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { |
| 3107 | const mod = func.bin_file.base.options.module.?; | 3111 | const mod = func.bin_file.base.options.module.?; |
| 3112 | // TODO: enable this assertion | ||
| 3113 | //assert(!isByRef(ty, mod)); | ||
| 3108 | const ip = &mod.intern_pool; | 3114 | const ip = &mod.intern_pool; |
| 3109 | var val = arg_val; | 3115 | var val = arg_val; |
| 3110 | switch (ip.indexToKey(val.ip_index)) { | 3116 | switch (ip.indexToKey(val.ip_index)) { |
| ... | @@ -3235,16 +3241,18 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { | ... | @@ -3235,16 +3241,18 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { |
| 3235 | val.writeToMemory(ty, mod, &buf) catch unreachable; | 3241 | val.writeToMemory(ty, mod, &buf) catch unreachable; |
| 3236 | return func.storeSimdImmd(buf); | 3242 | return func.storeSimdImmd(buf); |
| 3237 | }, | 3243 | }, |
| 3238 | .struct_type, .anon_struct_type => { | 3244 | .struct_type => |struct_type| { |
| 3239 | const struct_obj = mod.typeToStruct(ty).?; | 3245 | // non-packed structs are not handled in this function because they |
| 3240 | assert(struct_obj.layout == .Packed); | 3246 | // are by-ref types. |
| 3247 | assert(struct_type.layout == .Packed); | ||
| 3241 | var buf: [8]u8 = .{0} ** 8; // zero the buffer so we do not read 0xaa as integer | 3248 | var buf: [8]u8 = .{0} ** 8; // zero the buffer so we do not read 0xaa as integer |
| 3242 | val.writeToPackedMemory(ty, func.bin_file.base.options.module.?, &buf, 0) catch unreachable; | 3249 | val.writeToPackedMemory(ty, mod, &buf, 0) catch unreachable; |
| 3250 | const backing_int_ty = struct_type.backingIntType(ip).toType(); | ||
| 3243 | const int_val = try mod.intValue( | 3251 | const int_val = try mod.intValue( |
| 3244 | struct_obj.backing_int_ty, | 3252 | backing_int_ty, |
| 3245 | std.mem.readIntLittle(u64, &buf), | 3253 | mem.readIntLittle(u64, &buf), |
| 3246 | ); | 3254 | ); |
| 3247 | return func.lowerConstant(int_val, struct_obj.backing_int_ty); | 3255 | return func.lowerConstant(int_val, backing_int_ty); |
| 3248 | }, | 3256 | }, |
| 3249 | else => unreachable, | 3257 | else => unreachable, |
| 3250 | }, | 3258 | }, |
| ... | @@ -3269,6 +3277,7 @@ fn storeSimdImmd(func: *CodeGen, value: [16]u8) !WValue { | ... | @@ -3269,6 +3277,7 @@ fn storeSimdImmd(func: *CodeGen, value: [16]u8) !WValue { |
| 3269 | 3277 | ||
| 3270 | fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue { | 3278 | fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue { |
| 3271 | const mod = func.bin_file.base.options.module.?; | 3279 | const mod = func.bin_file.base.options.module.?; |
| 3280 | const ip = &mod.intern_pool; | ||
| 3272 | switch (ty.zigTypeTag(mod)) { | 3281 | switch (ty.zigTypeTag(mod)) { |
| 3273 | .Bool, .ErrorSet => return WValue{ .imm32 = 0xaaaaaaaa }, | 3282 | .Bool, .ErrorSet => return WValue{ .imm32 = 0xaaaaaaaa }, |
| 3274 | .Int, .Enum => switch (ty.intInfo(mod).bits) { | 3283 | .Int, .Enum => switch (ty.intInfo(mod).bits) { |
| ... | @@ -3298,9 +3307,8 @@ fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue { | ... | @@ -3298,9 +3307,8 @@ fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue { |
| 3298 | return WValue{ .imm32 = 0xaaaaaaaa }; | 3307 | return WValue{ .imm32 = 0xaaaaaaaa }; |
| 3299 | }, | 3308 | }, |
| 3300 | .Struct => { | 3309 | .Struct => { |
| 3301 | const struct_obj = mod.typeToStruct(ty).?; | 3310 | const packed_struct = mod.typeToPackedStruct(ty).?; |
| 3302 | assert(struct_obj.layout == .Packed); | 3311 | return func.emitUndefined(packed_struct.backingIntType(ip).toType()); |
| 3303 | return func.emitUndefined(struct_obj.backing_int_ty); | ||
| 3304 | }, | 3312 | }, |
| 3305 | else => return func.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty.zigTypeTag(mod)}), | 3313 | else => return func.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty.zigTypeTag(mod)}), |
| 3306 | } | 3314 | } |
| ... | @@ -3340,7 +3348,7 @@ fn intStorageAsI32(storage: InternPool.Key.Int.Storage, mod: *Module) i32 { | ... | @@ -3340,7 +3348,7 @@ fn intStorageAsI32(storage: InternPool.Key.Int.Storage, mod: *Module) i32 { |
| 3340 | .i64 => |x| @as(i32, @intCast(x)), | 3348 | .i64 => |x| @as(i32, @intCast(x)), |
| 3341 | .u64 => |x| @as(i32, @bitCast(@as(u32, @intCast(x)))), | 3349 | .u64 => |x| @as(i32, @bitCast(@as(u32, @intCast(x)))), |
| 3342 | .big_int => unreachable, | 3350 | .big_int => unreachable, |
| 3343 | .lazy_align => |ty| @as(i32, @bitCast(ty.toType().abiAlignment(mod))), | 3351 | .lazy_align => |ty| @as(i32, @bitCast(@as(u32, @intCast(ty.toType().abiAlignment(mod).toByteUnits(0))))), |
| 3344 | .lazy_size => |ty| @as(i32, @bitCast(@as(u32, @intCast(ty.toType().abiSize(mod))))), | 3352 | .lazy_size => |ty| @as(i32, @bitCast(@as(u32, @intCast(ty.toType().abiSize(mod))))), |
| 3345 | }; | 3353 | }; |
| 3346 | } | 3354 | } |
| ... | @@ -3757,6 +3765,7 @@ fn structFieldPtr( | ... | @@ -3757,6 +3765,7 @@ fn structFieldPtr( |
| 3757 | 3765 | ||
| 3758 | fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 3766 | fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3759 | const mod = func.bin_file.base.options.module.?; | 3767 | const mod = func.bin_file.base.options.module.?; |
| 3768 | const ip = &mod.intern_pool; | ||
| 3760 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; | 3769 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 3761 | const struct_field = func.air.extraData(Air.StructField, ty_pl.payload).data; | 3770 | const struct_field = func.air.extraData(Air.StructField, ty_pl.payload).data; |
| 3762 | 3771 | ||
| ... | @@ -3769,9 +3778,9 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3769,9 +3778,9 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3769 | const result = switch (struct_ty.containerLayout(mod)) { | 3778 | const result = switch (struct_ty.containerLayout(mod)) { |
| 3770 | .Packed => switch (struct_ty.zigTypeTag(mod)) { | 3779 | .Packed => switch (struct_ty.zigTypeTag(mod)) { |
| 3771 | .Struct => result: { | 3780 | .Struct => result: { |
| 3772 | const struct_obj = mod.typeToStruct(struct_ty).?; | 3781 | const packed_struct = mod.typeToPackedStruct(struct_ty).?; |
| 3773 | const offset = struct_obj.packedFieldBitOffset(mod, field_index); | 3782 | const offset = mod.structPackedFieldBitOffset(packed_struct, field_index); |
| 3774 | const backing_ty = struct_obj.backing_int_ty; | 3783 | const backing_ty = packed_struct.backingIntType(ip).toType(); |
| 3775 | const wasm_bits = toWasmBits(backing_ty.intInfo(mod).bits) orelse { | 3784 | const wasm_bits = toWasmBits(backing_ty.intInfo(mod).bits) orelse { |
| 3776 | return func.fail("TODO: airStructFieldVal for packed structs larger than 128 bits", .{}); | 3785 | return func.fail("TODO: airStructFieldVal for packed structs larger than 128 bits", .{}); |
| 3777 | }; | 3786 | }; |
| ... | @@ -3793,7 +3802,7 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3793,7 +3802,7 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3793 | const truncated = try func.trunc(shifted_value, int_type, backing_ty); | 3802 | const truncated = try func.trunc(shifted_value, int_type, backing_ty); |
| 3794 | const bitcasted = try func.bitcast(field_ty, int_type, truncated); | 3803 | const bitcasted = try func.bitcast(field_ty, int_type, truncated); |
| 3795 | break :result try bitcasted.toLocal(func, field_ty); | 3804 | break :result try bitcasted.toLocal(func, field_ty); |
| 3796 | } else if (field_ty.isPtrAtRuntime(mod) and struct_obj.fields.count() == 1) { | 3805 | } else if (field_ty.isPtrAtRuntime(mod) and packed_struct.field_types.len == 1) { |
| 3797 | // In this case we do not have to perform any transformations, | 3806 | // In this case we do not have to perform any transformations, |
| 3798 | // we can simply reuse the operand. | 3807 | // we can simply reuse the operand. |
| 3799 | break :result func.reuseOperand(struct_field.struct_operand, operand); | 3808 | break :result func.reuseOperand(struct_field.struct_operand, operand); |
| ... | @@ -4053,7 +4062,7 @@ fn airIsErr(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerErro | ... | @@ -4053,7 +4062,7 @@ fn airIsErr(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerErro |
| 4053 | if (pl_ty.hasRuntimeBitsIgnoreComptime(mod)) { | 4062 | if (pl_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 4054 | try func.addMemArg(.i32_load16_u, .{ | 4063 | try func.addMemArg(.i32_load16_u, .{ |
| 4055 | .offset = operand.offset() + @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod))), | 4064 | .offset = operand.offset() + @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod))), |
| 4056 | .alignment = Type.anyerror.abiAlignment(mod), | 4065 | .alignment = @intCast(Type.anyerror.abiAlignment(mod).toByteUnitsOptional().?), |
| 4057 | }); | 4066 | }); |
| 4058 | } | 4067 | } |
| 4059 | 4068 | ||
| ... | @@ -4141,7 +4150,10 @@ fn airWrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void | ... | @@ -4141,7 +4150,10 @@ fn airWrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void |
| 4141 | try func.emitWValue(err_union); | 4150 | try func.emitWValue(err_union); |
| 4142 | try func.addImm32(0); | 4151 | try func.addImm32(0); |
| 4143 | const err_val_offset = @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod))); | 4152 | const err_val_offset = @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod))); |
| 4144 | try func.addMemArg(.i32_store16, .{ .offset = err_union.offset() + err_val_offset, .alignment = 2 }); | 4153 | try func.addMemArg(.i32_store16, .{ |
| 4154 | .offset = err_union.offset() + err_val_offset, | ||
| 4155 | .alignment = 2, | ||
| 4156 | }); | ||
| 4145 | break :result err_union; | 4157 | break :result err_union; |
| 4146 | }; | 4158 | }; |
| 4147 | func.finishAir(inst, result, &.{ty_op.operand}); | 4159 | func.finishAir(inst, result, &.{ty_op.operand}); |
| ... | @@ -4977,7 +4989,7 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4977,7 +4989,7 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4977 | try func.mir_extra.appendSlice(func.gpa, &[_]u32{ | 4989 | try func.mir_extra.appendSlice(func.gpa, &[_]u32{ |
| 4978 | opcode, | 4990 | opcode, |
| 4979 | operand.offset(), | 4991 | operand.offset(), |
| 4980 | elem_ty.abiAlignment(mod), | 4992 | @intCast(elem_ty.abiAlignment(mod).toByteUnitsOptional().?), |
| 4981 | }); | 4993 | }); |
| 4982 | try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); | 4994 | try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); |
| 4983 | try func.addLabel(.local_set, result.local.value); | 4995 | try func.addLabel(.local_set, result.local.value); |
| ... | @@ -5065,7 +5077,7 @@ fn airShuffle(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5065,7 +5077,7 @@ fn airShuffle(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5065 | std.wasm.simdOpcode(.i8x16_shuffle), | 5077 | std.wasm.simdOpcode(.i8x16_shuffle), |
| 5066 | } ++ [1]u32{undefined} ** 4; | 5078 | } ++ [1]u32{undefined} ** 4; |
| 5067 | 5079 | ||
| 5068 | var lanes = std.mem.asBytes(operands[1..]); | 5080 | var lanes = mem.asBytes(operands[1..]); |
| 5069 | for (0..@as(usize, @intCast(mask_len))) |index| { | 5081 | for (0..@as(usize, @intCast(mask_len))) |index| { |
| 5070 | const mask_elem = (try mask.elemValue(mod, index)).toSignedInt(mod); | 5082 | const mask_elem = (try mask.elemValue(mod, index)).toSignedInt(mod); |
| 5071 | const base_index = if (mask_elem >= 0) | 5083 | const base_index = if (mask_elem >= 0) |
| ... | @@ -5099,6 +5111,7 @@ fn airReduce(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5099,6 +5111,7 @@ fn airReduce(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5099 | 5111 | ||
| 5100 | fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 5112 | fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5101 | const mod = func.bin_file.base.options.module.?; | 5113 | const mod = func.bin_file.base.options.module.?; |
| 5114 | const ip = &mod.intern_pool; | ||
| 5102 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; | 5115 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 5103 | const result_ty = func.typeOfIndex(inst); | 5116 | const result_ty = func.typeOfIndex(inst); |
| 5104 | const len = @as(usize, @intCast(result_ty.arrayLen(mod))); | 5117 | const len = @as(usize, @intCast(result_ty.arrayLen(mod))); |
| ... | @@ -5150,13 +5163,13 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5150,13 +5163,13 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5150 | if (isByRef(result_ty, mod)) { | 5163 | if (isByRef(result_ty, mod)) { |
| 5151 | return func.fail("TODO: airAggregateInit for packed structs larger than 64 bits", .{}); | 5164 | return func.fail("TODO: airAggregateInit for packed structs larger than 64 bits", .{}); |
| 5152 | } | 5165 | } |
| 5153 | const struct_obj = mod.typeToStruct(result_ty).?; | 5166 | const packed_struct = mod.typeToPackedStruct(result_ty).?; |
| 5154 | const fields = struct_obj.fields.values(); | 5167 | const field_types = packed_struct.field_types; |
| 5155 | const backing_type = struct_obj.backing_int_ty; | 5168 | const backing_type = packed_struct.backingIntType(ip).toType(); |
| 5156 | 5169 | ||
| 5157 | // ensure the result is zero'd | 5170 | // ensure the result is zero'd |
| 5158 | const result = try func.allocLocal(backing_type); | 5171 | const result = try func.allocLocal(backing_type); |
| 5159 | if (struct_obj.backing_int_ty.bitSize(mod) <= 32) | 5172 | if (backing_type.bitSize(mod) <= 32) |
| 5160 | try func.addImm32(0) | 5173 | try func.addImm32(0) |
| 5161 | else | 5174 | else |
| 5162 | try func.addImm64(0); | 5175 | try func.addImm64(0); |
| ... | @@ -5164,22 +5177,22 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5164,22 +5177,22 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5164 | 5177 | ||
| 5165 | var current_bit: u16 = 0; | 5178 | var current_bit: u16 = 0; |
| 5166 | for (elements, 0..) |elem, elem_index| { | 5179 | for (elements, 0..) |elem, elem_index| { |
| 5167 | const field = fields[elem_index]; | 5180 | const field_ty = field_types.get(ip)[elem_index].toType(); |
| 5168 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | 5181 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 5169 | 5182 | ||
| 5170 | const shift_val = if (struct_obj.backing_int_ty.bitSize(mod) <= 32) | 5183 | const shift_val = if (backing_type.bitSize(mod) <= 32) |
| 5171 | WValue{ .imm32 = current_bit } | 5184 | WValue{ .imm32 = current_bit } |
| 5172 | else | 5185 | else |
| 5173 | WValue{ .imm64 = current_bit }; | 5186 | WValue{ .imm64 = current_bit }; |
| 5174 | 5187 | ||
| 5175 | const value = try func.resolveInst(elem); | 5188 | const value = try func.resolveInst(elem); |
| 5176 | const value_bit_size = @as(u16, @intCast(field.ty.bitSize(mod))); | 5189 | const value_bit_size: u16 = @intCast(field_ty.bitSize(mod)); |
| 5177 | const int_ty = try mod.intType(.unsigned, value_bit_size); | 5190 | const int_ty = try mod.intType(.unsigned, value_bit_size); |
| 5178 | 5191 | ||
| 5179 | // load our current result on stack so we can perform all transformations | 5192 | // load our current result on stack so we can perform all transformations |
| 5180 | // using only stack values. Saving the cost of loads and stores. | 5193 | // using only stack values. Saving the cost of loads and stores. |
| 5181 | try func.emitWValue(result); | 5194 | try func.emitWValue(result); |
| 5182 | const bitcasted = try func.bitcast(int_ty, field.ty, value); | 5195 | const bitcasted = try func.bitcast(int_ty, field_ty, value); |
| 5183 | const extended_val = try func.intcast(bitcasted, int_ty, backing_type); | 5196 | const extended_val = try func.intcast(bitcasted, int_ty, backing_type); |
| 5184 | // no need to shift any values when the current offset is 0 | 5197 | // no need to shift any values when the current offset is 0 |
| 5185 | const shifted = if (current_bit != 0) shifted: { | 5198 | const shifted = if (current_bit != 0) shifted: { |
| ... | @@ -5199,7 +5212,7 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5199,7 +5212,7 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5199 | if ((try result_ty.structFieldValueComptime(mod, elem_index)) != null) continue; | 5212 | if ((try result_ty.structFieldValueComptime(mod, elem_index)) != null) continue; |
| 5200 | 5213 | ||
| 5201 | const elem_ty = result_ty.structFieldType(elem_index, mod); | 5214 | const elem_ty = result_ty.structFieldType(elem_index, mod); |
| 5202 | const elem_size = @as(u32, @intCast(elem_ty.abiSize(mod))); | 5215 | const elem_size: u32 = @intCast(elem_ty.abiSize(mod)); |
| 5203 | const value = try func.resolveInst(elem); | 5216 | const value = try func.resolveInst(elem); |
| 5204 | try func.store(offset, value, elem_ty, 0); | 5217 | try func.store(offset, value, elem_ty, 0); |
| 5205 | 5218 | ||
| ... | @@ -5256,7 +5269,7 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5256,7 +5269,7 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5256 | if (isByRef(union_ty, mod)) { | 5269 | if (isByRef(union_ty, mod)) { |
| 5257 | const result_ptr = try func.allocStack(union_ty); | 5270 | const result_ptr = try func.allocStack(union_ty); |
| 5258 | const payload = try func.resolveInst(extra.init); | 5271 | const payload = try func.resolveInst(extra.init); |
| 5259 | if (layout.tag_align >= layout.payload_align) { | 5272 | if (layout.tag_align.compare(.gte, layout.payload_align)) { |
| 5260 | if (isByRef(field_ty, mod)) { | 5273 | if (isByRef(field_ty, mod)) { |
| 5261 | const payload_ptr = try func.buildPointerOffset(result_ptr, layout.tag_size, .new); | 5274 | const payload_ptr = try func.buildPointerOffset(result_ptr, layout.tag_size, .new); |
| 5262 | try func.store(payload_ptr, payload, field_ty, 0); | 5275 | try func.store(payload_ptr, payload, field_ty, 0); |
| ... | @@ -5420,9 +5433,9 @@ fn airSetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5420,9 +5433,9 @@ fn airSetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5420 | 5433 | ||
| 5421 | // when the tag alignment is smaller than the payload, the field will be stored | 5434 | // when the tag alignment is smaller than the payload, the field will be stored |
| 5422 | // after the payload. | 5435 | // after the payload. |
| 5423 | const offset = if (layout.tag_align < layout.payload_align) blk: { | 5436 | const offset: u32 = if (layout.tag_align.compare(.lt, layout.payload_align)) blk: { |
| 5424 | break :blk @as(u32, @intCast(layout.payload_size)); | 5437 | break :blk @intCast(layout.payload_size); |
| 5425 | } else @as(u32, 0); | 5438 | } else 0; |
| 5426 | try func.store(union_ptr, new_tag, tag_ty, offset); | 5439 | try func.store(union_ptr, new_tag, tag_ty, offset); |
| 5427 | func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs }); | 5440 | func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs }); |
| 5428 | } | 5441 | } |
| ... | @@ -5439,9 +5452,9 @@ fn airGetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5439,9 +5452,9 @@ fn airGetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5439 | const operand = try func.resolveInst(ty_op.operand); | 5452 | const operand = try func.resolveInst(ty_op.operand); |
| 5440 | // when the tag alignment is smaller than the payload, the field will be stored | 5453 | // when the tag alignment is smaller than the payload, the field will be stored |
| 5441 | // after the payload. | 5454 | // after the payload. |
| 5442 | const offset = if (layout.tag_align < layout.payload_align) blk: { | 5455 | const offset: u32 = if (layout.tag_align.compare(.lt, layout.payload_align)) blk: { |
| 5443 | break :blk @as(u32, @intCast(layout.payload_size)); | 5456 | break :blk @intCast(layout.payload_size); |
| 5444 | } else @as(u32, 0); | 5457 | } else 0; |
| 5445 | const tag = try func.load(operand, tag_ty, offset); | 5458 | const tag = try func.load(operand, tag_ty, offset); |
| 5446 | const result = try tag.toLocal(func, tag_ty); | 5459 | const result = try tag.toLocal(func, tag_ty); |
| 5447 | func.finishAir(inst, result, &.{ty_op.operand}); | 5460 | func.finishAir(inst, result, &.{ty_op.operand}); |
| ... | @@ -6366,7 +6379,7 @@ fn lowerTry( | ... | @@ -6366,7 +6379,7 @@ fn lowerTry( |
| 6366 | const err_offset = @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod))); | 6379 | const err_offset = @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod))); |
| 6367 | try func.addMemArg(.i32_load16_u, .{ | 6380 | try func.addMemArg(.i32_load16_u, .{ |
| 6368 | .offset = err_union.offset() + err_offset, | 6381 | .offset = err_union.offset() + err_offset, |
| 6369 | .alignment = Type.anyerror.abiAlignment(mod), | 6382 | .alignment = @intCast(Type.anyerror.abiAlignment(mod).toByteUnitsOptional().?), |
| 6370 | }); | 6383 | }); |
| 6371 | } | 6384 | } |
| 6372 | try func.addTag(.i32_eqz); | 6385 | try func.addTag(.i32_eqz); |
| ... | @@ -7287,7 +7300,7 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7287,7 +7300,7 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7287 | else => |size| return func.fail("TODO: implement `@cmpxchg` for types with abi size '{d}'", .{size}), | 7300 | else => |size| return func.fail("TODO: implement `@cmpxchg` for types with abi size '{d}'", .{size}), |
| 7288 | }, .{ | 7301 | }, .{ |
| 7289 | .offset = ptr_operand.offset(), | 7302 | .offset = ptr_operand.offset(), |
| 7290 | .alignment = ty.abiAlignment(mod), | 7303 | .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?), |
| 7291 | }); | 7304 | }); |
| 7292 | try func.addLabel(.local_tee, val_local.local.value); | 7305 | try func.addLabel(.local_tee, val_local.local.value); |
| 7293 | _ = try func.cmp(.stack, expected_val, ty, .eq); | 7306 | _ = try func.cmp(.stack, expected_val, ty, .eq); |
| ... | @@ -7349,7 +7362,7 @@ fn airAtomicLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7349,7 +7362,7 @@ fn airAtomicLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7349 | try func.emitWValue(ptr); | 7362 | try func.emitWValue(ptr); |
| 7350 | try func.addAtomicMemArg(tag, .{ | 7363 | try func.addAtomicMemArg(tag, .{ |
| 7351 | .offset = ptr.offset(), | 7364 | .offset = ptr.offset(), |
| 7352 | .alignment = ty.abiAlignment(mod), | 7365 | .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?), |
| 7353 | }); | 7366 | }); |
| 7354 | } else { | 7367 | } else { |
| 7355 | _ = try func.load(ptr, ty, 0); | 7368 | _ = try func.load(ptr, ty, 0); |
| ... | @@ -7410,7 +7423,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7410,7 +7423,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7410 | }, | 7423 | }, |
| 7411 | .{ | 7424 | .{ |
| 7412 | .offset = ptr.offset(), | 7425 | .offset = ptr.offset(), |
| 7413 | .alignment = ty.abiAlignment(mod), | 7426 | .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?), |
| 7414 | }, | 7427 | }, |
| 7415 | ); | 7428 | ); |
| 7416 | const select_res = try func.allocLocal(ty); | 7429 | const select_res = try func.allocLocal(ty); |
| ... | @@ -7470,7 +7483,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7470,7 +7483,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7470 | }; | 7483 | }; |
| 7471 | try func.addAtomicMemArg(tag, .{ | 7484 | try func.addAtomicMemArg(tag, .{ |
| 7472 | .offset = ptr.offset(), | 7485 | .offset = ptr.offset(), |
| 7473 | .alignment = ty.abiAlignment(mod), | 7486 | .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?), |
| 7474 | }); | 7487 | }); |
| 7475 | const result = try WValue.toLocal(.stack, func, ty); | 7488 | const result = try WValue.toLocal(.stack, func, ty); |
| 7476 | return func.finishAir(inst, result, &.{ pl_op.operand, extra.operand }); | 7489 | return func.finishAir(inst, result, &.{ pl_op.operand, extra.operand }); |
| ... | @@ -7566,7 +7579,7 @@ fn airAtomicStore(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7566,7 +7579,7 @@ fn airAtomicStore(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7566 | try func.lowerToStack(operand); | 7579 | try func.lowerToStack(operand); |
| 7567 | try func.addAtomicMemArg(tag, .{ | 7580 | try func.addAtomicMemArg(tag, .{ |
| 7568 | .offset = ptr.offset(), | 7581 | .offset = ptr.offset(), |
| 7569 | .alignment = ty.abiAlignment(mod), | 7582 | .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?), |
| 7570 | }); | 7583 | }); |
| 7571 | } else { | 7584 | } else { |
| 7572 | try func.store(ptr, operand, ty, 0); | 7585 | try func.store(ptr, operand, ty, 0); |
src/arch/wasm/abi.zig+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-scalar | 36 | 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-natural | 38 | 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"); |
| 27 | const Mir = @import("Mir.zig"); | 27 | const Mir = @import("Mir.zig"); |
| 28 | const Module = @import("../../Module.zig"); | 28 | const Module = @import("../../Module.zig"); |
| 29 | const InternPool = @import("../../InternPool.zig"); | 29 | const InternPool = @import("../../InternPool.zig"); |
| 30 | const Alignment = InternPool.Alignment; | ||
| 30 | const Target = std.Target; | 31 | const Target = std.Target; |
| 31 | const Type = @import("../../type.zig").Type; | 32 | const Type = @import("../../type.zig").Type; |
| 32 | const TypedValue = @import("../../TypedValue.zig"); | 33 | const TypedValue = @import("../../TypedValue.zig"); |
| ... | @@ -607,19 +608,21 @@ const InstTracking = struct { | ... | @@ -607,19 +608,21 @@ const InstTracking = struct { |
| 607 | 608 | ||
| 608 | const FrameAlloc = struct { | 609 | const FrameAlloc = struct { |
| 609 | abi_size: u31, | 610 | abi_size: u31, |
| 610 | abi_align: u5, | 611 | abi_align: Alignment, |
| 611 | ref_count: u16, | 612 | ref_count: u16, |
| 612 | 613 | ||
| 613 | fn init(alloc_abi: struct { size: u64, alignment: u32 }) FrameAlloc { | 614 | fn init(alloc_abi: struct { size: u64, alignment: Alignment }) FrameAlloc { |
| 614 | assert(math.isPowerOfTwo(alloc_abi.alignment)); | ||
| 615 | return .{ | 615 | return .{ |
| 616 | .abi_size = @intCast(alloc_abi.size), | 616 | .abi_size = @intCast(alloc_abi.size), |
| 617 | .abi_align = math.log2_int(u32, alloc_abi.alignment), | 617 | .abi_align = alloc_abi.alignment, |
| 618 | .ref_count = 0, | 618 | .ref_count = 0, |
| 619 | }; | 619 | }; |
| 620 | } | 620 | } |
| 621 | fn initType(ty: Type, mod: *Module) FrameAlloc { | 621 | fn initType(ty: Type, mod: *Module) FrameAlloc { |
| 622 | return init(.{ .size = ty.abiSize(mod), .alignment = ty.abiAlignment(mod) }); | 622 | return init(.{ |
| 623 | .size = ty.abiSize(mod), | ||
| 624 | .alignment = ty.abiAlignment(mod), | ||
| 625 | }); | ||
| 623 | } | 626 | } |
| 624 | }; | 627 | }; |
| 625 | 628 | ||
| ... | @@ -702,12 +705,12 @@ pub fn generate( | ... | @@ -702,12 +705,12 @@ pub fn generate( |
| 702 | @intFromEnum(FrameIndex.stack_frame), | 705 | @intFromEnum(FrameIndex.stack_frame), |
| 703 | FrameAlloc.init(.{ | 706 | FrameAlloc.init(.{ |
| 704 | .size = 0, | 707 | .size = 0, |
| 705 | .alignment = @intCast(func.analysis(ip).stack_alignment.toByteUnitsOptional() orelse 1), | 708 | .alignment = func.analysis(ip).stack_alignment.max(.@"1"), |
| 706 | }), | 709 | }), |
| 707 | ); | 710 | ); |
| 708 | function.frame_allocs.set( | 711 | function.frame_allocs.set( |
| 709 | @intFromEnum(FrameIndex.call_frame), | 712 | @intFromEnum(FrameIndex.call_frame), |
| 710 | FrameAlloc.init(.{ .size = 0, .alignment = 1 }), | 713 | FrameAlloc.init(.{ .size = 0, .alignment = .@"1" }), |
| 711 | ); | 714 | ); |
| 712 | 715 | ||
| 713 | const fn_info = mod.typeToFunc(fn_type).?; | 716 | const fn_info = mod.typeToFunc(fn_type).?; |
| ... | @@ -729,15 +732,21 @@ pub fn generate( | ... | @@ -729,15 +732,21 @@ pub fn generate( |
| 729 | function.ret_mcv = call_info.return_value; | 732 | function.ret_mcv = call_info.return_value; |
| 730 | function.frame_allocs.set(@intFromEnum(FrameIndex.ret_addr), FrameAlloc.init(.{ | 733 | function.frame_allocs.set(@intFromEnum(FrameIndex.ret_addr), FrameAlloc.init(.{ |
| 731 | .size = Type.usize.abiSize(mod), | 734 | .size = Type.usize.abiSize(mod), |
| 732 | .alignment = @min(Type.usize.abiAlignment(mod), call_info.stack_align), | 735 | .alignment = Type.usize.abiAlignment(mod).min(call_info.stack_align), |
| 733 | })); | 736 | })); |
| 734 | function.frame_allocs.set(@intFromEnum(FrameIndex.base_ptr), FrameAlloc.init(.{ | 737 | function.frame_allocs.set(@intFromEnum(FrameIndex.base_ptr), FrameAlloc.init(.{ |
| 735 | .size = Type.usize.abiSize(mod), | 738 | .size = Type.usize.abiSize(mod), |
| 736 | .alignment = @min(Type.usize.abiAlignment(mod) * 2, call_info.stack_align), | 739 | .alignment = Alignment.min( |
| 740 | call_info.stack_align, | ||
| 741 | Alignment.fromNonzeroByteUnits(bin_file.options.target.stackAlignment()), | ||
| 742 | ), | ||
| 737 | })); | 743 | })); |
| 738 | function.frame_allocs.set( | 744 | function.frame_allocs.set( |
| 739 | @intFromEnum(FrameIndex.args_frame), | 745 | @intFromEnum(FrameIndex.args_frame), |
| 740 | FrameAlloc.init(.{ .size = call_info.stack_byte_count, .alignment = call_info.stack_align }), | 746 | FrameAlloc.init(.{ |
| 747 | .size = call_info.stack_byte_count, | ||
| 748 | .alignment = call_info.stack_align, | ||
| 749 | }), | ||
| 741 | ); | 750 | ); |
| 742 | 751 | ||
| 743 | function.gen() catch |err| switch (err) { | 752 | function.gen() catch |err| switch (err) { |
| ... | @@ -2156,8 +2165,8 @@ fn setFrameLoc( | ... | @@ -2156,8 +2165,8 @@ fn setFrameLoc( |
| 2156 | ) void { | 2165 | ) void { |
| 2157 | const frame_i = @intFromEnum(frame_index); | 2166 | const frame_i = @intFromEnum(frame_index); |
| 2158 | if (aligned) { | 2167 | if (aligned) { |
| 2159 | const alignment = @as(i32, 1) << self.frame_allocs.items(.abi_align)[frame_i]; | 2168 | const alignment = self.frame_allocs.items(.abi_align)[frame_i]; |
| 2160 | offset.* = mem.alignForward(i32, offset.*, alignment); | 2169 | offset.* = @intCast(alignment.forward(@intCast(offset.*))); |
| 2161 | } | 2170 | } |
| 2162 | self.frame_locs.set(frame_i, .{ .base = base, .disp = offset.* }); | 2171 | self.frame_locs.set(frame_i, .{ .base = base, .disp = offset.* }); |
| 2163 | offset.* += self.frame_allocs.items(.abi_size)[frame_i]; | 2172 | offset.* += self.frame_allocs.items(.abi_size)[frame_i]; |
| ... | @@ -2179,7 +2188,7 @@ fn computeFrameLayout(self: *Self) !FrameLayout { | ... | @@ -2179,7 +2188,7 @@ fn computeFrameLayout(self: *Self) !FrameLayout { |
| 2179 | const SortContext = struct { | 2188 | const SortContext = struct { |
| 2180 | frame_align: @TypeOf(frame_align), | 2189 | frame_align: @TypeOf(frame_align), |
| 2181 | pub fn lessThan(context: @This(), lhs: FrameIndex, rhs: FrameIndex) bool { | 2190 | pub fn lessThan(context: @This(), lhs: FrameIndex, rhs: FrameIndex) bool { |
| 2182 | return context.frame_align[@intFromEnum(lhs)] > context.frame_align[@intFromEnum(rhs)]; | 2191 | return context.frame_align[@intFromEnum(lhs)].compare(.gt, context.frame_align[@intFromEnum(rhs)]); |
| 2183 | } | 2192 | } |
| 2184 | }; | 2193 | }; |
| 2185 | const sort_context = SortContext{ .frame_align = frame_align }; | 2194 | const sort_context = SortContext{ .frame_align = frame_align }; |
| ... | @@ -2189,8 +2198,8 @@ fn computeFrameLayout(self: *Self) !FrameLayout { | ... | @@ -2189,8 +2198,8 @@ fn computeFrameLayout(self: *Self) !FrameLayout { |
| 2189 | const call_frame_align = frame_align[@intFromEnum(FrameIndex.call_frame)]; | 2198 | const call_frame_align = frame_align[@intFromEnum(FrameIndex.call_frame)]; |
| 2190 | const stack_frame_align = frame_align[@intFromEnum(FrameIndex.stack_frame)]; | 2199 | const stack_frame_align = frame_align[@intFromEnum(FrameIndex.stack_frame)]; |
| 2191 | const args_frame_align = frame_align[@intFromEnum(FrameIndex.args_frame)]; | 2200 | const args_frame_align = frame_align[@intFromEnum(FrameIndex.args_frame)]; |
| 2192 | const needed_align = @max(call_frame_align, stack_frame_align); | 2201 | const needed_align = call_frame_align.max(stack_frame_align); |
| 2193 | const need_align_stack = needed_align > args_frame_align; | 2202 | const need_align_stack = needed_align.compare(.gt, args_frame_align); |
| 2194 | 2203 | ||
| 2195 | // Create list of registers to save in the prologue. | 2204 | // Create list of registers to save in the prologue. |
| 2196 | // TODO handle register classes | 2205 | // TODO handle register classes |
| ... | @@ -2214,21 +2223,21 @@ fn computeFrameLayout(self: *Self) !FrameLayout { | ... | @@ -2214,21 +2223,21 @@ fn computeFrameLayout(self: *Self) !FrameLayout { |
| 2214 | self.setFrameLoc(.stack_frame, .rsp, &rsp_offset, true); | 2223 | self.setFrameLoc(.stack_frame, .rsp, &rsp_offset, true); |
| 2215 | for (stack_frame_order) |frame_index| self.setFrameLoc(frame_index, .rsp, &rsp_offset, true); | 2224 | for (stack_frame_order) |frame_index| self.setFrameLoc(frame_index, .rsp, &rsp_offset, true); |
| 2216 | rsp_offset += stack_frame_align_offset; | 2225 | rsp_offset += stack_frame_align_offset; |
| 2217 | rsp_offset = mem.alignForward(i32, rsp_offset, @as(i32, 1) << needed_align); | 2226 | rsp_offset = @intCast(needed_align.forward(@intCast(rsp_offset))); |
| 2218 | rsp_offset -= stack_frame_align_offset; | 2227 | rsp_offset -= stack_frame_align_offset; |
| 2219 | frame_size[@intFromEnum(FrameIndex.call_frame)] = | 2228 | frame_size[@intFromEnum(FrameIndex.call_frame)] = |
| 2220 | @intCast(rsp_offset - frame_offset[@intFromEnum(FrameIndex.stack_frame)]); | 2229 | @intCast(rsp_offset - frame_offset[@intFromEnum(FrameIndex.stack_frame)]); |
| 2221 | 2230 | ||
| 2222 | return .{ | 2231 | return .{ |
| 2223 | .stack_mask = @as(u32, math.maxInt(u32)) << (if (need_align_stack) needed_align else 0), | 2232 | .stack_mask = @as(u32, math.maxInt(u32)) << @intCast(if (need_align_stack) @intFromEnum(needed_align) else 0), |
| 2224 | .stack_adjust = @intCast(rsp_offset - frame_offset[@intFromEnum(FrameIndex.call_frame)]), | 2233 | .stack_adjust = @intCast(rsp_offset - frame_offset[@intFromEnum(FrameIndex.call_frame)]), |
| 2225 | .save_reg_list = save_reg_list, | 2234 | .save_reg_list = save_reg_list, |
| 2226 | }; | 2235 | }; |
| 2227 | } | 2236 | } |
| 2228 | 2237 | ||
| 2229 | fn getFrameAddrAlignment(self: *Self, frame_addr: FrameAddr) u32 { | 2238 | fn getFrameAddrAlignment(self: *Self, frame_addr: FrameAddr) Alignment { |
| 2230 | const alloc_align = @as(u32, 1) << self.frame_allocs.get(@intFromEnum(frame_addr.index)).abi_align; | 2239 | const alloc_align = self.frame_allocs.get(@intFromEnum(frame_addr.index)).abi_align; |
| 2231 | return @min(alloc_align, @as(u32, @bitCast(frame_addr.off)) & (alloc_align - 1)); | 2240 | return @enumFromInt(@min(@intFromEnum(alloc_align), @ctz(frame_addr.off))); |
| 2232 | } | 2241 | } |
| 2233 | 2242 | ||
| 2234 | fn getFrameAddrSize(self: *Self, frame_addr: FrameAddr) u32 { | 2243 | fn getFrameAddrSize(self: *Self, frame_addr: FrameAddr) u32 { |
| ... | @@ -2241,13 +2250,13 @@ fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex { | ... | @@ -2241,13 +2250,13 @@ fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex { |
| 2241 | const frame_align = frame_allocs_slice.items(.abi_align); | 2250 | const frame_align = frame_allocs_slice.items(.abi_align); |
| 2242 | 2251 | ||
| 2243 | const stack_frame_align = &frame_align[@intFromEnum(FrameIndex.stack_frame)]; | 2252 | const stack_frame_align = &frame_align[@intFromEnum(FrameIndex.stack_frame)]; |
| 2244 | stack_frame_align.* = @max(stack_frame_align.*, alloc.abi_align); | 2253 | stack_frame_align.* = stack_frame_align.max(alloc.abi_align); |
| 2245 | 2254 | ||
| 2246 | for (self.free_frame_indices.keys(), 0..) |frame_index, free_i| { | 2255 | for (self.free_frame_indices.keys(), 0..) |frame_index, free_i| { |
| 2247 | const abi_size = frame_size[@intFromEnum(frame_index)]; | 2256 | const abi_size = frame_size[@intFromEnum(frame_index)]; |
| 2248 | if (abi_size != alloc.abi_size) continue; | 2257 | if (abi_size != alloc.abi_size) continue; |
| 2249 | const abi_align = &frame_align[@intFromEnum(frame_index)]; | 2258 | const abi_align = &frame_align[@intFromEnum(frame_index)]; |
| 2250 | abi_align.* = @max(abi_align.*, alloc.abi_align); | 2259 | abi_align.* = abi_align.max(alloc.abi_align); |
| 2251 | 2260 | ||
| 2252 | _ = self.free_frame_indices.swapRemoveAt(free_i); | 2261 | _ = self.free_frame_indices.swapRemoveAt(free_i); |
| 2253 | return frame_index; | 2262 | return frame_index; |
| ... | @@ -2266,7 +2275,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !FrameIndex { | ... | @@ -2266,7 +2275,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !FrameIndex { |
| 2266 | .size = math.cast(u32, val_ty.abiSize(mod)) orelse { | 2275 | .size = math.cast(u32, val_ty.abiSize(mod)) orelse { |
| 2267 | return self.fail("type '{}' too big to fit into stack frame", .{val_ty.fmt(mod)}); | 2276 | return self.fail("type '{}' too big to fit into stack frame", .{val_ty.fmt(mod)}); |
| 2268 | }, | 2277 | }, |
| 2269 | .alignment = @max(ptr_ty.ptrAlignment(mod), 1), | 2278 | .alignment = ptr_ty.ptrAlignment(mod).max(.@"1"), |
| 2270 | })); | 2279 | })); |
| 2271 | } | 2280 | } |
| 2272 | 2281 | ||
| ... | @@ -4266,7 +4275,7 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4266,7 +4275,7 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 4266 | }; | 4275 | }; |
| 4267 | defer if (tag_lock) |lock| self.register_manager.unlockReg(lock); | 4276 | defer if (tag_lock) |lock| self.register_manager.unlockReg(lock); |
| 4268 | 4277 | ||
| 4269 | const adjusted_ptr: MCValue = if (layout.payload_size > 0 and layout.tag_align < layout.payload_align) blk: { | 4278 | const adjusted_ptr: MCValue = if (layout.payload_size > 0 and layout.tag_align.compare(.lt, layout.payload_align)) blk: { |
| 4270 | // TODO reusing the operand | 4279 | // TODO reusing the operand |
| 4271 | const reg = try self.copyToTmpRegister(ptr_union_ty, ptr); | 4280 | const reg = try self.copyToTmpRegister(ptr_union_ty, ptr); |
| 4272 | try self.genBinOpMir( | 4281 | try self.genBinOpMir( |
| ... | @@ -4309,7 +4318,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4309,7 +4318,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 4309 | switch (operand) { | 4318 | switch (operand) { |
| 4310 | .load_frame => |frame_addr| { | 4319 | .load_frame => |frame_addr| { |
| 4311 | if (tag_abi_size <= 8) { | 4320 | if (tag_abi_size <= 8) { |
| 4312 | const off: i32 = if (layout.tag_align < layout.payload_align) | 4321 | const off: i32 = if (layout.tag_align.compare(.lt, layout.payload_align)) |
| 4313 | @intCast(layout.payload_size) | 4322 | @intCast(layout.payload_size) |
| 4314 | else | 4323 | else |
| 4315 | 0; | 4324 | 0; |
| ... | @@ -4321,7 +4330,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4321,7 +4330,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 4321 | return self.fail("TODO implement get_union_tag for ABI larger than 8 bytes and operand {}", .{operand}); | 4330 | return self.fail("TODO implement get_union_tag for ABI larger than 8 bytes and operand {}", .{operand}); |
| 4322 | }, | 4331 | }, |
| 4323 | .register => { | 4332 | .register => { |
| 4324 | const shift: u6 = if (layout.tag_align < layout.payload_align) | 4333 | const shift: u6 = if (layout.tag_align.compare(.lt, layout.payload_align)) |
| 4325 | @intCast(layout.payload_size * 8) | 4334 | @intCast(layout.payload_size * 8) |
| 4326 | else | 4335 | else |
| 4327 | 0; | 4336 | 0; |
| ... | @@ -5600,8 +5609,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5600,8 +5609,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 5600 | const src_mcv = try self.resolveInst(operand); | 5609 | const src_mcv = try self.resolveInst(operand); |
| 5601 | const field_off: u32 = switch (container_ty.containerLayout(mod)) { | 5610 | const field_off: u32 = switch (container_ty.containerLayout(mod)) { |
| 5602 | .Auto, .Extern => @intCast(container_ty.structFieldOffset(index, mod) * 8), | 5611 | .Auto, .Extern => @intCast(container_ty.structFieldOffset(index, mod) * 8), |
| 5603 | .Packed => if (mod.typeToStruct(container_ty)) |struct_obj| | 5612 | .Packed => if (mod.typeToStruct(container_ty)) |struct_type| |
| 5604 | struct_obj.packedFieldBitOffset(mod, index) | 5613 | mod.structPackedFieldBitOffset(struct_type, index) |
| 5605 | else | 5614 | else |
| 5606 | 0, | 5615 | 0, |
| 5607 | }; | 5616 | }; |
| ... | @@ -8084,14 +8093,17 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -8084,14 +8093,17 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 8084 | // We need a properly aligned and sized call frame to be able to call this function. | 8093 | // We need a properly aligned and sized call frame to be able to call this function. |
| 8085 | { | 8094 | { |
| 8086 | const needed_call_frame = | 8095 | const needed_call_frame = |
| 8087 | FrameAlloc.init(.{ .size = info.stack_byte_count, .alignment = info.stack_align }); | 8096 | FrameAlloc.init(.{ |
| 8097 | .size = info.stack_byte_count, | ||
| 8098 | .alignment = info.stack_align, | ||
| 8099 | }); | ||
| 8088 | const frame_allocs_slice = self.frame_allocs.slice(); | 8100 | const frame_allocs_slice = self.frame_allocs.slice(); |
| 8089 | const stack_frame_size = | 8101 | const stack_frame_size = |
| 8090 | &frame_allocs_slice.items(.abi_size)[@intFromEnum(FrameIndex.call_frame)]; | 8102 | &frame_allocs_slice.items(.abi_size)[@intFromEnum(FrameIndex.call_frame)]; |
| 8091 | stack_frame_size.* = @max(stack_frame_size.*, needed_call_frame.abi_size); | 8103 | stack_frame_size.* = @max(stack_frame_size.*, needed_call_frame.abi_size); |
| 8092 | const stack_frame_align = | 8104 | const stack_frame_align = |
| 8093 | &frame_allocs_slice.items(.abi_align)[@intFromEnum(FrameIndex.call_frame)]; | 8105 | &frame_allocs_slice.items(.abi_align)[@intFromEnum(FrameIndex.call_frame)]; |
| 8094 | stack_frame_align.* = @max(stack_frame_align.*, needed_call_frame.abi_align); | 8106 | stack_frame_align.* = stack_frame_align.max(needed_call_frame.abi_align); |
| 8095 | } | 8107 | } |
| 8096 | 8108 | ||
| 8097 | try self.spillEflagsIfOccupied(); | 8109 | try self.spillEflagsIfOccupied(); |
| ... | @@ -9944,7 +9956,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -9944,7 +9956,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 9944 | .indirect => try self.moveStrategy(ty, false), | 9956 | .indirect => try self.moveStrategy(ty, false), |
| 9945 | .load_frame => |frame_addr| try self.moveStrategy( | 9957 | .load_frame => |frame_addr| try self.moveStrategy( |
| 9946 | ty, | 9958 | ty, |
| 9947 | self.getFrameAddrAlignment(frame_addr) >= ty.abiAlignment(mod), | 9959 | self.getFrameAddrAlignment(frame_addr).compare(.gte, ty.abiAlignment(mod)), |
| 9948 | ), | 9960 | ), |
| 9949 | .lea_frame => .{ .move = .{ ._, .lea } }, | 9961 | .lea_frame => .{ .move = .{ ._, .lea } }, |
| 9950 | else => unreachable, | 9962 | else => unreachable, |
| ... | @@ -9973,10 +9985,8 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -9973,10 +9985,8 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 9973 | .base = .{ .reg = .ds }, | 9985 | .base = .{ .reg = .ds }, |
| 9974 | .disp = small_addr, | 9986 | .disp = small_addr, |
| 9975 | }); | 9987 | }); |
| 9976 | switch (try self.moveStrategy(ty, mem.isAlignedGeneric( | 9988 | switch (try self.moveStrategy(ty, ty.abiAlignment(mod).check( |
| 9977 | u32, | ||
| 9978 | @as(u32, @bitCast(small_addr)), | 9989 | @as(u32, @bitCast(small_addr)), |
| 9979 | ty.abiAlignment(mod), | ||
| 9980 | ))) { | 9990 | ))) { |
| 9981 | .move => |tag| try self.asmRegisterMemory(tag, dst_alias, src_mem), | 9991 | .move => |tag| try self.asmRegisterMemory(tag, dst_alias, src_mem), |
| 9982 | .insert_extract => |ie| try self.asmRegisterMemoryImmediate( | 9992 | .insert_extract => |ie| try self.asmRegisterMemoryImmediate( |
| ... | @@ -10142,22 +10152,14 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal | ... | @@ -10142,22 +10152,14 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal |
| 10142 | ); | 10152 | ); |
| 10143 | const src_alias = registerAlias(src_reg, abi_size); | 10153 | const src_alias = registerAlias(src_reg, abi_size); |
| 10144 | switch (try self.moveStrategy(ty, switch (base) { | 10154 | switch (try self.moveStrategy(ty, switch (base) { |
| 10145 | .none => mem.isAlignedGeneric( | 10155 | .none => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))), |
| 10146 | u32, | ||
| 10147 | @as(u32, @bitCast(disp)), | ||
| 10148 | ty.abiAlignment(mod), | ||
| 10149 | ), | ||
| 10150 | .reg => |reg| switch (reg) { | 10156 | .reg => |reg| switch (reg) { |
| 10151 | .es, .cs, .ss, .ds => mem.isAlignedGeneric( | 10157 | .es, .cs, .ss, .ds => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))), |
| 10152 | u32, | ||
| 10153 | @as(u32, @bitCast(disp)), | ||
| 10154 | ty.abiAlignment(mod), | ||
| 10155 | ), | ||
| 10156 | else => false, | 10158 | else => false, |
| 10157 | }, | 10159 | }, |
| 10158 | .frame => |frame_index| self.getFrameAddrAlignment( | 10160 | .frame => |frame_index| self.getFrameAddrAlignment( |
| 10159 | .{ .index = frame_index, .off = disp }, | 10161 | .{ .index = frame_index, .off = disp }, |
| 10160 | ) >= ty.abiAlignment(mod), | 10162 | ).compare(.gte, ty.abiAlignment(mod)), |
| 10161 | })) { | 10163 | })) { |
| 10162 | .move => |tag| try self.asmMemoryRegister(tag, dst_mem, src_alias), | 10164 | .move => |tag| try self.asmMemoryRegister(tag, dst_mem, src_alias), |
| 10163 | .insert_extract, .vex_insert_extract => |ie| try self.asmMemoryRegisterImmediate( | 10165 | .insert_extract, .vex_insert_extract => |ie| try self.asmMemoryRegisterImmediate( |
| ... | @@ -11079,7 +11081,7 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -11079,7 +11081,7 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { |
| 11079 | stack_frame_size.* = @max(stack_frame_size.*, needed_call_frame.abi_size); | 11081 | stack_frame_size.* = @max(stack_frame_size.*, needed_call_frame.abi_size); |
| 11080 | const stack_frame_align = | 11082 | const stack_frame_align = |
| 11081 | &frame_allocs_slice.items(.abi_align)[@intFromEnum(FrameIndex.call_frame)]; | 11083 | &frame_allocs_slice.items(.abi_align)[@intFromEnum(FrameIndex.call_frame)]; |
| 11082 | stack_frame_align.* = @max(stack_frame_align.*, needed_call_frame.abi_align); | 11084 | stack_frame_align.* = stack_frame_align.max(needed_call_frame.abi_align); |
| 11083 | } | 11085 | } |
| 11084 | 11086 | ||
| 11085 | try self.spillEflagsIfOccupied(); | 11087 | try self.spillEflagsIfOccupied(); |
| ... | @@ -11418,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; |
| 11429 | 11432 | ||
| 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 | else | 11584 | 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 }); |
| 11584 | 11587 | ||
| 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 | 0 | 11589 | 0 |
| 11587 | else | 11590 | 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, |
| 11827 | 11830 | ||
| 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"; |
| 11876 | 11879 | ||
| 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 | } |
| 11958 | 11961 | ||
| 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"; |
| 11972 | 11975 | ||
| 11973 | // Return values | 11976 | // 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 | } |
| 12012 | 12015 | ||
| 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 | } |
| 12016 | 12019 |
src/arch/x86_64/abi.zig+14-24| ... | @@ -210,8 +210,9 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class { | ... | @@ -210,8 +210,9 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class { |
| 210 | // it contains unaligned fields, it has class MEMORY" | 210 | // it contains unaligned fields, it has class MEMORY" |
| 211 | // "If the size of the aggregate exceeds a single eightbyte, each is classified | 211 | // "If the size of the aggregate exceeds a single eightbyte, each is classified |
| 212 | // separately.". | 212 | // separately.". |
| 213 | const struct_type = mod.typeToStruct(ty).?; | ||
| 213 | const ty_size = ty.abiSize(mod); | 214 | const ty_size = ty.abiSize(mod); |
| 214 | if (ty.containerLayout(mod) == .Packed) { | 215 | if (struct_type.layout == .Packed) { |
| 215 | assert(ty_size <= 128); | 216 | assert(ty_size <= 128); |
| 216 | result[0] = .integer; | 217 | result[0] = .integer; |
| 217 | if (ty_size > 64) result[1] = .integer; | 218 | if (ty_size > 64) result[1] = .integer; |
| ... | @@ -222,15 +223,13 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class { | ... | @@ -222,15 +223,13 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class { |
| 222 | 223 | ||
| 223 | var result_i: usize = 0; // out of 8 | 224 | var result_i: usize = 0; // out of 8 |
| 224 | var byte_i: usize = 0; // out of 8 | 225 | var byte_i: usize = 0; // out of 8 |
| 225 | const fields = ty.structFields(mod); | 226 | for (struct_type.field_types.get(ip), 0..) |field_ty_ip, i| { |
| 226 | for (fields.values()) |field| { | 227 | const field_ty = field_ty_ip.toType(); |
| 227 | if (field.abi_align != .none) { | 228 | const field_align = struct_type.fieldAlign(ip, i); |
| 228 | if (field.abi_align.toByteUnitsOptional().? < field.ty.abiAlignment(mod)) { | 229 | if (field_align != .none and field_align.compare(.lt, field_ty.abiAlignment(mod))) |
| 229 | return memory_class; | 230 | return memory_class; |
| 230 | } | 231 | const field_size = field_ty.abiSize(mod); |
| 231 | } | 232 | const field_class_array = classifySystemV(field_ty, mod, .other); |
| 232 | const field_size = field.ty.abiSize(mod); | ||
| 233 | const field_class_array = classifySystemV(field.ty, mod, .other); | ||
| 234 | const field_class = std.mem.sliceTo(&field_class_array, .none); | 233 | const field_class = std.mem.sliceTo(&field_class_array, .none); |
| 235 | if (byte_i + field_size <= 8) { | 234 | if (byte_i + field_size <= 8) { |
| 236 | // Combine this field with the previous one. | 235 | // Combine this field with the previous one. |
| ... | @@ -341,10 +340,11 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class { | ... | @@ -341,10 +340,11 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class { |
| 341 | return memory_class; | 340 | return memory_class; |
| 342 | 341 | ||
| 343 | for (union_obj.field_types.get(ip), 0..) |field_ty, field_index| { | 342 | for (union_obj.field_types.get(ip), 0..) |field_ty, field_index| { |
| 344 | if (union_obj.fieldAlign(ip, @intCast(field_index)).toByteUnitsOptional()) |a| { | 343 | const field_align = union_obj.fieldAlign(ip, @intCast(field_index)); |
| 345 | if (a < field_ty.toType().abiAlignment(mod)) { | 344 | if (field_align != .none and |
| 346 | return memory_class; | 345 | field_align.compare(.lt, field_ty.toType().abiAlignment(mod))) |
| 347 | } | 346 | { |
| 347 | return memory_class; | ||
| 348 | } | 348 | } |
| 349 | // Combine this field with the previous one. | 349 | // Combine this field with the previous one. |
| 350 | const field_class = classifySystemV(field_ty.toType(), mod, .other); | 350 | const field_class = classifySystemV(field_ty.toType(), mod, .other); |
| ... | @@ -533,13 +533,3 @@ const Register = @import("bits.zig").Register; | ... | @@ -533,13 +533,3 @@ const Register = @import("bits.zig").Register; |
| 533 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; | 533 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; |
| 534 | const Type = @import("../../type.zig").Type; | 534 | const Type = @import("../../type.zig").Type; |
| 535 | const Value = @import("../../value.zig").Value; | 535 | const Value = @import("../../value.zig").Value; |
| 536 | |||
| 537 | fn _field(comptime tag: Type.Tag, offset: u32) Module.Struct.Field { | ||
| 538 | return .{ | ||
| 539 | .ty = Type.initTag(tag), | ||
| 540 | .default_val = Value.initTag(.unreachable_value), | ||
| 541 | .abi_align = 0, | ||
| 542 | .offset = offset, | ||
| 543 | .is_comptime = false, | ||
| 544 | }; | ||
| 545 | } |
src/codegen.zig+54-47| ... | @@ -22,6 +22,7 @@ const Type = @import("type.zig").Type; | ... | @@ -22,6 +22,7 @@ const Type = @import("type.zig").Type; |
| 22 | const TypedValue = @import("TypedValue.zig"); | 22 | const TypedValue = @import("TypedValue.zig"); |
| 23 | const Value = @import("value.zig").Value; | 23 | const Value = @import("value.zig").Value; |
| 24 | const Zir = @import("Zir.zig"); | 24 | const Zir = @import("Zir.zig"); |
| 25 | const Alignment = InternPool.Alignment; | ||
| 25 | 26 | ||
| 26 | pub const Result = union(enum) { | 27 | pub const Result = union(enum) { |
| 27 | /// The `code` parameter passed to `generateSymbol` has the value ok. | 28 | /// The `code` parameter passed to `generateSymbol` has the value ok. |
| ... | @@ -116,7 +117,8 @@ pub fn generateLazySymbol( | ... | @@ -116,7 +117,8 @@ pub fn generateLazySymbol( |
| 116 | bin_file: *link.File, | 117 | bin_file: *link.File, |
| 117 | src_loc: Module.SrcLoc, | 118 | src_loc: Module.SrcLoc, |
| 118 | lazy_sym: link.File.LazySymbol, | 119 | lazy_sym: link.File.LazySymbol, |
| 119 | alignment: *u32, | 120 | // TODO don't use an "out" parameter like this; put it in the result instead |
| 121 | alignment: *Alignment, | ||
| 120 | code: *std.ArrayList(u8), | 122 | code: *std.ArrayList(u8), |
| 121 | debug_output: DebugInfoOutput, | 123 | debug_output: DebugInfoOutput, |
| 122 | reloc_info: RelocInfo, | 124 | reloc_info: RelocInfo, |
| ... | @@ -141,7 +143,7 @@ pub fn generateLazySymbol( | ... | @@ -141,7 +143,7 @@ pub fn generateLazySymbol( |
| 141 | } | 143 | } |
| 142 | 144 | ||
| 143 | if (lazy_sym.ty.isAnyError(mod)) { | 145 | if (lazy_sym.ty.isAnyError(mod)) { |
| 144 | alignment.* = 4; | 146 | alignment.* = .@"4"; |
| 145 | const err_names = mod.global_error_set.keys(); | 147 | const err_names = mod.global_error_set.keys(); |
| 146 | mem.writeInt(u32, try code.addManyAsArray(4), @as(u32, @intCast(err_names.len)), endian); | 148 | mem.writeInt(u32, try code.addManyAsArray(4), @as(u32, @intCast(err_names.len)), endian); |
| 147 | var offset = code.items.len; | 149 | var offset = code.items.len; |
| ... | @@ -157,7 +159,7 @@ pub fn generateLazySymbol( | ... | @@ -157,7 +159,7 @@ pub fn generateLazySymbol( |
| 157 | mem.writeInt(u32, code.items[offset..][0..4], @as(u32, @intCast(code.items.len)), endian); | 159 | mem.writeInt(u32, code.items[offset..][0..4], @as(u32, @intCast(code.items.len)), endian); |
| 158 | return Result.ok; | 160 | return Result.ok; |
| 159 | } else if (lazy_sym.ty.zigTypeTag(mod) == .Enum) { | 161 | } else if (lazy_sym.ty.zigTypeTag(mod) == .Enum) { |
| 160 | alignment.* = 1; | 162 | alignment.* = .@"1"; |
| 161 | for (lazy_sym.ty.enumFields(mod)) |tag_name_ip| { | 163 | for (lazy_sym.ty.enumFields(mod)) |tag_name_ip| { |
| 162 | const tag_name = mod.intern_pool.stringToSlice(tag_name_ip); | 164 | const tag_name = mod.intern_pool.stringToSlice(tag_name_ip); |
| 163 | try code.ensureUnusedCapacity(tag_name.len + 1); | 165 | try code.ensureUnusedCapacity(tag_name.len + 1); |
| ... | @@ -273,7 +275,7 @@ pub fn generateSymbol( | ... | @@ -273,7 +275,7 @@ pub fn generateSymbol( |
| 273 | const abi_align = typed_value.ty.abiAlignment(mod); | 275 | const abi_align = typed_value.ty.abiAlignment(mod); |
| 274 | 276 | ||
| 275 | // error value first when its type is larger than the error union's payload | 277 | // error value first when its type is larger than the error union's payload |
| 276 | if (error_align > payload_align) { | 278 | if (error_align.order(payload_align) == .gt) { |
| 277 | try code.writer().writeInt(u16, err_val, endian); | 279 | try code.writer().writeInt(u16, err_val, endian); |
| 278 | } | 280 | } |
| 279 | 281 | ||
| ... | @@ -291,7 +293,7 @@ pub fn generateSymbol( | ... | @@ -291,7 +293,7 @@ pub fn generateSymbol( |
| 291 | .fail => |em| return .{ .fail = em }, | 293 | .fail => |em| return .{ .fail = em }, |
| 292 | } | 294 | } |
| 293 | const unpadded_end = code.items.len - begin; | 295 | const unpadded_end = code.items.len - begin; |
| 294 | const padded_end = mem.alignForward(u64, unpadded_end, abi_align); | 296 | const padded_end = abi_align.forward(unpadded_end); |
| 295 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; | 297 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; |
| 296 | 298 | ||
| 297 | if (padding > 0) { | 299 | if (padding > 0) { |
| ... | @@ -300,11 +302,11 @@ pub fn generateSymbol( | ... | @@ -300,11 +302,11 @@ pub fn generateSymbol( |
| 300 | } | 302 | } |
| 301 | 303 | ||
| 302 | // Payload size is larger than error set, so emit our error set last | 304 | // Payload size is larger than error set, so emit our error set last |
| 303 | if (error_align <= payload_align) { | 305 | if (error_align.compare(.lte, payload_align)) { |
| 304 | const begin = code.items.len; | 306 | const begin = code.items.len; |
| 305 | try code.writer().writeInt(u16, err_val, endian); | 307 | try code.writer().writeInt(u16, err_val, endian); |
| 306 | const unpadded_end = code.items.len - begin; | 308 | const unpadded_end = code.items.len - begin; |
| 307 | const padded_end = mem.alignForward(u64, unpadded_end, abi_align); | 309 | const padded_end = abi_align.forward(unpadded_end); |
| 308 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; | 310 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; |
| 309 | 311 | ||
| 310 | if (padding > 0) { | 312 | if (padding > 0) { |
| ... | @@ -474,23 +476,18 @@ pub fn generateSymbol( | ... | @@ -474,23 +476,18 @@ pub fn generateSymbol( |
| 474 | } | 476 | } |
| 475 | } | 477 | } |
| 476 | }, | 478 | }, |
| 477 | .struct_type => |struct_type| { | 479 | .struct_type => |struct_type| switch (struct_type.layout) { |
| 478 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | 480 | .Packed => { |
| 479 | |||
| 480 | if (struct_obj.layout == .Packed) { | ||
| 481 | const fields = struct_obj.fields.values(); | ||
| 482 | const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse | 481 | const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse |
| 483 | return error.Overflow; | 482 | return error.Overflow; |
| 484 | const current_pos = code.items.len; | 483 | const current_pos = code.items.len; |
| 485 | try code.resize(current_pos + abi_size); | 484 | try code.resize(current_pos + abi_size); |
| 486 | var bits: u16 = 0; | 485 | var bits: u16 = 0; |
| 487 | 486 | ||
| 488 | for (fields, 0..) |field, index| { | 487 | for (struct_type.field_types.get(ip), 0..) |field_ty, index| { |
| 489 | const field_ty = field.ty; | ||
| 490 | |||
| 491 | const field_val = switch (aggregate.storage) { | 488 | const field_val = switch (aggregate.storage) { |
| 492 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ | 489 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ |
| 493 | .ty = field_ty.toIntern(), | 490 | .ty = field_ty, |
| 494 | .storage = .{ .u64 = bytes[index] }, | 491 | .storage = .{ .u64 = bytes[index] }, |
| 495 | } }), | 492 | } }), |
| 496 | .elems => |elems| elems[index], | 493 | .elems => |elems| elems[index], |
| ... | @@ -499,48 +496,51 @@ pub fn generateSymbol( | ... | @@ -499,48 +496,51 @@ pub fn generateSymbol( |
| 499 | 496 | ||
| 500 | // pointer may point to a decl which must be marked used | 497 | // pointer may point to a decl which must be marked used |
| 501 | // but can also result in a relocation. Therefore we handle those separately. | 498 | // but can also result in a relocation. Therefore we handle those separately. |
| 502 | if (field_ty.zigTypeTag(mod) == .Pointer) { | 499 | if (field_ty.toType().zigTypeTag(mod) == .Pointer) { |
| 503 | const field_size = math.cast(usize, field_ty.abiSize(mod)) orelse | 500 | const field_size = math.cast(usize, field_ty.toType().abiSize(mod)) orelse |
| 504 | return error.Overflow; | 501 | return error.Overflow; |
| 505 | var tmp_list = try std.ArrayList(u8).initCapacity(code.allocator, field_size); | 502 | var tmp_list = try std.ArrayList(u8).initCapacity(code.allocator, field_size); |
| 506 | defer tmp_list.deinit(); | 503 | defer tmp_list.deinit(); |
| 507 | switch (try generateSymbol(bin_file, src_loc, .{ | 504 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 508 | .ty = field_ty, | 505 | .ty = field_ty.toType(), |
| 509 | .val = field_val.toValue(), | 506 | .val = field_val.toValue(), |
| 510 | }, &tmp_list, debug_output, reloc_info)) { | 507 | }, &tmp_list, debug_output, reloc_info)) { |
| 511 | .ok => @memcpy(code.items[current_pos..][0..tmp_list.items.len], tmp_list.items), | 508 | .ok => @memcpy(code.items[current_pos..][0..tmp_list.items.len], tmp_list.items), |
| 512 | .fail => |em| return Result{ .fail = em }, | 509 | .fail => |em| return Result{ .fail = em }, |
| 513 | } | 510 | } |
| 514 | } else { | 511 | } else { |
| 515 | field_val.toValue().writeToPackedMemory(field_ty, mod, code.items[current_pos..], bits) catch unreachable; | 512 | field_val.toValue().writeToPackedMemory(field_ty.toType(), mod, code.items[current_pos..], bits) catch unreachable; |
| 516 | } | 513 | } |
| 517 | bits += @as(u16, @intCast(field_ty.bitSize(mod))); | 514 | bits += @as(u16, @intCast(field_ty.toType().bitSize(mod))); |
| 518 | } | 515 | } |
| 519 | } else { | 516 | }, |
| 517 | .Auto, .Extern => { | ||
| 520 | const struct_begin = code.items.len; | 518 | const struct_begin = code.items.len; |
| 521 | const fields = struct_obj.fields.values(); | 519 | const field_types = struct_type.field_types.get(ip); |
| 522 | 520 | const offsets = struct_type.offsets.get(ip); | |
| 523 | var it = typed_value.ty.iterateStructOffsets(mod); | ||
| 524 | 521 | ||
| 525 | while (it.next()) |field_offset| { | 522 | var it = struct_type.iterateRuntimeOrder(ip); |
| 526 | const field_ty = fields[field_offset.field].ty; | 523 | while (it.next()) |field_index| { |
| 527 | 524 | const field_ty = field_types[field_index]; | |
| 528 | if (!field_ty.hasRuntimeBits(mod)) continue; | 525 | if (!field_ty.toType().hasRuntimeBits(mod)) continue; |
| 529 | 526 | ||
| 530 | const field_val = switch (ip.indexToKey(typed_value.val.toIntern()).aggregate.storage) { | 527 | const field_val = switch (ip.indexToKey(typed_value.val.toIntern()).aggregate.storage) { |
| 531 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ | 528 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ |
| 532 | .ty = field_ty.toIntern(), | 529 | .ty = field_ty, |
| 533 | .storage = .{ .u64 = bytes[field_offset.field] }, | 530 | .storage = .{ .u64 = bytes[field_index] }, |
| 534 | } }), | 531 | } }), |
| 535 | .elems => |elems| elems[field_offset.field], | 532 | .elems => |elems| elems[field_index], |
| 536 | .repeated_elem => |elem| elem, | 533 | .repeated_elem => |elem| elem, |
| 537 | }; | 534 | }; |
| 538 | 535 | ||
| 539 | const padding = math.cast(usize, field_offset.offset - (code.items.len - struct_begin)) orelse return error.Overflow; | 536 | const padding = math.cast( |
| 537 | usize, | ||
| 538 | offsets[field_index] - (code.items.len - struct_begin), | ||
| 539 | ) orelse return error.Overflow; | ||
| 540 | if (padding > 0) try code.appendNTimes(0, padding); | 540 | if (padding > 0) try code.appendNTimes(0, padding); |
| 541 | 541 | ||
| 542 | switch (try generateSymbol(bin_file, src_loc, .{ | 542 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 543 | .ty = field_ty, | 543 | .ty = field_ty.toType(), |
| 544 | .val = field_val.toValue(), | 544 | .val = field_val.toValue(), |
| 545 | }, code, debug_output, reloc_info)) { | 545 | }, code, debug_output, reloc_info)) { |
| 546 | .ok => {}, | 546 | .ok => {}, |
| ... | @@ -548,9 +548,16 @@ pub fn generateSymbol( | ... | @@ -548,9 +548,16 @@ pub fn generateSymbol( |
| 548 | } | 548 | } |
| 549 | } | 549 | } |
| 550 | 550 | ||
| 551 | const padding = math.cast(usize, std.mem.alignForward(u64, it.offset, @max(it.big_align, 1)) - (code.items.len - struct_begin)) orelse return error.Overflow; | 551 | const size = struct_type.size(ip).*; |
| 552 | const alignment = struct_type.flagsPtr(ip).alignment.toByteUnitsOptional().?; | ||
| 553 | |||
| 554 | const padding = math.cast( | ||
| 555 | usize, | ||
| 556 | std.mem.alignForward(u64, size, @max(alignment, 1)) - | ||
| 557 | (code.items.len - struct_begin), | ||
| 558 | ) orelse return error.Overflow; | ||
| 552 | if (padding > 0) try code.appendNTimes(0, padding); | 559 | if (padding > 0) try code.appendNTimes(0, padding); |
| 553 | } | 560 | }, |
| 554 | }, | 561 | }, |
| 555 | else => unreachable, | 562 | else => unreachable, |
| 556 | }, | 563 | }, |
| ... | @@ -565,7 +572,7 @@ pub fn generateSymbol( | ... | @@ -565,7 +572,7 @@ pub fn generateSymbol( |
| 565 | } | 572 | } |
| 566 | 573 | ||
| 567 | // Check if we should store the tag first. | 574 | // Check if we should store the tag first. |
| 568 | if (layout.tag_size > 0 and layout.tag_align >= layout.payload_align) { | 575 | if (layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align)) { |
| 569 | switch (try generateSymbol(bin_file, src_loc, .{ | 576 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 570 | .ty = typed_value.ty.unionTagType(mod).?, | 577 | .ty = typed_value.ty.unionTagType(mod).?, |
| 571 | .val = un.tag.toValue(), | 578 | .val = un.tag.toValue(), |
| ... | @@ -595,7 +602,7 @@ pub fn generateSymbol( | ... | @@ -595,7 +602,7 @@ pub fn generateSymbol( |
| 595 | } | 602 | } |
| 596 | } | 603 | } |
| 597 | 604 | ||
| 598 | if (layout.tag_size > 0 and layout.tag_align < layout.payload_align) { | 605 | if (layout.tag_size > 0 and layout.tag_align.compare(.lt, layout.payload_align)) { |
| 599 | switch (try generateSymbol(bin_file, src_loc, .{ | 606 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 600 | .ty = union_obj.enum_tag_ty.toType(), | 607 | .ty = union_obj.enum_tag_ty.toType(), |
| 601 | .val = un.tag.toValue(), | 608 | .val = un.tag.toValue(), |
| ... | @@ -695,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 | } |
| 855 | 862 | ||
| ... | @@ -1036,10 +1043,10 @@ pub fn errUnionPayloadOffset(payload_ty: Type, mod: *Module) u64 { | ... | @@ -1036,10 +1043,10 @@ pub fn errUnionPayloadOffset(payload_ty: Type, mod: *Module) u64 { |
| 1036 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return 0; | 1043 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return 0; |
| 1037 | const payload_align = payload_ty.abiAlignment(mod); | 1044 | const payload_align = payload_ty.abiAlignment(mod); |
| 1038 | const error_align = Type.anyerror.abiAlignment(mod); | 1045 | const error_align = Type.anyerror.abiAlignment(mod); |
| 1039 | if (payload_align >= error_align or !payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | 1046 | if (payload_align.compare(.gte, error_align) or !payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 1040 | return 0; | 1047 | return 0; |
| 1041 | } else { | 1048 | } else { |
| 1042 | return mem.alignForward(u64, Type.anyerror.abiSize(mod), payload_align); | 1049 | return payload_align.forward(Type.anyerror.abiSize(mod)); |
| 1043 | } | 1050 | } |
| 1044 | } | 1051 | } |
| 1045 | 1052 | ||
| ... | @@ -1047,8 +1054,8 @@ pub fn errUnionErrorOffset(payload_ty: Type, mod: *Module) u64 { | ... | @@ -1047,8 +1054,8 @@ pub fn errUnionErrorOffset(payload_ty: Type, mod: *Module) u64 { |
| 1047 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return 0; | 1054 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return 0; |
| 1048 | const payload_align = payload_ty.abiAlignment(mod); | 1055 | const payload_align = payload_ty.abiAlignment(mod); |
| 1049 | const error_align = Type.anyerror.abiAlignment(mod); | 1056 | const error_align = Type.anyerror.abiAlignment(mod); |
| 1050 | if (payload_align >= error_align and payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | 1057 | if (payload_align.compare(.gte, error_align) and payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 1051 | return mem.alignForward(u64, payload_ty.abiSize(mod), error_align); | 1058 | return error_align.forward(payload_ty.abiSize(mod)); |
| 1052 | } else { | 1059 | } else { |
| 1053 | return 0; | 1060 | return 0; |
| 1054 | } | 1061 | } |
src/codegen/c.zig+138-140| ... | @@ -17,6 +17,7 @@ const LazySrcLoc = Module.LazySrcLoc; | ... | @@ -17,6 +17,7 @@ const LazySrcLoc = Module.LazySrcLoc; |
| 17 | const Air = @import("../Air.zig"); | 17 | const Air = @import("../Air.zig"); |
| 18 | const Liveness = @import("../Liveness.zig"); | 18 | const Liveness = @import("../Liveness.zig"); |
| 19 | const InternPool = @import("../InternPool.zig"); | 19 | const InternPool = @import("../InternPool.zig"); |
| 20 | const Alignment = InternPool.Alignment; | ||
| 20 | 21 | ||
| 21 | const BigIntLimb = std.math.big.Limb; | 22 | const BigIntLimb = std.math.big.Limb; |
| 22 | const BigInt = std.math.big.int; | 23 | const BigInt = std.math.big.int; |
| ... | @@ -292,7 +293,7 @@ pub const Function = struct { | ... | @@ -292,7 +293,7 @@ pub const Function = struct { |
| 292 | 293 | ||
| 293 | const result: CValue = if (lowersToArray(ty, mod)) result: { | 294 | const result: CValue = if (lowersToArray(ty, mod)) result: { |
| 294 | const writer = f.object.code_header.writer(); | 295 | const writer = f.object.code_header.writer(); |
| 295 | const alignment = 0; | 296 | const alignment: Alignment = .none; |
| 296 | const decl_c_value = try f.allocLocalValue(ty, alignment); | 297 | const decl_c_value = try f.allocLocalValue(ty, alignment); |
| 297 | const gpa = f.object.dg.gpa; | 298 | const gpa = f.object.dg.gpa; |
| 298 | try f.allocs.put(gpa, decl_c_value.new_local, false); | 299 | try f.allocs.put(gpa, decl_c_value.new_local, false); |
| ... | @@ -318,25 +319,25 @@ pub const Function = struct { | ... | @@ -318,25 +319,25 @@ pub const Function = struct { |
| 318 | /// Skips the reuse logic. This function should be used for any persistent allocation, i.e. | 319 | /// Skips the reuse logic. This function should be used for any persistent allocation, i.e. |
| 319 | /// those which go into `allocs`. This function does not add the resulting local into `allocs`; | 320 | /// those which go into `allocs`. This function does not add the resulting local into `allocs`; |
| 320 | /// that responsibility lies with the caller. | 321 | /// that responsibility lies with the caller. |
| 321 | fn allocLocalValue(f: *Function, ty: Type, alignment: u32) !CValue { | 322 | fn allocLocalValue(f: *Function, ty: Type, alignment: Alignment) !CValue { |
| 322 | const mod = f.object.dg.module; | 323 | const mod = f.object.dg.module; |
| 323 | const gpa = f.object.dg.gpa; | 324 | const gpa = f.object.dg.gpa; |
| 324 | try f.locals.append(gpa, .{ | 325 | try f.locals.append(gpa, .{ |
| 325 | .cty_idx = try f.typeToIndex(ty, .complete), | 326 | .cty_idx = try f.typeToIndex(ty, .complete), |
| 326 | .alignas = CType.AlignAs.init(alignment, ty.abiAlignment(mod)), | 327 | .alignas = CType.AlignAs.init(alignment, ty.abiAlignment(mod)), |
| 327 | }); | 328 | }); |
| 328 | return .{ .new_local = @as(LocalIndex, @intCast(f.locals.items.len - 1)) }; | 329 | return .{ .new_local = @intCast(f.locals.items.len - 1) }; |
| 329 | } | 330 | } |
| 330 | 331 | ||
| 331 | fn allocLocal(f: *Function, inst: Air.Inst.Index, ty: Type) !CValue { | 332 | fn allocLocal(f: *Function, inst: Air.Inst.Index, ty: Type) !CValue { |
| 332 | const result = try f.allocAlignedLocal(ty, .{}, 0); | 333 | const result = try f.allocAlignedLocal(ty, .{}, .none); |
| 333 | log.debug("%{d}: allocating t{d}", .{ inst, result.new_local }); | 334 | log.debug("%{d}: allocating t{d}", .{ inst, result.new_local }); |
| 334 | return result; | 335 | return result; |
| 335 | } | 336 | } |
| 336 | 337 | ||
| 337 | /// Only allocates the local; does not print anything. Will attempt to re-use locals, so should | 338 | /// Only allocates the local; does not print anything. Will attempt to re-use locals, so should |
| 338 | /// not be used for persistent locals (i.e. those in `allocs`). | 339 | /// not be used for persistent locals (i.e. those in `allocs`). |
| 339 | fn allocAlignedLocal(f: *Function, ty: Type, _: CQualifiers, alignment: u32) !CValue { | 340 | fn allocAlignedLocal(f: *Function, ty: Type, _: CQualifiers, alignment: Alignment) !CValue { |
| 340 | const mod = f.object.dg.module; | 341 | const mod = f.object.dg.module; |
| 341 | if (f.free_locals_map.getPtr(.{ | 342 | if (f.free_locals_map.getPtr(.{ |
| 342 | .cty_idx = try f.typeToIndex(ty, .complete), | 343 | .cty_idx = try f.typeToIndex(ty, .complete), |
| ... | @@ -1299,139 +1300,134 @@ pub const DeclGen = struct { | ... | @@ -1299,139 +1300,134 @@ pub const DeclGen = struct { |
| 1299 | } | 1300 | } |
| 1300 | try writer.writeByte('}'); | 1301 | try writer.writeByte('}'); |
| 1301 | }, | 1302 | }, |
| 1302 | .struct_type => |struct_type| { | 1303 | .struct_type => |struct_type| switch (struct_type.layout) { |
| 1303 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | 1304 | .Auto, .Extern => { |
| 1304 | switch (struct_obj.layout) { | 1305 | if (!location.isInitializer()) { |
| 1305 | .Auto, .Extern => { | 1306 | try writer.writeByte('('); |
| 1306 | if (!location.isInitializer()) { | 1307 | try dg.renderType(writer, ty); |
| 1308 | try writer.writeByte(')'); | ||
| 1309 | } | ||
| 1310 | |||
| 1311 | try writer.writeByte('{'); | ||
| 1312 | var empty = true; | ||
| 1313 | 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 | } |
| 1311 | 1360 | ||
| 1312 | try writer.writeByte('{'); | 1361 | var eff_index: usize = 0; |
| 1313 | var empty = true; | 1362 | var needs_closing_paren = false; |
| 1314 | for (struct_obj.fields.values(), 0..) |field, field_i| { | 1363 | for (field_types, 0..) |field_ty, field_i| { |
| 1315 | if (field.is_comptime) continue; | 1364 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 1316 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | ||
| 1317 | 1365 | ||
| 1318 | if (!empty) try writer.writeByte(','); | ||
| 1319 | const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) { | 1366 | const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) { |
| 1320 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ | 1367 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ |
| 1321 | .ty = field.ty.toIntern(), | 1368 | .ty = field_ty, |
| 1322 | .storage = .{ .u64 = bytes[field_i] }, | 1369 | .storage = .{ .u64 = bytes[field_i] }, |
| 1323 | } }), | 1370 | } }), |
| 1324 | .elems => |elems| elems[field_i], | 1371 | .elems => |elems| elems[field_i], |
| 1325 | .repeated_elem => |elem| elem, | 1372 | .repeated_elem => |elem| elem, |
| 1326 | }; | 1373 | }; |
| 1327 | try dg.renderValue(writer, field.ty, field_val.toValue(), initializer_type); | 1374 | const cast_context = IntCastContext{ .value = .{ .value = field_val.toValue() } }; |
| 1328 | 1375 | if (bit_offset != 0) { | |
| 1329 | empty = false; | 1376 | try writer.writeAll("zig_shl_"); |
| 1330 | } | 1377 | try dg.renderTypeForBuiltinFnName(writer, ty); |
| 1331 | try writer.writeByte('}'); | 1378 | try writer.writeByte('('); |
| 1332 | }, | 1379 | try dg.renderIntCast(writer, ty, cast_context, field_ty.toType(), .FunctionArgument); |
| 1333 | .Packed => { | 1380 | try writer.writeAll(", "); |
| 1334 | const int_info = ty.intInfo(mod); | 1381 | const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset); |
| 1335 | 1382 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | |
| 1336 | const bits = Type.smallestUnsignedBits(int_info.bits - 1); | 1383 | try writer.writeByte(')'); |
| 1337 | const bit_offset_ty = try mod.intType(.unsigned, bits); | 1384 | } else { |
| 1338 | 1385 | try dg.renderIntCast(writer, ty, cast_context, field_ty.toType(), .FunctionArgument); | |
| 1339 | var bit_offset: u64 = 0; | 1386 | } |
| 1340 | var eff_num_fields: usize = 0; | ||
| 1341 | 1387 | ||
| 1342 | for (struct_obj.fields.values()) |field| { | 1388 | if (needs_closing_paren) try writer.writeByte(')'); |
| 1343 | if (field.is_comptime) continue; | 1389 | if (eff_index != eff_num_fields - 1) try writer.writeAll(", "); |
| 1344 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | ||
| 1345 | 1390 | ||
| 1346 | eff_num_fields += 1; | 1391 | bit_offset += field_ty.toType().bitSize(mod); |
| 1392 | needs_closing_paren = true; | ||
| 1393 | eff_index += 1; | ||
| 1347 | } | 1394 | } |
| 1395 | } else { | ||
| 1396 | try writer.writeByte('('); | ||
| 1397 | // a << a_off | b << b_off | c << c_off | ||
| 1398 | var empty = true; | ||
| 1399 | for (field_types, 0..) |field_ty, field_i| { | ||
| 1400 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; | ||
| 1348 | 1401 | ||
| 1349 | if (eff_num_fields == 0) { | 1402 | if (!empty) try writer.writeAll(" | "); |
| 1350 | try writer.writeByte('('); | 1403 | try writer.writeByte('('); |
| 1351 | try dg.renderValue(writer, ty, Value.undef, initializer_type); | 1404 | try dg.renderType(writer, ty); |
| 1352 | try writer.writeByte(')'); | 1405 | try writer.writeByte(')'); |
| 1353 | } else if (ty.bitSize(mod) > 64) { | ||
| 1354 | // zig_or_u128(zig_or_u128(zig_shl_u128(a, a_off), zig_shl_u128(b, b_off)), zig_shl_u128(c, c_off)) | ||
| 1355 | var num_or = eff_num_fields - 1; | ||
| 1356 | while (num_or > 0) : (num_or -= 1) { | ||
| 1357 | try writer.writeAll("zig_or_"); | ||
| 1358 | try dg.renderTypeForBuiltinFnName(writer, ty); | ||
| 1359 | try writer.writeByte('('); | ||
| 1360 | } | ||
| 1361 | 1406 | ||
| 1362 | var eff_index: usize = 0; | 1407 | const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) { |
| 1363 | var needs_closing_paren = false; | 1408 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ |
| 1364 | for (struct_obj.fields.values(), 0..) |field, field_i| { | 1409 | .ty = field_ty, |
| 1365 | if (field.is_comptime) continue; | 1410 | .storage = .{ .u64 = bytes[field_i] }, |
| 1366 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | 1411 | } }), |
| 1367 | 1412 | .elems => |elems| elems[field_i], | |
| 1368 | const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) { | 1413 | .repeated_elem => |elem| elem, |
| 1369 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ | 1414 | }; |
| 1370 | .ty = field.ty.toIntern(), | ||
| 1371 | .storage = .{ .u64 = bytes[field_i] }, | ||
| 1372 | } }), | ||
| 1373 | .elems => |elems| elems[field_i], | ||
| 1374 | .repeated_elem => |elem| elem, | ||
| 1375 | }; | ||
| 1376 | const cast_context = IntCastContext{ .value = .{ .value = field_val.toValue() } }; | ||
| 1377 | if (bit_offset != 0) { | ||
| 1378 | try writer.writeAll("zig_shl_"); | ||
| 1379 | try dg.renderTypeForBuiltinFnName(writer, ty); | ||
| 1380 | try writer.writeByte('('); | ||
| 1381 | try dg.renderIntCast(writer, ty, cast_context, field.ty, .FunctionArgument); | ||
| 1382 | try writer.writeAll(", "); | ||
| 1383 | const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset); | ||
| 1384 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | ||
| 1385 | try writer.writeByte(')'); | ||
| 1386 | } else { | ||
| 1387 | try dg.renderIntCast(writer, ty, cast_context, field.ty, .FunctionArgument); | ||
| 1388 | } | ||
| 1389 | |||
| 1390 | if (needs_closing_paren) try writer.writeByte(')'); | ||
| 1391 | if (eff_index != eff_num_fields - 1) try writer.writeAll(", "); | ||
| 1392 | |||
| 1393 | bit_offset += field.ty.bitSize(mod); | ||
| 1394 | needs_closing_paren = true; | ||
| 1395 | eff_index += 1; | ||
| 1396 | } | ||
| 1397 | } else { | ||
| 1398 | try writer.writeByte('('); | ||
| 1399 | // a << a_off | b << b_off | c << c_off | ||
| 1400 | var empty = true; | ||
| 1401 | for (struct_obj.fields.values(), 0..) |field, field_i| { | ||
| 1402 | if (field.is_comptime) continue; | ||
| 1403 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | ||
| 1404 | |||
| 1405 | if (!empty) try writer.writeAll(" | "); | ||
| 1406 | try writer.writeByte('('); | ||
| 1407 | try dg.renderType(writer, ty); | ||
| 1408 | try writer.writeByte(')'); | ||
| 1409 | 1415 | ||
| 1410 | const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) { | 1416 | if (bit_offset != 0) { |
| 1411 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ | 1417 | try dg.renderValue(writer, field_ty.toType(), field_val.toValue(), .Other); |
| 1412 | .ty = field.ty.toIntern(), | 1418 | try writer.writeAll(" << "); |
| 1413 | .storage = .{ .u64 = bytes[field_i] }, | 1419 | const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset); |
| 1414 | } }), | 1420 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); |
| 1415 | .elems => |elems| elems[field_i], | 1421 | } else { |
| 1416 | .repeated_elem => |elem| elem, | 1422 | try dg.renderValue(writer, field_ty.toType(), field_val.toValue(), .Other); |
| 1417 | }; | ||
| 1418 | |||
| 1419 | if (bit_offset != 0) { | ||
| 1420 | try dg.renderValue(writer, field.ty, field_val.toValue(), .Other); | ||
| 1421 | try writer.writeAll(" << "); | ||
| 1422 | const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset); | ||
| 1423 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | ||
| 1424 | } else { | ||
| 1425 | try dg.renderValue(writer, field.ty, field_val.toValue(), .Other); | ||
| 1426 | } | ||
| 1427 | |||
| 1428 | bit_offset += field.ty.bitSize(mod); | ||
| 1429 | empty = false; | ||
| 1430 | } | 1423 | } |
| 1431 | try writer.writeByte(')'); | 1424 | |
| 1425 | bit_offset += field_ty.toType().bitSize(mod); | ||
| 1426 | empty = false; | ||
| 1432 | } | 1427 | } |
| 1433 | }, | 1428 | try writer.writeByte(')'); |
| 1434 | } | 1429 | } |
| 1430 | }, | ||
| 1435 | }, | 1431 | }, |
| 1436 | else => unreachable, | 1432 | else => unreachable, |
| 1437 | }, | 1433 | }, |
| ... | @@ -1723,7 +1719,7 @@ pub const DeclGen = struct { | ... | @@ -1723,7 +1719,7 @@ pub const DeclGen = struct { |
| 1723 | ty: Type, | 1719 | ty: Type, |
| 1724 | name: CValue, | 1720 | name: CValue, |
| 1725 | qualifiers: CQualifiers, | 1721 | qualifiers: CQualifiers, |
| 1726 | alignment: u64, | 1722 | alignment: Alignment, |
| 1727 | kind: CType.Kind, | 1723 | kind: CType.Kind, |
| 1728 | ) error{ OutOfMemory, AnalysisFail }!void { | 1724 | ) error{ OutOfMemory, AnalysisFail }!void { |
| 1729 | const mod = dg.module; | 1725 | const mod = dg.module; |
| ... | @@ -1854,7 +1850,7 @@ pub const DeclGen = struct { | ... | @@ -1854,7 +1850,7 @@ pub const DeclGen = struct { |
| 1854 | decl.ty, | 1850 | decl.ty, |
| 1855 | .{ .decl = decl_index }, | 1851 | .{ .decl = decl_index }, |
| 1856 | CQualifiers.init(.{ .@"const" = variable.is_const }), | 1852 | CQualifiers.init(.{ .@"const" = variable.is_const }), |
| 1857 | @as(u32, @intCast(decl.alignment.toByteUnits(0))), | 1853 | decl.alignment, |
| 1858 | .complete, | 1854 | .complete, |
| 1859 | ); | 1855 | ); |
| 1860 | try fwd_decl_writer.writeAll(";\n"); | 1856 | try fwd_decl_writer.writeAll(";\n"); |
| ... | @@ -2460,7 +2456,7 @@ pub fn genErrDecls(o: *Object) !void { | ... | @@ -2460,7 +2456,7 @@ pub fn genErrDecls(o: *Object) !void { |
| 2460 | } }); | 2456 | } }); |
| 2461 | 2457 | ||
| 2462 | try writer.writeAll("static "); | 2458 | try writer.writeAll("static "); |
| 2463 | try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, Const, 0, .complete); | 2459 | try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, Const, .none, .complete); |
| 2464 | try writer.writeAll(" = "); | 2460 | try writer.writeAll(" = "); |
| 2465 | try o.dg.renderValue(writer, name_ty, name_val.toValue(), .StaticInitializer); | 2461 | try o.dg.renderValue(writer, name_ty, name_val.toValue(), .StaticInitializer); |
| 2466 | try writer.writeAll(";\n"); | 2462 | try writer.writeAll(";\n"); |
| ... | @@ -2472,7 +2468,7 @@ pub fn genErrDecls(o: *Object) !void { | ... | @@ -2472,7 +2468,7 @@ pub fn genErrDecls(o: *Object) !void { |
| 2472 | }); | 2468 | }); |
| 2473 | 2469 | ||
| 2474 | try writer.writeAll("static "); | 2470 | try writer.writeAll("static "); |
| 2475 | try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = array_identifier }, Const, 0, .complete); | 2471 | try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = array_identifier }, Const, .none, .complete); |
| 2476 | try writer.writeAll(" = {"); | 2472 | try writer.writeAll(" = {"); |
| 2477 | for (mod.global_error_set.keys(), 0..) |name_nts, value| { | 2473 | for (mod.global_error_set.keys(), 0..) |name_nts, value| { |
| 2478 | const name = mod.intern_pool.stringToSlice(name_nts); | 2474 | const name = mod.intern_pool.stringToSlice(name_nts); |
| ... | @@ -2523,7 +2519,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { | ... | @@ -2523,7 +2519,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { |
| 2523 | try w.writeByte(' '); | 2519 | try w.writeByte(' '); |
| 2524 | try w.writeAll(fn_name); | 2520 | try w.writeAll(fn_name); |
| 2525 | try w.writeByte('('); | 2521 | try w.writeByte('('); |
| 2526 | try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, 0, .complete); | 2522 | try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, .none, .complete); |
| 2527 | try w.writeAll(") {\n switch (tag) {\n"); | 2523 | try w.writeAll(") {\n switch (tag) {\n"); |
| 2528 | for (enum_ty.enumFields(mod), 0..) |name_ip, index_usize| { | 2524 | for (enum_ty.enumFields(mod), 0..) |name_ip, index_usize| { |
| 2529 | const index = @as(u32, @intCast(index_usize)); | 2525 | const index = @as(u32, @intCast(index_usize)); |
| ... | @@ -2546,7 +2542,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { | ... | @@ -2546,7 +2542,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { |
| 2546 | try w.print(" case {}: {{\n static ", .{ | 2542 | try w.print(" case {}: {{\n static ", .{ |
| 2547 | try o.dg.fmtIntLiteral(enum_ty, int_val, .Other), | 2543 | try o.dg.fmtIntLiteral(enum_ty, int_val, .Other), |
| 2548 | }); | 2544 | }); |
| 2549 | try o.dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, Const, 0, .complete); | 2545 | try o.dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, Const, .none, .complete); |
| 2550 | try w.writeAll(" = "); | 2546 | try w.writeAll(" = "); |
| 2551 | try o.dg.renderValue(w, name_ty, name_val.toValue(), .Initializer); | 2547 | try o.dg.renderValue(w, name_ty, name_val.toValue(), .Initializer); |
| 2552 | try w.writeAll(";\n return ("); | 2548 | try w.writeAll(";\n return ("); |
| ... | @@ -2706,7 +2702,7 @@ pub fn genDecl(o: *Object) !void { | ... | @@ -2706,7 +2702,7 @@ pub fn genDecl(o: *Object) !void { |
| 2706 | if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage "); | 2702 | if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage "); |
| 2707 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| | 2703 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| |
| 2708 | try w.print("zig_linksection(\"{s}\", ", .{s}); | 2704 | try w.print("zig_linksection(\"{s}\", ", .{s}); |
| 2709 | try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .{}, decl.alignment.toByteUnits(0), .complete); | 2705 | try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .{}, decl.alignment, .complete); |
| 2710 | if (decl.@"linksection" != .none) try w.writeAll(", read, write)"); | 2706 | if (decl.@"linksection" != .none) try w.writeAll(", read, write)"); |
| 2711 | try w.writeAll(" = "); | 2707 | try w.writeAll(" = "); |
| 2712 | try o.dg.renderValue(w, tv.ty, variable.init.toValue(), .StaticInitializer); | 2708 | try o.dg.renderValue(w, tv.ty, variable.init.toValue(), .StaticInitializer); |
| ... | @@ -2717,14 +2713,14 @@ pub fn genDecl(o: *Object) !void { | ... | @@ -2717,14 +2713,14 @@ pub fn genDecl(o: *Object) !void { |
| 2717 | const fwd_decl_writer = o.dg.fwd_decl.writer(); | 2713 | const fwd_decl_writer = o.dg.fwd_decl.writer(); |
| 2718 | 2714 | ||
| 2719 | try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static "); | 2715 | try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static "); |
| 2720 | try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, Const, decl.alignment.toByteUnits(0), .complete); | 2716 | try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, Const, decl.alignment, .complete); |
| 2721 | try fwd_decl_writer.writeAll(";\n"); | 2717 | try fwd_decl_writer.writeAll(";\n"); |
| 2722 | 2718 | ||
| 2723 | const w = o.writer(); | 2719 | const w = o.writer(); |
| 2724 | if (!is_global) try w.writeAll("static "); | 2720 | if (!is_global) try w.writeAll("static "); |
| 2725 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| | 2721 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| |
| 2726 | try w.print("zig_linksection(\"{s}\", ", .{s}); | 2722 | try w.print("zig_linksection(\"{s}\", ", .{s}); |
| 2727 | try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, Const, decl.alignment.toByteUnits(0), .complete); | 2723 | try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, Const, decl.alignment, .complete); |
| 2728 | if (decl.@"linksection" != .none) try w.writeAll(", read)"); | 2724 | if (decl.@"linksection" != .none) try w.writeAll(", read)"); |
| 2729 | try w.writeAll(" = "); | 2725 | try w.writeAll(" = "); |
| 2730 | try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer); | 2726 | try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer); |
| ... | @@ -3353,8 +3349,8 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3353,8 +3349,8 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3353 | 3349 | ||
| 3354 | try reap(f, inst, &.{ty_op.operand}); | 3350 | try reap(f, inst, &.{ty_op.operand}); |
| 3355 | 3351 | ||
| 3356 | const is_aligned = if (ptr_info.flags.alignment.toByteUnitsOptional()) |alignment| | 3352 | const is_aligned = if (ptr_info.flags.alignment != .none) |
| 3357 | alignment >= src_ty.abiAlignment(mod) | 3353 | ptr_info.flags.alignment.compare(.gte, src_ty.abiAlignment(mod)) |
| 3358 | else | 3354 | else |
| 3359 | true; | 3355 | true; |
| 3360 | const is_array = lowersToArray(src_ty, mod); | 3356 | const is_array = lowersToArray(src_ty, mod); |
| ... | @@ -3625,8 +3621,8 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { | ... | @@ -3625,8 +3621,8 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 3625 | return .none; | 3621 | return .none; |
| 3626 | } | 3622 | } |
| 3627 | 3623 | ||
| 3628 | const is_aligned = if (ptr_info.flags.alignment.toByteUnitsOptional()) |alignment| | 3624 | const is_aligned = if (ptr_info.flags.alignment != .none) |
| 3629 | alignment >= src_ty.abiAlignment(mod) | 3625 | ptr_info.flags.alignment.compare(.gte, src_ty.abiAlignment(mod)) |
| 3630 | else | 3626 | else |
| 3631 | true; | 3627 | true; |
| 3632 | const is_array = lowersToArray(ptr_info.child.toType(), mod); | 3628 | const is_array = lowersToArray(ptr_info.child.toType(), mod); |
| ... | @@ -4847,7 +4843,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4847,7 +4843,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4847 | if (is_reg) { | 4843 | if (is_reg) { |
| 4848 | const output_ty = if (output == .none) inst_ty else f.typeOf(output).childType(mod); | 4844 | const output_ty = if (output == .none) inst_ty else f.typeOf(output).childType(mod); |
| 4849 | try writer.writeAll("register "); | 4845 | try writer.writeAll("register "); |
| 4850 | const alignment = 0; | 4846 | const alignment: Alignment = .none; |
| 4851 | const local_value = try f.allocLocalValue(output_ty, alignment); | 4847 | const local_value = try f.allocLocalValue(output_ty, alignment); |
| 4852 | try f.allocs.put(gpa, local_value.new_local, false); | 4848 | try f.allocs.put(gpa, local_value.new_local, false); |
| 4853 | try f.object.dg.renderTypeAndName(writer, output_ty, local_value, .{}, alignment, .complete); | 4849 | try f.object.dg.renderTypeAndName(writer, output_ty, local_value, .{}, alignment, .complete); |
| ... | @@ -4880,7 +4876,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4880,7 +4876,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4880 | if (asmInputNeedsLocal(f, constraint, input_val)) { | 4876 | if (asmInputNeedsLocal(f, constraint, input_val)) { |
| 4881 | const input_ty = f.typeOf(input); | 4877 | const input_ty = f.typeOf(input); |
| 4882 | if (is_reg) try writer.writeAll("register "); | 4878 | if (is_reg) try writer.writeAll("register "); |
| 4883 | const alignment = 0; | 4879 | const alignment: Alignment = .none; |
| 4884 | const local_value = try f.allocLocalValue(input_ty, alignment); | 4880 | const local_value = try f.allocLocalValue(input_ty, alignment); |
| 4885 | try f.allocs.put(gpa, local_value.new_local, false); | 4881 | try f.allocs.put(gpa, local_value.new_local, false); |
| 4886 | try f.object.dg.renderTypeAndName(writer, input_ty, local_value, Const, alignment, .complete); | 4882 | try f.object.dg.renderTypeAndName(writer, input_ty, local_value, Const, alignment, .complete); |
| ... | @@ -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 | else | 5237 | 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 | else | 5424 | 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); |
| 5432 | 5429 | ||
| 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)); |
| 5434 | 5431 | ||
| 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); |
| 5437 | 5434 | ||
| 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 | else | 5486 | else |
| 5490 | .{ .identifier = ip.stringToSlice(struct_ty.structFieldName(extra.field_index, mod)) }, | 5487 | .{ .identifier = ip.stringToSlice(struct_ty.legacyStructFieldName(extra.field_index, mod)) }, |
| 5491 | 5488 | ||
| 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 | else | 6829 | 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, |
| 285 | 285 | ||
| 286 | pub fn init(alignment: u64, abi_alignment: u32) AlignAs { | 286 | pub fn init(@"align": Alignment, abi_align: Alignment) AlignAs { |
| 287 | const @"align" = Alignment.fromByteUnits(alignment); | 287 | assert(abi_align != .none); |
| 288 | const abi_align = Alignment.fromNonzeroByteUnits(abi_alignment); | ||
| 289 | return .{ | 288 | return .{ |
| 290 | .@"align" = if (@"align" != .none) @"align" else abi_align, | 289 | .@"align" = if (@"align" != .none) @"align" else abi_align, |
| 291 | .abi = abi_align, | 290 | .abi = abi_align, |
| 292 | }; | 291 | }; |
| 293 | } | 292 | } |
| 293 | |||
| 294 | pub fn initByteUnits(alignment: u64, abi_alignment: u32) AlignAs { | ||
| 295 | return init( | ||
| 296 | Alignment.fromByteUnits(alignment), | ||
| 297 | Alignment.fromNonzeroByteUnits(abi_alignment), | ||
| 298 | ); | ||
| 299 | } | ||
| 294 | pub fn abiAlign(ty: Type, mod: *Module) AlignAs { | 300 | pub fn abiAlign(ty: Type, mod: *Module) AlignAs { |
| 295 | const abi_align = ty.abiAlignment(mod); | 301 | const abi_align = ty.abiAlignment(mod); |
| 296 | return init(abi_align, abi_align); | 302 | return init(abi_align, abi_align); |
| ... | @@ -1360,6 +1366,7 @@ pub const CType = extern union { | ... | @@ -1360,6 +1366,7 @@ pub const CType = extern union { |
| 1360 | 1366 | ||
| 1361 | pub fn initType(self: *@This(), ty: Type, kind: Kind, lookup: Lookup) !void { | 1367 | pub fn initType(self: *@This(), ty: Type, kind: Kind, lookup: Lookup) !void { |
| 1362 | const mod = lookup.getModule(); | 1368 | const mod = lookup.getModule(); |
| 1369 | const ip = &mod.intern_pool; | ||
| 1363 | 1370 | ||
| 1364 | self.* = undefined; | 1371 | self.* = undefined; |
| 1365 | if (!ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) | 1372 | if (!ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) |
| ... | @@ -1382,12 +1389,12 @@ pub const CType = extern union { | ... | @@ -1382,12 +1389,12 @@ pub const CType = extern union { |
| 1382 | .array => switch (kind) { | 1389 | .array => switch (kind) { |
| 1383 | .forward, .complete, .global => { | 1390 | .forward, .complete, .global => { |
| 1384 | const abi_size = ty.abiSize(mod); | 1391 | const abi_size = ty.abiSize(mod); |
| 1385 | const abi_align = ty.abiAlignment(mod); | 1392 | const abi_align = ty.abiAlignment(mod).toByteUnits(0); |
| 1386 | self.storage = .{ .seq = .{ .base = .{ .tag = .array }, .data = .{ | 1393 | self.storage = .{ .seq = .{ .base = .{ .tag = .array }, .data = .{ |
| 1387 | .len = @divExact(abi_size, abi_align), | 1394 | .len = @divExact(abi_size, abi_align), |
| 1388 | .elem_type = tagFromIntInfo(.{ | 1395 | .elem_type = tagFromIntInfo(.{ |
| 1389 | .signedness = .unsigned, | 1396 | .signedness = .unsigned, |
| 1390 | .bits = @as(u16, @intCast(abi_align * 8)), | 1397 | .bits = @intCast(abi_align * 8), |
| 1391 | }).toIndex(), | 1398 | }).toIndex(), |
| 1392 | } } }; | 1399 | } } }; |
| 1393 | self.value = .{ .cty = initPayload(&self.storage.seq) }; | 1400 | self.value = .{ .cty = initPayload(&self.storage.seq) }; |
| ... | @@ -1488,10 +1495,10 @@ pub const CType = extern union { | ... | @@ -1488,10 +1495,10 @@ pub const CType = extern union { |
| 1488 | }, | 1495 | }, |
| 1489 | 1496 | ||
| 1490 | .Struct, .Union => |zig_ty_tag| if (ty.containerLayout(mod) == .Packed) { | 1497 | .Struct, .Union => |zig_ty_tag| if (ty.containerLayout(mod) == .Packed) { |
| 1491 | if (mod.typeToStruct(ty)) |struct_obj| { | 1498 | if (mod.typeToPackedStruct(ty)) |packed_struct| { |
| 1492 | try self.initType(struct_obj.backing_int_ty, kind, lookup); | 1499 | try self.initType(packed_struct.backingIntType(ip).toType(), kind, lookup); |
| 1493 | } else { | 1500 | } else { |
| 1494 | const bits = @as(u16, @intCast(ty.bitSize(mod))); | 1501 | const bits: u16 = @intCast(ty.bitSize(mod)); |
| 1495 | const int_ty = try mod.intType(.unsigned, bits); | 1502 | const int_ty = try mod.intType(.unsigned, bits); |
| 1496 | try self.initType(int_ty, kind, lookup); | 1503 | try self.initType(int_ty, kind, lookup); |
| 1497 | } | 1504 | } |
| ... | @@ -1722,7 +1729,6 @@ pub const CType = extern union { | ... | @@ -1722,7 +1729,6 @@ pub const CType = extern union { |
| 1722 | 1729 | ||
| 1723 | .Fn => { | 1730 | .Fn => { |
| 1724 | const info = mod.typeToFunc(ty).?; | 1731 | const info = mod.typeToFunc(ty).?; |
| 1725 | const ip = &mod.intern_pool; | ||
| 1726 | if (!info.is_generic) { | 1732 | if (!info.is_generic) { |
| 1727 | if (lookup.isMutable()) { | 1733 | if (lookup.isMutable()) { |
| 1728 | const param_kind: Kind = switch (kind) { | 1734 | const param_kind: Kind = switch (kind) { |
| ... | @@ -1947,7 +1953,8 @@ pub const CType = extern union { | ... | @@ -1947,7 +1953,8 @@ pub const CType = extern union { |
| 1947 | 1953 | ||
| 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)) or | 1959 | 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 | else | 1966 | 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)) or | 2104 | 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 unreachable | 2118 | std.fmt.bufPrintZ(&name_buf, "f{}", .{field_i}) catch unreachable |
| 2111 | else | 2119 | 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)) or | 2233 | 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 unreachable | 2243 | std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable |
| 2235 | else | 2244 | 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 { |
| 833 | 833 | ||
| 834 | /// When an LLVM struct type is created, an entry is inserted into this | 834 | /// 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 corresponding | 835 | /// 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 | ); |
| 1082 | 1085 | ||
| ... | @@ -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 | } |
| 1320 | 1323 | ||
| 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); |
| 1408 | 1412 | ||
| 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(); |
| 1427 | 1431 | ||
| 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(); |
| 1442 | 1446 | ||
| 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; |
| 1457 | 1461 | ||
| 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); |
| 1462 | 1466 | ||
| ... | @@ -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() orelse | 1489 | @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; |
| 1533 | 1537 | ||
| 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); |
| 1537 | 1541 | ||
| ... | @@ -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; |
| 1548 | 1552 | ||
| 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); |
| 1552 | 1556 | ||
| ... | @@ -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 { |
| 2055 | 2059 | ||
| 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; |
| 2060 | 2064 | ||
| 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 bits | 2071 | ptr_size * 8, // size in bits |
| 2068 | ptr_align * 8, // align in bits | 2072 | ptr_align.toByteUnits(0) * 8, // align in bits |
| 2069 | 0, // offset in bits | 2073 | 0, // offset in bits |
| 2070 | 0, // flags | 2074 | 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 bits | 2082 | len_size * 8, // size in bits |
| 2079 | len_align * 8, // align in bits | 2083 | len_align.toByteUnits(0) * 8, // align in bits |
| 2080 | len_offset * 8, // offset in bits | 2084 | len_offset * 8, // offset in bits |
| 2081 | 0, // flags | 2085 | 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 bits | 2095 | ty.abiSize(mod) * 8, // size in bits |
| 2092 | ty.abiAlignment(mod) * 8, // align in bits | 2096 | ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits |
| 2093 | 0, // flags | 2097 | 0, // flags |
| 2094 | null, // derived from | 2098 | 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 { |
| 2174 | 2178 | ||
| 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 { |
| 2223 | 2227 | ||
| 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; |
| 2228 | 2232 | ||
| 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 bits | 2239 | payload_size * 8, // size in bits |
| 2236 | payload_align * 8, // align in bits | 2240 | payload_align.toByteUnits(0) * 8, // align in bits |
| 2237 | 0, // offset in bits | 2241 | 0, // offset in bits |
| 2238 | 0, // flags | 2242 | 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 bits | 2250 | non_null_size * 8, // size in bits |
| 2247 | non_null_align * 8, // align in bits | 2251 | non_null_align.toByteUnits(0) * 8, // align in bits |
| 2248 | non_null_offset * 8, // offset in bits | 2252 | non_null_offset * 8, // offset in bits |
| 2249 | 0, // flags | 2253 | 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 bits | 2263 | ty.abiSize(mod) * 8, // size in bits |
| 2260 | ty.abiAlignment(mod) * 8, // align in bits | 2264 | ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits |
| 2261 | 0, // flags | 2265 | 0, // flags |
| 2262 | null, // derived from | 2266 | 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 | } |
| 2320 | 2324 | ||
| 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 bits | 2331 | error_size * 8, // size in bits |
| 2328 | error_align * 8, // align in bits | 2332 | error_align.toByteUnits(0) * 8, // align in bits |
| 2329 | error_offset * 8, // offset in bits | 2333 | error_offset * 8, // offset in bits |
| 2330 | 0, // flags | 2334 | 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 bits | 2342 | payload_size * 8, // size in bits |
| 2339 | payload_align * 8, // align in bits | 2343 | payload_align.toByteUnits(0) * 8, // align in bits |
| 2340 | payload_offset * 8, // offset in bits | 2344 | payload_offset * 8, // offset in bits |
| 2341 | 0, // flags | 2345 | 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 bits | 2354 | ty.abiSize(mod) * 8, // size in bits |
| 2351 | ty.abiAlignment(mod) * 8, // align in bits | 2355 | ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits |
| 2352 | 0, // flags | 2356 | 0, // flags |
| 2353 | null, // derived from | 2357 | 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); |
| 2376 | 2380 | ||
| 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 { |
| 2417 | 2421 | ||
| 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; |
| 2422 | 2426 | ||
| 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, // file | 2436 | null, // file |
| 2433 | 0, // line | 2437 | 0, // line |
| 2434 | field_size * 8, // size in bits | 2438 | field_size * 8, // size in bits |
| 2435 | field_align * 8, // align in bits | 2439 | field_align.toByteUnits(0) * 8, // align in bits |
| 2436 | field_offset * 8, // offset in bits | 2440 | field_offset * 8, // offset in bits |
| 2437 | 0, // flags | 2441 | 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, // file | 2449 | null, // file |
| 2446 | 0, // line | 2450 | 0, // line |
| 2447 | ty.abiSize(mod) * 8, // size in bits | 2451 | ty.abiSize(mod) * 8, // size in bits |
| 2448 | ty.abiAlignment(mod) * 8, // align in bits | 2452 | ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits |
| 2449 | 0, // flags | 2453 | 0, // flags |
| 2450 | null, // derived from | 2454 | 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 to | 2468 | // This can happen if a struct type makes it all the way to |
| 2467 | // flush() without ever being instantiated or referenced (even | 2469 | // flush() without ever being instantiated or referenced (even |
| 2468 | // via pointer). The only reason we are hearing about it now is | 2470 | // 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 | } |
| 2494 | 2496 | ||
| 2495 | const fields = ty.structFields(mod); | 2497 | const struct_type = mod.typeToStruct(ty).?; |
| 2496 | const layout = ty.containerLayout(mod); | ||
| 2497 | 2498 | ||
| 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); |
| 2500 | 2501 | ||
| 2501 | try di_fields.ensureUnusedCapacity(gpa, fields.count()); | 2502 | try di_fields.ensureUnusedCapacity(gpa, struct_type.field_types.len); |
| 2502 | 2503 | ||
| 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); | ||
| 2505 | 2516 | ||
| 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; | ||
| 2513 | 2519 | ||
| 2514 | const field_name = ip.stringToSlice(fields.keys()[field_and_index.index]); | 2520 | const field_di_ty = try o.lowerDebugType(field_ty, .full); |
| 2515 | 2521 | ||
| 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, // file | 2525 | null, // file |
| 2520 | 0, // line | 2526 | 0, // line |
| 2521 | field_size * 8, // size in bits | 2527 | field_size * 8, // size in bits |
| 2522 | field_align * 8, // align in bits | 2528 | field_align.toByteUnits(0) * 8, // align in bits |
| 2523 | field_offset * 8, // offset in bits | 2529 | field_offset * 8, // offset in bits |
| 2524 | 0, // flags | 2530 | 0, // flags |
| 2525 | try o.lowerDebugType(field.ty, .full), | 2531 | field_di_ty, |
| 2526 | )); | 2532 | )); |
| 2527 | } | 2533 | } |
| 2528 | 2534 | ||
| ... | @@ -2532,7 +2538,7 @@ pub const Object = struct { | ... | @@ -2532,7 +2538,7 @@ pub const Object = struct { |
| 2532 | null, // file | 2538 | null, // file |
| 2533 | 0, // line | 2539 | 0, // line |
| 2534 | ty.abiSize(mod) * 8, // size in bits | 2540 | ty.abiSize(mod) * 8, // size in bits |
| 2535 | ty.abiAlignment(mod) * 8, // align in bits | 2541 | ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits |
| 2536 | 0, // flags | 2542 | 0, // flags |
| 2537 | null, // derived from | 2543 | 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, // file | 2594 | null, // file |
| 2589 | 0, // line | 2595 | 0, // line |
| 2590 | ty.abiSize(mod) * 8, // size in bits | 2596 | ty.abiSize(mod) * 8, // size in bits |
| 2591 | ty.abiAlignment(mod) * 8, // align in bits | 2597 | ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits |
| 2592 | 0, // flags | 2598 | 0, // flags |
| 2593 | null, // derived from | 2599 | 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, // file | 2630 | null, // file |
| 2625 | 0, // line | 2631 | 0, // line |
| 2626 | field_size * 8, // size in bits | 2632 | field_size * 8, // size in bits |
| 2627 | field_align * 8, // align in bits | 2633 | field_align.toByteUnits(0) * 8, // align in bits |
| 2628 | 0, // offset in bits | 2634 | 0, // offset in bits |
| 2629 | 0, // flags | 2635 | 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, // file | 2650 | null, // file |
| 2645 | 0, // line | 2651 | 0, // line |
| 2646 | ty.abiSize(mod) * 8, // size in bits | 2652 | ty.abiSize(mod) * 8, // size in bits |
| 2647 | ty.abiAlignment(mod) * 8, // align in bits | 2653 | ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits |
| 2648 | 0, // flags | 2654 | 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 { |
| 2661 | 2667 | ||
| 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 | } |
| 2671 | 2677 | ||
| 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, // file | 2681 | null, // file |
| 2676 | 0, // line | 2682 | 0, // line |
| 2677 | layout.tag_size * 8, | 2683 | layout.tag_size * 8, |
| 2678 | layout.tag_align * 8, // align in bits | 2684 | layout.tag_align.toByteUnits(0) * 8, |
| 2679 | tag_offset * 8, // offset in bits | 2685 | tag_offset * 8, // offset in bits |
| 2680 | 0, // flags | 2686 | 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, // file | 2693 | null, // file |
| 2688 | 0, // line | 2694 | 0, // line |
| 2689 | layout.payload_size * 8, // size in bits | 2695 | layout.payload_size * 8, // size in bits |
| 2690 | layout.payload_align * 8, // align in bits | 2696 | layout.payload_align.toByteUnits(0) * 8, |
| 2691 | payload_offset * 8, // offset in bits | 2697 | payload_offset * 8, // offset in bits |
| 2692 | 0, // flags | 2698 | 0, // flags |
| 2693 | union_di_ty, | 2699 | union_di_ty, |
| 2694 | ); | 2700 | ); |
| 2695 | 2701 | ||
| 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 | else | 2705 | 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, // file | 2711 | null, // file |
| 2706 | 0, // line | 2712 | 0, // line |
| 2707 | ty.abiSize(mod) * 8, // size in bits | 2713 | ty.abiSize(mod) * 8, // size in bits |
| 2708 | ty.abiAlignment(mod) * 8, // align in bits | 2714 | ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits |
| 2709 | 0, // flags | 2715 | 0, // flags |
| 2710 | null, // derived from | 2716 | 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 | } |
| 2927 | 2933 | ||
| 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); |
| 2930 | 2936 | ||
| 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 { |
| 3248 | 3253 | ||
| 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.*; |
| 3278 | 3283 | ||
| 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 | } |
| 3286 | 3289 | ||
| 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 calls | 3294 | gop.value_ptr.* = ty; // must be done before any recursive calls |
| 3292 | 3295 | ||
| 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 be | 3298 | // 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); |
| 3301 | 3302 | ||
| 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; |
| 3306 | 3307 | // When we encounter a zero-bit field, we place it here so we know to map it to the next non-zero-bit field (if any). | |
| 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); |
| 3316 | 3321 | ||
| 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)); |
| 3327 | 3346 | ||
| 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 { |
| 3353 | 3372 | ||
| 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); | ||
| 3357 | 3378 | ||
| 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; |
| 3364 | 3385 | ||
| 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); |
| 3369 | 3390 | ||
| 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; |
| 3449 | 3482 | ||
| 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 { |
| 3687 | 3720 | ||
| 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; |
| 3922 | 3955 | ||
| 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); |
| 3927 | 3960 | ||
| 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; |
| 3975 | 4007 | ||
| 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); |
| 4022 | 4058 | ||
| 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 | } |
| 4033 | 4069 | ||
| 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; |
| 4041 | 4082 | ||
| 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 { |
| 4174 | 4215 | ||
| 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); |
| 4183 | 4225 | ||
| 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 pointer | 4229 | // 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 | } |
| 4191 | 4233 | ||
| 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); |
| 4200 | 4243 | ||
| 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) or | 4246 | 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); |
| 4219 | 4262 | ||
| 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); |
| 4227 | 4270 | ||
| 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 { |
| 4241 | 4284 | ||
| 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 one | 4299 | // 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() orelse | 4456 | 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); |
| 4931 | 4974 | ||
| 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); |
| 4979 | 5022 | ||
| 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)); |
| 4996 | 5039 | ||
| 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 allocate | 5045 | // 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() orelse | 5175 | @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 having | 5220 | // In this case the function return type is honoring the calling convention by having |
| 5178 | // a different LLVM type than the usual one. We solve this here at the callsite | 5221 | // 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 { |
| 5266 | 5309 | ||
| 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(); |
| 5270 | 5313 | ||
| 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 means | 5315 | // 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; |
| 5336 | 5379 | ||
| 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); |
| 5339 | 5382 | ||
| 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); |
| 5360 | 5403 | ||
| 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); |
| 5363 | 5406 | ||
| 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; |
| 5999 | 6042 | ||
| 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 | } |
| 6003 | 6046 | ||
| ... | @@ -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 | } |
| 6103 | 6146 | ||
| ... | @@ -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); |
| 6115 | 6158 | ||
| 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; |
| 6230 | 6271 | ||
| 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); |
| 6839 | 6880 | ||
| 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, ""); |
| 7265 | 7304 | ||
| 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).?; |
| 7691 | 7730 | ||
| 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).?; |
| 8049 | 8088 | ||
| 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 completely | 8389 | // 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 | } |
| 8375 | 8414 | ||
| 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 | } |
| 8380 | 8419 | ||
| 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(); |
| 8463 | 8498 | ||
| 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 | } |
| 8468 | 8503 | ||
| ... | @@ -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 | } |
| 8481 | 8516 | ||
| ... | @@ -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 | ); |
| 8652 | 8687 | ||
| ... | @@ -8685,7 +8720,7 @@ pub const FuncGen = struct { | ... | @@ -8685,7 +8720,7 @@ pub const FuncGen = struct { |
| 8685 | 8720 | ||
| 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(); |
| 8689 | 8724 | ||
| 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 { |
| 8911 | 8947 | ||
| 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 { |
| 8998 | 9032 | ||
| 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 store | 9060 | // 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; | ||
| 9637 | 9670 | ||
| 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 | else | 9676 | 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 | } |
| 9654 | 9687 | ||
| 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 0xaa | 9691 | // 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); |
| 9660 | 9695 | ||
| 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 { |
| 9694 | 9727 | ||
| 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); |
| 9699 | 9732 | ||
| 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 set | 9804 | // 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 | } |
| 9828 | 9861 | ||
| 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 | } |
| 9847 | 9880 | ||
| ... | @@ -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 | ); |
| 9984 | 10017 | ||
| ... | @@ -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, ""); |
| 10025 | 10058 | ||
| 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; |
| 10051 | 10084 | ||
| 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); |
| 10055 | 10088 | ||
| 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; |
| 10170 | 10201 | ||
| 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; |
| 10176 | 10209 | ||
| ... | @@ -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); |
| 10202 | 10235 | ||
| 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); |
| 10206 | 10239 | ||
| 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; |
| 10245 | 10278 | ||
| ... | @@ -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; |
| 10338 | 10371 | ||
| 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(); |
| 10341 | 10374 | ||
| 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 |
| 10718 | 10751 | ||
| 10719 | fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type { | 10752 | fn 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 { |
| 10982 | 11020 | ||
| 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 { |
| 11137 | 11181 | ||
| 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; | ||
| 11161 | 11199 | ||
| 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 | } |
| 11363 | 11409 | ||
| 11364 | fn errUnionPayloadOffset(payload_ty: Type, mod: *Module) u1 { | 11410 | fn 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 | } |
| 11367 | 11413 | ||
| 11368 | fn errUnionErrorOffset(payload_ty: Type, mod: *Module) u1 { | 11414 | fn 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 | } |
| 11371 | 11417 | ||
| 11372 | /// Returns true for asm constraint (e.g. "=*m", "=r") if it accepts a memory location | 11418 | /// Returns true for asm constraint (e.g. "=*m", "=r") if it accepts a memory location |
src/codegen/spirv.zig+26-24| ... | @@ -792,24 +792,28 @@ pub const DeclGen = struct { | ... | @@ -792,24 +792,28 @@ pub const DeclGen = struct { |
| 792 | }, | 792 | }, |
| 793 | .vector_type => return dg.todo("indirect constant of type {}", .{ty.fmt(mod)}), | 793 | .vector_type => return dg.todo("indirect constant of type {}", .{ty.fmt(mod)}), |
| 794 | .struct_type => { | 794 | .struct_type => { |
| 795 | const struct_ty = mod.typeToStruct(ty).?; | 795 | const struct_type = mod.typeToStruct(ty).?; |
| 796 | if (struct_ty.layout == .Packed) { | 796 | if (struct_type.layout == .Packed) { |
| 797 | return dg.todo("packed struct constants", .{}); | 797 | return dg.todo("packed struct constants", .{}); |
| 798 | } | 798 | } |
| 799 | 799 | ||
| 800 | // TODO iterate with runtime order instead so that struct field | ||
| 801 | // reordering can be enabled for this backend. | ||
| 800 | const struct_begin = self.size; | 802 | const struct_begin = self.size; |
| 801 | for (struct_ty.fields.values(), 0..) |field, i| { | 803 | for (struct_type.field_types.get(ip), 0..) |field_ty, i_usize| { |
| 802 | if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue; | 804 | const i: u32 = @intCast(i_usize); |
| 805 | if (struct_type.fieldIsComptime(ip, i)) continue; | ||
| 806 | if (!field_ty.toType().hasRuntimeBits(mod)) continue; | ||
| 803 | 807 | ||
| 804 | const field_val = switch (aggregate.storage) { | 808 | const field_val = switch (aggregate.storage) { |
| 805 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ | 809 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ |
| 806 | .ty = field.ty.toIntern(), | 810 | .ty = field_ty, |
| 807 | .storage = .{ .u64 = bytes[i] }, | 811 | .storage = .{ .u64 = bytes[i] }, |
| 808 | } }), | 812 | } }), |
| 809 | .elems => |elems| elems[i], | 813 | .elems => |elems| elems[i], |
| 810 | .repeated_elem => |elem| elem, | 814 | .repeated_elem => |elem| elem, |
| 811 | }; | 815 | }; |
| 812 | try self.lower(field.ty, field_val.toValue()); | 816 | try self.lower(field_ty.toType(), field_val.toValue()); |
| 813 | 817 | ||
| 814 | // Add padding if required. | 818 | // Add padding if required. |
| 815 | // TODO: Add to type generation as well? | 819 | // TODO: Add to type generation as well? |
| ... | @@ -838,7 +842,7 @@ pub const DeclGen = struct { | ... | @@ -838,7 +842,7 @@ pub const DeclGen = struct { |
| 838 | const active_field_ty = union_obj.field_types.get(ip)[active_field].toType(); | 842 | const active_field_ty = union_obj.field_types.get(ip)[active_field].toType(); |
| 839 | 843 | ||
| 840 | const has_tag = layout.tag_size != 0; | 844 | const has_tag = layout.tag_size != 0; |
| 841 | const tag_first = layout.tag_align >= layout.payload_align; | 845 | const tag_first = layout.tag_align.compare(.gte, layout.payload_align); |
| 842 | 846 | ||
| 843 | if (has_tag and tag_first) { | 847 | if (has_tag and tag_first) { |
| 844 | try self.lower(ty.unionTagTypeSafety(mod).?, un.tag.toValue()); | 848 | try self.lower(ty.unionTagTypeSafety(mod).?, un.tag.toValue()); |
| ... | @@ -1094,7 +1098,7 @@ pub const DeclGen = struct { | ... | @@ -1094,7 +1098,7 @@ pub const DeclGen = struct { |
| 1094 | val, | 1098 | val, |
| 1095 | .UniformConstant, | 1099 | .UniformConstant, |
| 1096 | false, | 1100 | false, |
| 1097 | alignment, | 1101 | @intCast(alignment.toByteUnits(0)), |
| 1098 | ); | 1102 | ); |
| 1099 | log.debug("indirect constant: index = {}", .{@intFromEnum(spv_decl_index)}); | 1103 | log.debug("indirect constant: index = {}", .{@intFromEnum(spv_decl_index)}); |
| 1100 | try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {}); | 1104 | try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {}); |
| ... | @@ -1180,7 +1184,7 @@ pub const DeclGen = struct { | ... | @@ -1180,7 +1184,7 @@ pub const DeclGen = struct { |
| 1180 | var member_names = std.BoundedArray(CacheString, 4){}; | 1184 | var member_names = std.BoundedArray(CacheString, 4){}; |
| 1181 | 1185 | ||
| 1182 | const has_tag = layout.tag_size != 0; | 1186 | const has_tag = layout.tag_size != 0; |
| 1183 | const tag_first = layout.tag_align >= layout.payload_align; | 1187 | const tag_first = layout.tag_align.compare(.gte, layout.payload_align); |
| 1184 | const u8_ty_ref = try self.intType(.unsigned, 8); // TODO: What if Int8Type is not enabled? | 1188 | const u8_ty_ref = try self.intType(.unsigned, 8); // TODO: What if Int8Type is not enabled? |
| 1185 | 1189 | ||
| 1186 | if (has_tag and tag_first) { | 1190 | if (has_tag and tag_first) { |
| ... | @@ -1333,7 +1337,7 @@ pub const DeclGen = struct { | ... | @@ -1333,7 +1337,7 @@ pub const DeclGen = struct { |
| 1333 | } }); | 1337 | } }); |
| 1334 | }, | 1338 | }, |
| 1335 | .Struct => { | 1339 | .Struct => { |
| 1336 | const struct_ty = switch (ip.indexToKey(ty.toIntern())) { | 1340 | const struct_type = switch (ip.indexToKey(ty.toIntern())) { |
| 1337 | .anon_struct_type => |tuple| { | 1341 | .anon_struct_type => |tuple| { |
| 1338 | const member_types = try self.gpa.alloc(CacheRef, tuple.values.len); | 1342 | const member_types = try self.gpa.alloc(CacheRef, tuple.values.len); |
| 1339 | defer self.gpa.free(member_types); | 1343 | defer self.gpa.free(member_types); |
| ... | @@ -1350,13 +1354,12 @@ pub const DeclGen = struct { | ... | @@ -1350,13 +1354,12 @@ pub const DeclGen = struct { |
| 1350 | .member_types = member_types[0..member_index], | 1354 | .member_types = member_types[0..member_index], |
| 1351 | } }); | 1355 | } }); |
| 1352 | }, | 1356 | }, |
| 1353 | .struct_type => |struct_ty| struct_ty, | 1357 | .struct_type => |struct_type| struct_type, |
| 1354 | else => unreachable, | 1358 | else => unreachable, |
| 1355 | }; | 1359 | }; |
| 1356 | 1360 | ||
| 1357 | const struct_obj = mod.structPtrUnwrap(struct_ty.index).?; | 1361 | if (struct_type.layout == .Packed) { |
| 1358 | if (struct_obj.layout == .Packed) { | 1362 | return try self.resolveType(struct_type.backingIntType(ip).toType(), .direct); |
| 1359 | return try self.resolveType(struct_obj.backing_int_ty, .direct); | ||
| 1360 | } | 1363 | } |
| 1361 | 1364 | ||
| 1362 | var member_types = std.ArrayList(CacheRef).init(self.gpa); | 1365 | var member_types = std.ArrayList(CacheRef).init(self.gpa); |
| ... | @@ -1365,16 +1368,15 @@ pub const DeclGen = struct { | ... | @@ -1365,16 +1368,15 @@ pub const DeclGen = struct { |
| 1365 | var member_names = std.ArrayList(CacheString).init(self.gpa); | 1368 | var member_names = std.ArrayList(CacheString).init(self.gpa); |
| 1366 | defer member_names.deinit(); | 1369 | defer member_names.deinit(); |
| 1367 | 1370 | ||
| 1368 | var it = struct_obj.runtimeFieldIterator(mod); | 1371 | var it = struct_type.iterateRuntimeOrder(ip); |
| 1369 | while (it.next()) |field_and_index| { | 1372 | while (it.next()) |field_index| { |
| 1370 | const field = field_and_index.field; | 1373 | const field_ty = struct_type.field_types.get(ip)[field_index]; |
| 1371 | const index = field_and_index.index; | 1374 | const field_name = ip.stringToSlice(struct_type.field_names.get(ip)[field_index]); |
| 1372 | const field_name = ip.stringToSlice(struct_obj.fields.keys()[index]); | 1375 | try member_types.append(try self.resolveType(field_ty.toType(), .indirect)); |
| 1373 | try member_types.append(try self.resolveType(field.ty, .indirect)); | ||
| 1374 | try member_names.append(try self.spv.resolveString(field_name)); | 1376 | try member_names.append(try self.spv.resolveString(field_name)); |
| 1375 | } | 1377 | } |
| 1376 | 1378 | ||
| 1377 | const name = ip.stringToSlice(try struct_obj.getFullyQualifiedName(self.module)); | 1379 | const name = ip.stringToSlice(try mod.declPtr(struct_type.decl.unwrap().?).getFullyQualifiedName(mod)); |
| 1378 | 1380 | ||
| 1379 | return try self.spv.resolve(.{ .struct_type = .{ | 1381 | return try self.spv.resolve(.{ .struct_type = .{ |
| 1380 | .name = try self.spv.resolveString(name), | 1382 | .name = try self.spv.resolveString(name), |
| ... | @@ -1500,7 +1502,7 @@ pub const DeclGen = struct { | ... | @@ -1500,7 +1502,7 @@ pub const DeclGen = struct { |
| 1500 | const error_align = Type.anyerror.abiAlignment(mod); | 1502 | const error_align = Type.anyerror.abiAlignment(mod); |
| 1501 | const payload_align = payload_ty.abiAlignment(mod); | 1503 | const payload_align = payload_ty.abiAlignment(mod); |
| 1502 | 1504 | ||
| 1503 | const error_first = error_align > payload_align; | 1505 | const error_first = error_align.compare(.gt, payload_align); |
| 1504 | return .{ | 1506 | return .{ |
| 1505 | .payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(mod), | 1507 | .payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(mod), |
| 1506 | .error_first = error_first, | 1508 | .error_first = error_first, |
| ... | @@ -1662,7 +1664,7 @@ pub const DeclGen = struct { | ... | @@ -1662,7 +1664,7 @@ pub const DeclGen = struct { |
| 1662 | init_val, | 1664 | init_val, |
| 1663 | actual_storage_class, | 1665 | actual_storage_class, |
| 1664 | final_storage_class == .Generic, | 1666 | final_storage_class == .Generic, |
| 1665 | @as(u32, @intCast(decl.alignment.toByteUnits(0))), | 1667 | @intCast(decl.alignment.toByteUnits(0)), |
| 1666 | ); | 1668 | ); |
| 1667 | } | 1669 | } |
| 1668 | } | 1670 | } |
| ... | @@ -2603,7 +2605,7 @@ pub const DeclGen = struct { | ... | @@ -2603,7 +2605,7 @@ pub const DeclGen = struct { |
| 2603 | if (layout.payload_size == 0) return union_handle; | 2605 | if (layout.payload_size == 0) return union_handle; |
| 2604 | 2606 | ||
| 2605 | const tag_ty = un_ty.unionTagTypeSafety(mod).?; | 2607 | const tag_ty = un_ty.unionTagTypeSafety(mod).?; |
| 2606 | const tag_index = @intFromBool(layout.tag_align < layout.payload_align); | 2608 | const tag_index = @intFromBool(layout.tag_align.compare(.lt, layout.payload_align)); |
| 2607 | return try self.extractField(tag_ty, union_handle, tag_index); | 2609 | return try self.extractField(tag_ty, union_handle, tag_index); |
| 2608 | } | 2610 | } |
| 2609 | 2611 |
src/link/Coff.zig+4-4| ... | @@ -1118,7 +1118,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In | ... | @@ -1118,7 +1118,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In |
| 1118 | }, | 1118 | }, |
| 1119 | }; | 1119 | }; |
| 1120 | 1120 | ||
| 1121 | const required_alignment = tv.ty.abiAlignment(mod); | 1121 | const required_alignment: u32 = @intCast(tv.ty.abiAlignment(mod).toByteUnits(0)); |
| 1122 | const atom = self.getAtomPtr(atom_index); | 1122 | const atom = self.getAtomPtr(atom_index); |
| 1123 | atom.size = @as(u32, @intCast(code.len)); | 1123 | atom.size = @as(u32, @intCast(code.len)); |
| 1124 | atom.getSymbolPtr(self).value = try self.allocateAtom(atom_index, atom.size, required_alignment); | 1124 | atom.getSymbolPtr(self).value = try self.allocateAtom(atom_index, atom.size, required_alignment); |
| ... | @@ -1196,7 +1196,7 @@ fn updateLazySymbolAtom( | ... | @@ -1196,7 +1196,7 @@ fn updateLazySymbolAtom( |
| 1196 | const gpa = self.base.allocator; | 1196 | const gpa = self.base.allocator; |
| 1197 | const mod = self.base.options.module.?; | 1197 | const mod = self.base.options.module.?; |
| 1198 | 1198 | ||
| 1199 | var required_alignment: u32 = undefined; | 1199 | var required_alignment: InternPool.Alignment = .none; |
| 1200 | var code_buffer = std.ArrayList(u8).init(gpa); | 1200 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 1201 | defer code_buffer.deinit(); | 1201 | defer code_buffer.deinit(); |
| 1202 | 1202 | ||
| ... | @@ -1240,7 +1240,7 @@ fn updateLazySymbolAtom( | ... | @@ -1240,7 +1240,7 @@ fn updateLazySymbolAtom( |
| 1240 | symbol.section_number = @as(coff.SectionNumber, @enumFromInt(section_index + 1)); | 1240 | symbol.section_number = @as(coff.SectionNumber, @enumFromInt(section_index + 1)); |
| 1241 | symbol.type = .{ .complex_type = .NULL, .base_type = .NULL }; | 1241 | symbol.type = .{ .complex_type = .NULL, .base_type = .NULL }; |
| 1242 | 1242 | ||
| 1243 | const vaddr = try self.allocateAtom(atom_index, code_len, required_alignment); | 1243 | const vaddr = try self.allocateAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits(0))); |
| 1244 | errdefer self.freeAtom(atom_index); | 1244 | errdefer self.freeAtom(atom_index); |
| 1245 | 1245 | ||
| 1246 | log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr }); | 1246 | log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr }); |
| ... | @@ -1322,7 +1322,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []u8, comple | ... | @@ -1322,7 +1322,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []u8, comple |
| 1322 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); | 1322 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| 1323 | 1323 | ||
| 1324 | log.debug("updateDeclCode {s}{*}", .{ decl_name, decl }); | 1324 | log.debug("updateDeclCode {s}{*}", .{ decl_name, decl }); |
| 1325 | const required_alignment = decl.getAlignment(mod); | 1325 | const required_alignment: u32 = @intCast(decl.getAlignment(mod).toByteUnits(0)); |
| 1326 | 1326 | ||
| 1327 | const decl_metadata = self.decls.get(decl_index).?; | 1327 | const decl_metadata = self.decls.get(decl_index).?; |
| 1328 | const atom_index = decl_metadata.atom; | 1328 | const atom_index = decl_metadata.atom; |
src/link/Dwarf.zig+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.string | 345 | // DW.AT.name, DW.FORM.string |
| 347 | try ty.print(dbg_info_buffer.writer(), mod); | 346 | try ty.print(dbg_info_buffer.writer(), mod); |
| 348 | try dbg_info_buffer.append(0); | 347 | try dbg_info_buffer.append(0); |
| 349 | 348 | ||
| 350 | if (struct_obj.layout == .Packed) { | 349 | if (struct_type.layout == .Packed) { |
| 351 | log.debug("TODO implement .debug_info for packed structs", .{}); | 350 | log.debug("TODO implement .debug_info for packed structs", .{}); |
| 352 | break :blk; | 351 | break :blk; |
| 353 | } | 352 | } |
| 354 | 353 | ||
| 355 | for ( | 354 | 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.member | 361 | // 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.string | 364 | 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.ref4 | 367 | } |
| 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.udata | 371 | 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 have | 435 | // TODO this is temporary to match current state of unions in Zig - we don't yet have |
| 422 | // safety checks implemented meaning the implicit tag is not yet stored and generated | 436 | // 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); |
| 504 | 518 | ||
| 505 | // DW.AT.structure_type | 519 | // 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(); |
| 410 | 410 | ||
| 411 | if (self.phdr_table_index == null) { | 411 | if (self.phdr_table_index == null) { |
| 412 | self.phdr_table_index = @as(u16, @intCast(self.phdrs.items.len)); | 412 | self.phdr_table_index = @intCast(self.phdrs.items.len); |
| 413 | const p_align: u16 = switch (self.ptr_width) { | 413 | const p_align: u16 = switch (self.ptr_width) { |
| 414 | .p32 => @alignOf(elf.Elf32_Phdr), | 414 | .p32 => @alignOf(elf.Elf32_Phdr), |
| 415 | .p64 => @alignOf(elf.Elf64_Phdr), | 415 | .p64 => @alignOf(elf.Elf64_Phdr), |
| ... | @@ -428,7 +428,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -428,7 +428,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 428 | } | 428 | } |
| 429 | 429 | ||
| 430 | if (self.phdr_table_load_index == null) { | 430 | if (self.phdr_table_load_index == null) { |
| 431 | self.phdr_table_load_index = @as(u16, @intCast(self.phdrs.items.len)); | 431 | self.phdr_table_load_index = @intCast(self.phdrs.items.len); |
| 432 | // TODO Same as for GOT | 432 | // TODO Same as for GOT |
| 433 | try self.phdrs.append(gpa, .{ | 433 | try self.phdrs.append(gpa, .{ |
| 434 | .p_type = elf.PT_LOAD, | 434 | .p_type = elf.PT_LOAD, |
| ... | @@ -444,7 +444,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -444,7 +444,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 444 | } | 444 | } |
| 445 | 445 | ||
| 446 | if (self.phdr_load_re_index == null) { | 446 | if (self.phdr_load_re_index == null) { |
| 447 | self.phdr_load_re_index = @as(u16, @intCast(self.phdrs.items.len)); | 447 | self.phdr_load_re_index = @intCast(self.phdrs.items.len); |
| 448 | const file_size = self.base.options.program_code_size_hint; | 448 | const file_size = self.base.options.program_code_size_hint; |
| 449 | const p_align = self.page_size; | 449 | const p_align = self.page_size; |
| 450 | const off = self.findFreeSpace(file_size, p_align); | 450 | const off = self.findFreeSpace(file_size, p_align); |
| ... | @@ -465,7 +465,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -465,7 +465,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 465 | } | 465 | } |
| 466 | 466 | ||
| 467 | if (self.phdr_got_index == null) { | 467 | if (self.phdr_got_index == null) { |
| 468 | self.phdr_got_index = @as(u16, @intCast(self.phdrs.items.len)); | 468 | self.phdr_got_index = @intCast(self.phdrs.items.len); |
| 469 | const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint; | 469 | const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint; |
| 470 | // We really only need ptr alignment but since we are using PROGBITS, linux requires | 470 | // We really only need ptr alignment but since we are using PROGBITS, linux requires |
| 471 | // page align. | 471 | // page align. |
| ... | @@ -490,7 +490,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -490,7 +490,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 490 | } | 490 | } |
| 491 | 491 | ||
| 492 | if (self.phdr_load_ro_index == null) { | 492 | if (self.phdr_load_ro_index == null) { |
| 493 | self.phdr_load_ro_index = @as(u16, @intCast(self.phdrs.items.len)); | 493 | self.phdr_load_ro_index = @intCast(self.phdrs.items.len); |
| 494 | // TODO Find a hint about how much data need to be in rodata ? | 494 | // TODO Find a hint about how much data need to be in rodata ? |
| 495 | const file_size = 1024; | 495 | const file_size = 1024; |
| 496 | // Same reason as for GOT | 496 | // Same reason as for GOT |
| ... | @@ -513,7 +513,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -513,7 +513,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 513 | } | 513 | } |
| 514 | 514 | ||
| 515 | if (self.phdr_load_rw_index == null) { | 515 | if (self.phdr_load_rw_index == null) { |
| 516 | self.phdr_load_rw_index = @as(u16, @intCast(self.phdrs.items.len)); | 516 | self.phdr_load_rw_index = @intCast(self.phdrs.items.len); |
| 517 | // TODO Find a hint about how much data need to be in data ? | 517 | // TODO Find a hint about how much data need to be in data ? |
| 518 | const file_size = 1024; | 518 | const file_size = 1024; |
| 519 | // Same reason as for GOT | 519 | // Same reason as for GOT |
| ... | @@ -536,7 +536,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -536,7 +536,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 536 | } | 536 | } |
| 537 | 537 | ||
| 538 | if (self.phdr_load_zerofill_index == null) { | 538 | if (self.phdr_load_zerofill_index == null) { |
| 539 | self.phdr_load_zerofill_index = @as(u16, @intCast(self.phdrs.items.len)); | 539 | self.phdr_load_zerofill_index = @intCast(self.phdrs.items.len); |
| 540 | const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); | 540 | const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); |
| 541 | const off = self.phdrs.items[self.phdr_load_rw_index.?].p_offset; | 541 | const off = self.phdrs.items[self.phdr_load_rw_index.?].p_offset; |
| 542 | log.debug("found PT_LOAD zerofill free space 0x{x} to 0x{x}", .{ off, off }); | 542 | log.debug("found PT_LOAD zerofill free space 0x{x} to 0x{x}", .{ off, off }); |
| ... | @@ -556,7 +556,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -556,7 +556,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 556 | } | 556 | } |
| 557 | 557 | ||
| 558 | if (self.shstrtab_section_index == null) { | 558 | if (self.shstrtab_section_index == null) { |
| 559 | self.shstrtab_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 559 | self.shstrtab_section_index = @intCast(self.shdrs.items.len); |
| 560 | assert(self.shstrtab.buffer.items.len == 0); | 560 | assert(self.shstrtab.buffer.items.len == 0); |
| 561 | try self.shstrtab.buffer.append(gpa, 0); // need a 0 at position 0 | 561 | try self.shstrtab.buffer.append(gpa, 0); // need a 0 at position 0 |
| 562 | const off = self.findFreeSpace(self.shstrtab.buffer.items.len, 1); | 562 | const off = self.findFreeSpace(self.shstrtab.buffer.items.len, 1); |
| ... | @@ -578,7 +578,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -578,7 +578,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 578 | } | 578 | } |
| 579 | 579 | ||
| 580 | if (self.strtab_section_index == null) { | 580 | if (self.strtab_section_index == null) { |
| 581 | self.strtab_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 581 | self.strtab_section_index = @intCast(self.shdrs.items.len); |
| 582 | assert(self.strtab.buffer.items.len == 0); | 582 | assert(self.strtab.buffer.items.len == 0); |
| 583 | try self.strtab.buffer.append(gpa, 0); // need a 0 at position 0 | 583 | try self.strtab.buffer.append(gpa, 0); // need a 0 at position 0 |
| 584 | const off = self.findFreeSpace(self.strtab.buffer.items.len, 1); | 584 | const off = self.findFreeSpace(self.strtab.buffer.items.len, 1); |
| ... | @@ -600,7 +600,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -600,7 +600,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 600 | } | 600 | } |
| 601 | 601 | ||
| 602 | if (self.text_section_index == null) { | 602 | if (self.text_section_index == null) { |
| 603 | self.text_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 603 | self.text_section_index = @intCast(self.shdrs.items.len); |
| 604 | const phdr = &self.phdrs.items[self.phdr_load_re_index.?]; | 604 | const phdr = &self.phdrs.items[self.phdr_load_re_index.?]; |
| 605 | try self.shdrs.append(gpa, .{ | 605 | try self.shdrs.append(gpa, .{ |
| 606 | .sh_name = try self.shstrtab.insert(gpa, ".text"), | 606 | .sh_name = try self.shstrtab.insert(gpa, ".text"), |
| ... | @@ -620,7 +620,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -620,7 +620,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 620 | } | 620 | } |
| 621 | 621 | ||
| 622 | if (self.got_section_index == null) { | 622 | if (self.got_section_index == null) { |
| 623 | self.got_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 623 | self.got_section_index = @intCast(self.shdrs.items.len); |
| 624 | const phdr = &self.phdrs.items[self.phdr_got_index.?]; | 624 | const phdr = &self.phdrs.items[self.phdr_got_index.?]; |
| 625 | try self.shdrs.append(gpa, .{ | 625 | try self.shdrs.append(gpa, .{ |
| 626 | .sh_name = try self.shstrtab.insert(gpa, ".got"), | 626 | .sh_name = try self.shstrtab.insert(gpa, ".got"), |
| ... | @@ -639,7 +639,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -639,7 +639,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 639 | } | 639 | } |
| 640 | 640 | ||
| 641 | if (self.rodata_section_index == null) { | 641 | if (self.rodata_section_index == null) { |
| 642 | self.rodata_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 642 | self.rodata_section_index = @intCast(self.shdrs.items.len); |
| 643 | const phdr = &self.phdrs.items[self.phdr_load_ro_index.?]; | 643 | const phdr = &self.phdrs.items[self.phdr_load_ro_index.?]; |
| 644 | try self.shdrs.append(gpa, .{ | 644 | try self.shdrs.append(gpa, .{ |
| 645 | .sh_name = try self.shstrtab.insert(gpa, ".rodata"), | 645 | .sh_name = try self.shstrtab.insert(gpa, ".rodata"), |
| ... | @@ -659,7 +659,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -659,7 +659,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 659 | } | 659 | } |
| 660 | 660 | ||
| 661 | if (self.data_section_index == null) { | 661 | if (self.data_section_index == null) { |
| 662 | self.data_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 662 | self.data_section_index = @intCast(self.shdrs.items.len); |
| 663 | const phdr = &self.phdrs.items[self.phdr_load_rw_index.?]; | 663 | const phdr = &self.phdrs.items[self.phdr_load_rw_index.?]; |
| 664 | try self.shdrs.append(gpa, .{ | 664 | try self.shdrs.append(gpa, .{ |
| 665 | .sh_name = try self.shstrtab.insert(gpa, ".data"), | 665 | .sh_name = try self.shstrtab.insert(gpa, ".data"), |
| ... | @@ -679,7 +679,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -679,7 +679,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 679 | } | 679 | } |
| 680 | 680 | ||
| 681 | if (self.bss_section_index == null) { | 681 | if (self.bss_section_index == null) { |
| 682 | self.bss_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 682 | self.bss_section_index = @intCast(self.shdrs.items.len); |
| 683 | const phdr = &self.phdrs.items[self.phdr_load_zerofill_index.?]; | 683 | const phdr = &self.phdrs.items[self.phdr_load_zerofill_index.?]; |
| 684 | try self.shdrs.append(gpa, .{ | 684 | try self.shdrs.append(gpa, .{ |
| 685 | .sh_name = try self.shstrtab.insert(gpa, ".bss"), | 685 | .sh_name = try self.shstrtab.insert(gpa, ".bss"), |
| ... | @@ -699,7 +699,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -699,7 +699,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 699 | } | 699 | } |
| 700 | 700 | ||
| 701 | if (self.symtab_section_index == null) { | 701 | if (self.symtab_section_index == null) { |
| 702 | self.symtab_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 702 | self.symtab_section_index = @intCast(self.shdrs.items.len); |
| 703 | const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym); | 703 | const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym); |
| 704 | const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym); | 704 | const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym); |
| 705 | const file_size = self.base.options.symbol_count_hint * each_size; | 705 | const file_size = self.base.options.symbol_count_hint * each_size; |
| ... | @@ -714,7 +714,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -714,7 +714,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 714 | .sh_size = file_size, | 714 | .sh_size = file_size, |
| 715 | // The section header index of the associated string table. | 715 | // The section header index of the associated string table. |
| 716 | .sh_link = self.strtab_section_index.?, | 716 | .sh_link = self.strtab_section_index.?, |
| 717 | .sh_info = @as(u32, @intCast(self.symbols.items.len)), | 717 | .sh_info = @intCast(self.symbols.items.len), |
| 718 | .sh_addralign = min_align, | 718 | .sh_addralign = min_align, |
| 719 | .sh_entsize = each_size, | 719 | .sh_entsize = each_size, |
| 720 | }); | 720 | }); |
| ... | @@ -723,7 +723,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -723,7 +723,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 723 | 723 | ||
| 724 | if (self.dwarf) |*dw| { | 724 | if (self.dwarf) |*dw| { |
| 725 | if (self.debug_str_section_index == null) { | 725 | if (self.debug_str_section_index == null) { |
| 726 | self.debug_str_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 726 | self.debug_str_section_index = @intCast(self.shdrs.items.len); |
| 727 | assert(dw.strtab.buffer.items.len == 0); | 727 | assert(dw.strtab.buffer.items.len == 0); |
| 728 | try dw.strtab.buffer.append(gpa, 0); | 728 | try dw.strtab.buffer.append(gpa, 0); |
| 729 | try self.shdrs.append(gpa, .{ | 729 | try self.shdrs.append(gpa, .{ |
| ... | @@ -743,7 +743,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -743,7 +743,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 743 | } | 743 | } |
| 744 | 744 | ||
| 745 | if (self.debug_info_section_index == null) { | 745 | if (self.debug_info_section_index == null) { |
| 746 | self.debug_info_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 746 | self.debug_info_section_index = @intCast(self.shdrs.items.len); |
| 747 | const file_size_hint = 200; | 747 | const file_size_hint = 200; |
| 748 | const p_align = 1; | 748 | const p_align = 1; |
| 749 | const off = self.findFreeSpace(file_size_hint, p_align); | 749 | const off = self.findFreeSpace(file_size_hint, p_align); |
| ... | @@ -768,7 +768,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -768,7 +768,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 768 | } | 768 | } |
| 769 | 769 | ||
| 770 | if (self.debug_abbrev_section_index == null) { | 770 | if (self.debug_abbrev_section_index == null) { |
| 771 | self.debug_abbrev_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 771 | self.debug_abbrev_section_index = @intCast(self.shdrs.items.len); |
| 772 | const file_size_hint = 128; | 772 | const file_size_hint = 128; |
| 773 | const p_align = 1; | 773 | const p_align = 1; |
| 774 | const off = self.findFreeSpace(file_size_hint, p_align); | 774 | const off = self.findFreeSpace(file_size_hint, p_align); |
| ... | @@ -793,7 +793,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -793,7 +793,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 793 | } | 793 | } |
| 794 | 794 | ||
| 795 | if (self.debug_aranges_section_index == null) { | 795 | if (self.debug_aranges_section_index == null) { |
| 796 | self.debug_aranges_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 796 | self.debug_aranges_section_index = @intCast(self.shdrs.items.len); |
| 797 | const file_size_hint = 160; | 797 | const file_size_hint = 160; |
| 798 | const p_align = 16; | 798 | const p_align = 16; |
| 799 | const off = self.findFreeSpace(file_size_hint, p_align); | 799 | const off = self.findFreeSpace(file_size_hint, p_align); |
| ... | @@ -818,7 +818,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -818,7 +818,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 818 | } | 818 | } |
| 819 | 819 | ||
| 820 | if (self.debug_line_section_index == null) { | 820 | if (self.debug_line_section_index == null) { |
| 821 | self.debug_line_section_index = @as(u16, @intCast(self.shdrs.items.len)); | 821 | self.debug_line_section_index = @intCast(self.shdrs.items.len); |
| 822 | const file_size_hint = 250; | 822 | const file_size_hint = 250; |
| 823 | const p_align = 1; | 823 | const p_align = 1; |
| 824 | const off = self.findFreeSpace(file_size_hint, p_align); | 824 | const off = self.findFreeSpace(file_size_hint, p_align); |
| ... | @@ -2666,12 +2666,12 @@ fn updateDeclCode( | ... | @@ -2666,12 +2666,12 @@ fn updateDeclCode( |
| 2666 | 2666 | ||
| 2667 | const old_size = atom_ptr.size; | 2667 | const old_size = atom_ptr.size; |
| 2668 | const old_vaddr = atom_ptr.value; | 2668 | const old_vaddr = atom_ptr.value; |
| 2669 | atom_ptr.alignment = math.log2_int(u64, required_alignment); | 2669 | atom_ptr.alignment = required_alignment; |
| 2670 | atom_ptr.size = code.len; | 2670 | atom_ptr.size = code.len; |
| 2671 | 2671 | ||
| 2672 | if (old_size > 0 and self.base.child_pid == null) { | 2672 | if (old_size > 0 and self.base.child_pid == null) { |
| 2673 | const capacity = atom_ptr.capacity(self); | 2673 | const capacity = atom_ptr.capacity(self); |
| 2674 | const need_realloc = code.len > capacity or !mem.isAlignedGeneric(u64, sym.value, required_alignment); | 2674 | const need_realloc = code.len > capacity or !required_alignment.check(sym.value); |
| 2675 | if (need_realloc) { | 2675 | if (need_realloc) { |
| 2676 | try atom_ptr.grow(self); | 2676 | try atom_ptr.grow(self); |
| 2677 | log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, old_vaddr, atom_ptr.value }); | 2677 | log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, old_vaddr, atom_ptr.value }); |
| ... | @@ -2869,7 +2869,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. | ... | @@ -2869,7 +2869,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. |
| 2869 | const mod = self.base.options.module.?; | 2869 | const mod = self.base.options.module.?; |
| 2870 | const zig_module = self.file(self.zig_module_index.?).?.zig_module; | 2870 | const zig_module = self.file(self.zig_module_index.?).?.zig_module; |
| 2871 | 2871 | ||
| 2872 | var required_alignment: u32 = undefined; | 2872 | var required_alignment: InternPool.Alignment = .none; |
| 2873 | var code_buffer = std.ArrayList(u8).init(gpa); | 2873 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 2874 | defer code_buffer.deinit(); | 2874 | defer code_buffer.deinit(); |
| 2875 | 2875 | ||
| ... | @@ -2918,7 +2918,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. | ... | @@ -2918,7 +2918,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. |
| 2918 | const atom_ptr = local_sym.atom(self).?; | 2918 | const atom_ptr = local_sym.atom(self).?; |
| 2919 | atom_ptr.alive = true; | 2919 | atom_ptr.alive = true; |
| 2920 | atom_ptr.name_offset = name_str_index; | 2920 | atom_ptr.name_offset = name_str_index; |
| 2921 | atom_ptr.alignment = math.log2_int(u64, required_alignment); | 2921 | atom_ptr.alignment = required_alignment; |
| 2922 | atom_ptr.size = code.len; | 2922 | atom_ptr.size = code.len; |
| 2923 | 2923 | ||
| 2924 | try atom_ptr.allocate(self); | 2924 | try atom_ptr.allocate(self); |
| ... | @@ -2995,7 +2995,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module | ... | @@ -2995,7 +2995,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module |
| 2995 | const atom_ptr = local_sym.atom(self).?; | 2995 | const atom_ptr = local_sym.atom(self).?; |
| 2996 | atom_ptr.alive = true; | 2996 | atom_ptr.alive = true; |
| 2997 | atom_ptr.name_offset = name_str_index; | 2997 | atom_ptr.name_offset = name_str_index; |
| 2998 | atom_ptr.alignment = math.log2_int(u64, required_alignment); | 2998 | atom_ptr.alignment = required_alignment; |
| 2999 | atom_ptr.size = code.len; | 2999 | atom_ptr.size = code.len; |
| 3000 | 3000 | ||
| 3001 | try atom_ptr.allocate(self); | 3001 | try atom_ptr.allocate(self); |
src/link/Elf/Atom.zig+8-9| ... | @@ -11,7 +11,7 @@ file_index: File.Index = 0, | ... | @@ -11,7 +11,7 @@ file_index: File.Index = 0, |
| 11 | size: u64 = 0, | 11 | size: u64 = 0, |
| 12 | 12 | ||
| 13 | /// Alignment of this atom as a power of two. | 13 | /// Alignment of this atom as a power of two. |
| 14 | alignment: u8 = 0, | 14 | alignment: Alignment = .@"1", |
| 15 | 15 | ||
| 16 | /// Index of the input section. | 16 | /// Index of the input section. |
| 17 | input_section_index: Index = 0, | 17 | input_section_index: Index = 0, |
| ... | @@ -42,6 +42,8 @@ fde_end: u32 = 0, | ... | @@ -42,6 +42,8 @@ fde_end: u32 = 0, |
| 42 | prev_index: Index = 0, | 42 | prev_index: Index = 0, |
| 43 | next_index: Index = 0, | 43 | next_index: Index = 0, |
| 44 | 44 | ||
| 45 | pub const Alignment = @import("../../InternPool.zig").Alignment; | ||
| 46 | |||
| 45 | pub fn name(self: Atom, elf_file: *Elf) []const u8 { | 47 | pub fn name(self: Atom, elf_file: *Elf) []const u8 { |
| 46 | return elf_file.strtab.getAssumeExists(self.name_offset); | 48 | return elf_file.strtab.getAssumeExists(self.name_offset); |
| 47 | } | 49 | } |
| ... | @@ -112,7 +114,6 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { | ... | @@ -112,7 +114,6 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { |
| 112 | const free_list = &meta.free_list; | 114 | const free_list = &meta.free_list; |
| 113 | const last_atom_index = &meta.last_atom_index; | 115 | const last_atom_index = &meta.last_atom_index; |
| 114 | const new_atom_ideal_capacity = Elf.padToIdeal(self.size); | 116 | const new_atom_ideal_capacity = Elf.padToIdeal(self.size); |
| 115 | const alignment = try std.math.powi(u64, 2, self.alignment); | ||
| 116 | 117 | ||
| 117 | // We use these to indicate our intention to update metadata, placing the new atom, | 118 | // We use these to indicate our intention to update metadata, placing the new atom, |
| 118 | // and possibly removing a free list node. | 119 | // and possibly removing a free list node. |
| ... | @@ -136,7 +137,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { | ... | @@ -136,7 +137,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { |
| 136 | const ideal_capacity_end_vaddr = std.math.add(u64, big_atom.value, ideal_capacity) catch ideal_capacity; | 137 | const ideal_capacity_end_vaddr = std.math.add(u64, big_atom.value, ideal_capacity) catch ideal_capacity; |
| 137 | const capacity_end_vaddr = big_atom.value + cap; | 138 | const capacity_end_vaddr = big_atom.value + cap; |
| 138 | const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity; | 139 | const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity; |
| 139 | const new_start_vaddr = std.mem.alignBackward(u64, new_start_vaddr_unaligned, alignment); | 140 | const new_start_vaddr = self.alignment.backward(new_start_vaddr_unaligned); |
| 140 | if (new_start_vaddr < ideal_capacity_end_vaddr) { | 141 | if (new_start_vaddr < ideal_capacity_end_vaddr) { |
| 141 | // Additional bookkeeping here to notice if this free list node | 142 | // Additional bookkeeping here to notice if this free list node |
| 142 | // should be deleted because the block that it points to has grown to take up | 143 | // should be deleted because the block that it points to has grown to take up |
| ... | @@ -163,7 +164,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { | ... | @@ -163,7 +164,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { |
| 163 | } else if (elf_file.atom(last_atom_index.*)) |last| { | 164 | } else if (elf_file.atom(last_atom_index.*)) |last| { |
| 164 | const ideal_capacity = Elf.padToIdeal(last.size); | 165 | const ideal_capacity = Elf.padToIdeal(last.size); |
| 165 | const ideal_capacity_end_vaddr = last.value + ideal_capacity; | 166 | const ideal_capacity_end_vaddr = last.value + ideal_capacity; |
| 166 | const new_start_vaddr = std.mem.alignForward(u64, ideal_capacity_end_vaddr, alignment); | 167 | const new_start_vaddr = self.alignment.forward(ideal_capacity_end_vaddr); |
| 167 | // Set up the metadata to be updated, after errors are no longer possible. | 168 | // Set up the metadata to be updated, after errors are no longer possible. |
| 168 | atom_placement = last.atom_index; | 169 | atom_placement = last.atom_index; |
| 169 | break :blk new_start_vaddr; | 170 | break :blk new_start_vaddr; |
| ... | @@ -192,7 +193,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { | ... | @@ -192,7 +193,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { |
| 192 | elf_file.debug_aranges_section_dirty = true; | 193 | elf_file.debug_aranges_section_dirty = true; |
| 193 | } | 194 | } |
| 194 | } | 195 | } |
| 195 | shdr.sh_addralign = @max(shdr.sh_addralign, alignment); | 196 | shdr.sh_addralign = @max(shdr.sh_addralign, self.alignment.toByteUnitsOptional().?); |
| 196 | 197 | ||
| 197 | // This function can also reallocate an atom. | 198 | // This function can also reallocate an atom. |
| 198 | // In this case we need to "unplug" it from its previous location before | 199 | // In this case we need to "unplug" it from its previous location before |
| ... | @@ -224,10 +225,8 @@ pub fn shrink(self: *Atom, elf_file: *Elf) void { | ... | @@ -224,10 +225,8 @@ pub fn shrink(self: *Atom, elf_file: *Elf) void { |
| 224 | } | 225 | } |
| 225 | 226 | ||
| 226 | pub fn grow(self: *Atom, elf_file: *Elf) !void { | 227 | pub fn grow(self: *Atom, elf_file: *Elf) !void { |
| 227 | const alignment = try std.math.powi(u64, 2, self.alignment); | 228 | if (!self.alignment.check(self.value) or self.size > self.capacity(elf_file)) |
| 228 | const align_ok = std.mem.alignBackward(u64, self.value, alignment) == self.value; | 229 | try self.allocate(elf_file); |
| 229 | const need_realloc = !align_ok or self.size > self.capacity(elf_file); | ||
| 230 | if (need_realloc) try self.allocate(elf_file); | ||
| 231 | } | 230 | } |
| 232 | 231 | ||
| 233 | pub fn free(self: *Atom, elf_file: *Elf) void { | 232 | pub fn free(self: *Atom, elf_file: *Elf) void { |
src/link/Elf/Object.zig+4-3| ... | @@ -181,10 +181,10 @@ fn addAtom(self: *Object, shdr: elf.Elf64_Shdr, shndx: u16, name: [:0]const u8, | ... | @@ -181,10 +181,10 @@ fn addAtom(self: *Object, shdr: elf.Elf64_Shdr, shndx: u16, name: [:0]const u8, |
| 181 | const data = try self.shdrContents(shndx); | 181 | const data = try self.shdrContents(shndx); |
| 182 | const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*; | 182 | const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*; |
| 183 | atom.size = chdr.ch_size; | 183 | atom.size = chdr.ch_size; |
| 184 | atom.alignment = math.log2_int(u64, chdr.ch_addralign); | 184 | atom.alignment = Alignment.fromNonzeroByteUnits(chdr.ch_addralign); |
| 185 | } else { | 185 | } else { |
| 186 | atom.size = shdr.sh_size; | 186 | atom.size = shdr.sh_size; |
| 187 | atom.alignment = math.log2_int(u64, shdr.sh_addralign); | 187 | atom.alignment = Alignment.fromNonzeroByteUnits(shdr.sh_addralign); |
| 188 | } | 188 | } |
| 189 | } | 189 | } |
| 190 | 190 | ||
| ... | @@ -571,7 +571,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void { | ... | @@ -571,7 +571,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void { |
| 571 | atom.file = self.index; | 571 | atom.file = self.index; |
| 572 | atom.size = this_sym.st_size; | 572 | atom.size = this_sym.st_size; |
| 573 | const alignment = this_sym.st_value; | 573 | const alignment = this_sym.st_value; |
| 574 | atom.alignment = math.log2_int(u64, alignment); | 574 | atom.alignment = Alignment.fromNonzeroByteUnits(alignment); |
| 575 | 575 | ||
| 576 | var sh_flags: u32 = elf.SHF_ALLOC | elf.SHF_WRITE; | 576 | var sh_flags: u32 = elf.SHF_ALLOC | elf.SHF_WRITE; |
| 577 | if (is_tls) sh_flags |= elf.SHF_TLS; | 577 | if (is_tls) sh_flags |= elf.SHF_TLS; |
| ... | @@ -870,3 +870,4 @@ const Fde = eh_frame.Fde; | ... | @@ -870,3 +870,4 @@ const Fde = eh_frame.Fde; |
| 870 | const File = @import("file.zig").File; | 870 | const File = @import("file.zig").File; |
| 871 | const StringTable = @import("../strtab.zig").StringTable; | 871 | const StringTable = @import("../strtab.zig").StringTable; |
| 872 | const Symbol = @import("Symbol.zig"); | 872 | const Symbol = @import("Symbol.zig"); |
| 873 | const Alignment = Atom.Alignment; |
src/link/MachO.zig+17-18| ... | @@ -1425,7 +1425,7 @@ pub fn allocateSpecialSymbols(self: *MachO) !void { | ... | @@ -1425,7 +1425,7 @@ pub fn allocateSpecialSymbols(self: *MachO) !void { |
| 1425 | 1425 | ||
| 1426 | const CreateAtomOpts = struct { | 1426 | const CreateAtomOpts = struct { |
| 1427 | size: u64 = 0, | 1427 | size: u64 = 0, |
| 1428 | alignment: u32 = 0, | 1428 | alignment: Alignment = .@"1", |
| 1429 | }; | 1429 | }; |
| 1430 | 1430 | ||
| 1431 | pub fn createAtom(self: *MachO, sym_index: u32, opts: CreateAtomOpts) !Atom.Index { | 1431 | pub fn createAtom(self: *MachO, sym_index: u32, opts: CreateAtomOpts) !Atom.Index { |
| ... | @@ -1473,7 +1473,7 @@ pub fn createTentativeDefAtoms(self: *MachO) !void { | ... | @@ -1473,7 +1473,7 @@ pub fn createTentativeDefAtoms(self: *MachO) !void { |
| 1473 | 1473 | ||
| 1474 | const atom_index = try self.createAtom(global.sym_index, .{ | 1474 | const atom_index = try self.createAtom(global.sym_index, .{ |
| 1475 | .size = size, | 1475 | .size = size, |
| 1476 | .alignment = alignment, | 1476 | .alignment = @enumFromInt(alignment), |
| 1477 | }); | 1477 | }); |
| 1478 | const atom = self.getAtomPtr(atom_index); | 1478 | const atom = self.getAtomPtr(atom_index); |
| 1479 | atom.file = global.file; | 1479 | atom.file = global.file; |
| ... | @@ -1493,7 +1493,7 @@ pub fn createDyldPrivateAtom(self: *MachO) !void { | ... | @@ -1493,7 +1493,7 @@ pub fn createDyldPrivateAtom(self: *MachO) !void { |
| 1493 | const sym_index = try self.allocateSymbol(); | 1493 | const sym_index = try self.allocateSymbol(); |
| 1494 | const atom_index = try self.createAtom(sym_index, .{ | 1494 | const atom_index = try self.createAtom(sym_index, .{ |
| 1495 | .size = @sizeOf(u64), | 1495 | .size = @sizeOf(u64), |
| 1496 | .alignment = 3, | 1496 | .alignment = .@"8", |
| 1497 | }); | 1497 | }); |
| 1498 | try self.atom_by_index_table.putNoClobber(self.base.allocator, sym_index, atom_index); | 1498 | try self.atom_by_index_table.putNoClobber(self.base.allocator, sym_index, atom_index); |
| 1499 | 1499 | ||
| ... | @@ -1510,7 +1510,7 @@ pub fn createDyldPrivateAtom(self: *MachO) !void { | ... | @@ -1510,7 +1510,7 @@ pub fn createDyldPrivateAtom(self: *MachO) !void { |
| 1510 | switch (self.mode) { | 1510 | switch (self.mode) { |
| 1511 | .zld => self.addAtomToSection(atom_index), | 1511 | .zld => self.addAtomToSection(atom_index), |
| 1512 | .incremental => { | 1512 | .incremental => { |
| 1513 | sym.n_value = try self.allocateAtom(atom_index, atom.size, @alignOf(u64)); | 1513 | sym.n_value = try self.allocateAtom(atom_index, atom.size, .@"8"); |
| 1514 | log.debug("allocated dyld_private atom at 0x{x}", .{sym.n_value}); | 1514 | log.debug("allocated dyld_private atom at 0x{x}", .{sym.n_value}); |
| 1515 | var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64); | 1515 | var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64); |
| 1516 | try self.writeAtom(atom_index, &buffer); | 1516 | try self.writeAtom(atom_index, &buffer); |
| ... | @@ -1521,7 +1521,7 @@ pub fn createDyldPrivateAtom(self: *MachO) !void { | ... | @@ -1521,7 +1521,7 @@ pub fn createDyldPrivateAtom(self: *MachO) !void { |
| 1521 | fn createThreadLocalDescriptorAtom(self: *MachO, sym_name: []const u8, target: SymbolWithLoc) !Atom.Index { | 1521 | fn createThreadLocalDescriptorAtom(self: *MachO, sym_name: []const u8, target: SymbolWithLoc) !Atom.Index { |
| 1522 | const gpa = self.base.allocator; | 1522 | const gpa = self.base.allocator; |
| 1523 | const size = 3 * @sizeOf(u64); | 1523 | const size = 3 * @sizeOf(u64); |
| 1524 | const required_alignment: u32 = 1; | 1524 | const required_alignment: Alignment = .@"1"; |
| 1525 | const sym_index = try self.allocateSymbol(); | 1525 | const sym_index = try self.allocateSymbol(); |
| 1526 | const atom_index = try self.createAtom(sym_index, .{}); | 1526 | const atom_index = try self.createAtom(sym_index, .{}); |
| 1527 | try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index); | 1527 | try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index); |
| ... | @@ -2030,10 +2030,10 @@ fn shrinkAtom(self: *MachO, atom_index: Atom.Index, new_block_size: u64) void { | ... | @@ -2030,10 +2030,10 @@ fn shrinkAtom(self: *MachO, atom_index: Atom.Index, new_block_size: u64) void { |
| 2030 | // capacity, insert a free list node for it. | 2030 | // capacity, insert a free list node for it. |
| 2031 | } | 2031 | } |
| 2032 | 2032 | ||
| 2033 | fn growAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignment: u64) !u64 { | 2033 | fn growAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignment: Alignment) !u64 { |
| 2034 | const atom = self.getAtom(atom_index); | 2034 | const atom = self.getAtom(atom_index); |
| 2035 | const sym = atom.getSymbol(self); | 2035 | const sym = atom.getSymbol(self); |
| 2036 | const align_ok = mem.alignBackward(u64, sym.n_value, alignment) == sym.n_value; | 2036 | const align_ok = alignment.check(sym.n_value); |
| 2037 | const need_realloc = !align_ok or new_atom_size > atom.capacity(self); | 2037 | const need_realloc = !align_ok or new_atom_size > atom.capacity(self); |
| 2038 | if (!need_realloc) return sym.n_value; | 2038 | if (!need_realloc) return sym.n_value; |
| 2039 | return self.allocateAtom(atom_index, new_atom_size, alignment); | 2039 | return self.allocateAtom(atom_index, new_atom_size, alignment); |
| ... | @@ -2350,7 +2350,7 @@ fn updateLazySymbolAtom( | ... | @@ -2350,7 +2350,7 @@ fn updateLazySymbolAtom( |
| 2350 | const gpa = self.base.allocator; | 2350 | const gpa = self.base.allocator; |
| 2351 | const mod = self.base.options.module.?; | 2351 | const mod = self.base.options.module.?; |
| 2352 | 2352 | ||
| 2353 | var required_alignment: u32 = undefined; | 2353 | var required_alignment: Alignment = .none; |
| 2354 | var code_buffer = std.ArrayList(u8).init(gpa); | 2354 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 2355 | defer code_buffer.deinit(); | 2355 | defer code_buffer.deinit(); |
| 2356 | 2356 | ||
| ... | @@ -2617,7 +2617,7 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64 | ... | @@ -2617,7 +2617,7 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64 |
| 2617 | sym.n_desc = 0; | 2617 | sym.n_desc = 0; |
| 2618 | 2618 | ||
| 2619 | const capacity = atom.capacity(self); | 2619 | const capacity = atom.capacity(self); |
| 2620 | const need_realloc = code_len > capacity or !mem.isAlignedGeneric(u64, sym.n_value, required_alignment); | 2620 | const need_realloc = code_len > capacity or !required_alignment.check(sym.n_value); |
| 2621 | 2621 | ||
| 2622 | if (need_realloc) { | 2622 | if (need_realloc) { |
| 2623 | const vaddr = try self.growAtom(atom_index, code_len, required_alignment); | 2623 | const vaddr = try self.growAtom(atom_index, code_len, required_alignment); |
| ... | @@ -3204,7 +3204,7 @@ pub fn addAtomToSection(self: *MachO, atom_index: Atom.Index) void { | ... | @@ -3204,7 +3204,7 @@ pub fn addAtomToSection(self: *MachO, atom_index: Atom.Index) void { |
| 3204 | self.sections.set(sym.n_sect - 1, section); | 3204 | self.sections.set(sym.n_sect - 1, section); |
| 3205 | } | 3205 | } |
| 3206 | 3206 | ||
| 3207 | fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignment: u64) !u64 { | 3207 | fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignment: Alignment) !u64 { |
| 3208 | const tracy = trace(@src()); | 3208 | const tracy = trace(@src()); |
| 3209 | defer tracy.end(); | 3209 | defer tracy.end(); |
| 3210 | 3210 | ||
| ... | @@ -3247,7 +3247,7 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm | ... | @@ -3247,7 +3247,7 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm |
| 3247 | const ideal_capacity_end_vaddr = math.add(u64, sym.n_value, ideal_capacity) catch ideal_capacity; | 3247 | const ideal_capacity_end_vaddr = math.add(u64, sym.n_value, ideal_capacity) catch ideal_capacity; |
| 3248 | const capacity_end_vaddr = sym.n_value + capacity; | 3248 | const capacity_end_vaddr = sym.n_value + capacity; |
| 3249 | const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity; | 3249 | const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity; |
| 3250 | const new_start_vaddr = mem.alignBackward(u64, new_start_vaddr_unaligned, alignment); | 3250 | const new_start_vaddr = alignment.backward(new_start_vaddr_unaligned); |
| 3251 | if (new_start_vaddr < ideal_capacity_end_vaddr) { | 3251 | if (new_start_vaddr < ideal_capacity_end_vaddr) { |
| 3252 | // Additional bookkeeping here to notice if this free list node | 3252 | // Additional bookkeeping here to notice if this free list node |
| 3253 | // should be deleted because the atom that it points to has grown to take up | 3253 | // should be deleted because the atom that it points to has grown to take up |
| ... | @@ -3276,11 +3276,11 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm | ... | @@ -3276,11 +3276,11 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm |
| 3276 | const last_symbol = last.getSymbol(self); | 3276 | const last_symbol = last.getSymbol(self); |
| 3277 | const ideal_capacity = if (requires_padding) padToIdeal(last.size) else last.size; | 3277 | const ideal_capacity = if (requires_padding) padToIdeal(last.size) else last.size; |
| 3278 | const ideal_capacity_end_vaddr = last_symbol.n_value + ideal_capacity; | 3278 | const ideal_capacity_end_vaddr = last_symbol.n_value + ideal_capacity; |
| 3279 | const new_start_vaddr = mem.alignForward(u64, ideal_capacity_end_vaddr, alignment); | 3279 | const new_start_vaddr = alignment.forward(ideal_capacity_end_vaddr); |
| 3280 | atom_placement = last_index; | 3280 | atom_placement = last_index; |
| 3281 | break :blk new_start_vaddr; | 3281 | break :blk new_start_vaddr; |
| 3282 | } else { | 3282 | } else { |
| 3283 | break :blk mem.alignForward(u64, segment.vmaddr, alignment); | 3283 | break :blk alignment.forward(segment.vmaddr); |
| 3284 | } | 3284 | } |
| 3285 | }; | 3285 | }; |
| 3286 | 3286 | ||
| ... | @@ -3295,10 +3295,8 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm | ... | @@ -3295,10 +3295,8 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm |
| 3295 | self.segment_table_dirty = true; | 3295 | self.segment_table_dirty = true; |
| 3296 | } | 3296 | } |
| 3297 | 3297 | ||
| 3298 | const align_pow = @as(u32, @intCast(math.log2(alignment))); | 3298 | assert(alignment != .none); |
| 3299 | if (header.@"align" < align_pow) { | 3299 | header.@"align" = @min(header.@"align", @intFromEnum(alignment)); |
| 3300 | header.@"align" = align_pow; | ||
| 3301 | } | ||
| 3302 | self.getAtomPtr(atom_index).size = new_atom_size; | 3300 | self.getAtomPtr(atom_index).size = new_atom_size; |
| 3303 | 3301 | ||
| 3304 | if (atom.prev_index) |prev_index| { | 3302 | if (atom.prev_index) |prev_index| { |
| ... | @@ -3338,7 +3336,7 @@ pub fn getGlobalSymbol(self: *MachO, name: []const u8, lib_name: ?[]const u8) !u | ... | @@ -3338,7 +3336,7 @@ pub fn getGlobalSymbol(self: *MachO, name: []const u8, lib_name: ?[]const u8) !u |
| 3338 | 3336 | ||
| 3339 | pub fn writeSegmentHeaders(self: *MachO, writer: anytype) !void { | 3337 | pub fn writeSegmentHeaders(self: *MachO, writer: anytype) !void { |
| 3340 | for (self.segments.items, 0..) |seg, i| { | 3338 | for (self.segments.items, 0..) |seg, i| { |
| 3341 | const indexes = self.getSectionIndexes(@as(u8, @intCast(i))); | 3339 | const indexes = self.getSectionIndexes(@intCast(i)); |
| 3342 | var out_seg = seg; | 3340 | var out_seg = seg; |
| 3343 | out_seg.cmdsize = @sizeOf(macho.segment_command_64); | 3341 | out_seg.cmdsize = @sizeOf(macho.segment_command_64); |
| 3344 | out_seg.nsects = 0; | 3342 | out_seg.nsects = 0; |
| ... | @@ -5526,6 +5524,7 @@ const Trie = @import("MachO/Trie.zig"); | ... | @@ -5526,6 +5524,7 @@ const Trie = @import("MachO/Trie.zig"); |
| 5526 | const Type = @import("../type.zig").Type; | 5524 | const Type = @import("../type.zig").Type; |
| 5527 | const TypedValue = @import("../TypedValue.zig"); | 5525 | const TypedValue = @import("../TypedValue.zig"); |
| 5528 | const Value = @import("../value.zig").Value; | 5526 | const Value = @import("../value.zig").Value; |
| 5527 | const Alignment = Atom.Alignment; | ||
| 5529 | 5528 | ||
| 5530 | pub const DebugSymbols = @import("MachO/DebugSymbols.zig"); | 5529 | pub const DebugSymbols = @import("MachO/DebugSymbols.zig"); |
| 5531 | pub const Bind = @import("MachO/dyld_info/bind.zig").Bind(*const MachO, SymbolWithLoc); | 5530 | pub const Bind = @import("MachO/dyld_info/bind.zig").Bind(*const MachO, SymbolWithLoc); |
src/link/MachO/Atom.zig+3-1| ... | @@ -28,13 +28,15 @@ size: u64 = 0, | ... | @@ -28,13 +28,15 @@ size: u64 = 0, |
| 28 | 28 | ||
| 29 | /// Alignment of this atom as a power of 2. | 29 | /// Alignment of this atom as a power of 2. |
| 30 | /// For instance, aligmment of 0 should be read as 2^0 = 1 byte aligned. | 30 | /// For instance, aligmment of 0 should be read as 2^0 = 1 byte aligned. |
| 31 | alignment: u32 = 0, | 31 | alignment: Alignment = .@"1", |
| 32 | 32 | ||
| 33 | /// Points to the previous and next neighbours | 33 | /// Points to the previous and next neighbours |
| 34 | /// TODO use the same trick as with symbols: reserve index 0 as null atom | 34 | /// TODO use the same trick as with symbols: reserve index 0 as null atom |
| 35 | next_index: ?Index = null, | 35 | next_index: ?Index = null, |
| 36 | prev_index: ?Index = null, | 36 | prev_index: ?Index = null, |
| 37 | 37 | ||
| 38 | pub const Alignment = @import("../../InternPool.zig").Alignment; | ||
| 39 | |||
| 38 | pub const Index = u32; | 40 | pub const Index = u32; |
| 39 | 41 | ||
| 40 | pub const Binding = struct { | 42 | pub const Binding = struct { |
src/link/MachO/Object.zig+12-8| ... | @@ -382,7 +382,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) ! | ... | @@ -382,7 +382,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) ! |
| 382 | const out_sect_id = (try Atom.getOutputSection(macho_file, sect)) orelse continue; | 382 | const out_sect_id = (try Atom.getOutputSection(macho_file, sect)) orelse continue; |
| 383 | if (sect.size == 0) continue; | 383 | if (sect.size == 0) continue; |
| 384 | 384 | ||
| 385 | const sect_id = @as(u8, @intCast(id)); | 385 | const sect_id: u8 = @intCast(id); |
| 386 | const sym_index = self.getSectionAliasSymbolIndex(sect_id); | 386 | const sym_index = self.getSectionAliasSymbolIndex(sect_id); |
| 387 | const atom_index = try self.createAtomFromSubsection( | 387 | const atom_index = try self.createAtomFromSubsection( |
| 388 | macho_file, | 388 | macho_file, |
| ... | @@ -391,7 +391,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) ! | ... | @@ -391,7 +391,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) ! |
| 391 | sym_index, | 391 | sym_index, |
| 392 | 1, | 392 | 1, |
| 393 | sect.size, | 393 | sect.size, |
| 394 | sect.@"align", | 394 | Alignment.fromLog2Units(sect.@"align"), |
| 395 | out_sect_id, | 395 | out_sect_id, |
| 396 | ); | 396 | ); |
| 397 | macho_file.addAtomToSection(atom_index); | 397 | macho_file.addAtomToSection(atom_index); |
| ... | @@ -470,7 +470,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) ! | ... | @@ -470,7 +470,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) ! |
| 470 | sym_index, | 470 | sym_index, |
| 471 | 1, | 471 | 1, |
| 472 | atom_size, | 472 | atom_size, |
| 473 | sect.@"align", | 473 | Alignment.fromLog2Units(sect.@"align"), |
| 474 | out_sect_id, | 474 | out_sect_id, |
| 475 | ); | 475 | ); |
| 476 | if (!sect.isZerofill()) { | 476 | if (!sect.isZerofill()) { |
| ... | @@ -494,10 +494,10 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) ! | ... | @@ -494,10 +494,10 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) ! |
| 494 | else | 494 | else |
| 495 | sect.addr + sect.size - addr; | 495 | sect.addr + sect.size - addr; |
| 496 | 496 | ||
| 497 | const atom_align = if (addr > 0) | 497 | const atom_align = Alignment.fromLog2Units(if (addr > 0) |
| 498 | @min(@ctz(addr), sect.@"align") | 498 | @min(@ctz(addr), sect.@"align") |
| 499 | else | 499 | else |
| 500 | sect.@"align"; | 500 | sect.@"align"); |
| 501 | 501 | ||
| 502 | const atom_index = try self.createAtomFromSubsection( | 502 | const atom_index = try self.createAtomFromSubsection( |
| 503 | macho_file, | 503 | macho_file, |
| ... | @@ -532,7 +532,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) ! | ... | @@ -532,7 +532,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) ! |
| 532 | sect_start_index, | 532 | sect_start_index, |
| 533 | sect_loc.len, | 533 | sect_loc.len, |
| 534 | sect.size, | 534 | sect.size, |
| 535 | sect.@"align", | 535 | Alignment.fromLog2Units(sect.@"align"), |
| 536 | out_sect_id, | 536 | out_sect_id, |
| 537 | ); | 537 | ); |
| 538 | if (!sect.isZerofill()) { | 538 | if (!sect.isZerofill()) { |
| ... | @@ -551,11 +551,14 @@ fn createAtomFromSubsection( | ... | @@ -551,11 +551,14 @@ fn createAtomFromSubsection( |
| 551 | inner_sym_index: u32, | 551 | inner_sym_index: u32, |
| 552 | inner_nsyms_trailing: u32, | 552 | inner_nsyms_trailing: u32, |
| 553 | size: u64, | 553 | size: u64, |
| 554 | alignment: u32, | 554 | alignment: Alignment, |
| 555 | out_sect_id: u8, | 555 | out_sect_id: u8, |
| 556 | ) !Atom.Index { | 556 | ) !Atom.Index { |
| 557 | const gpa = macho_file.base.allocator; | 557 | const gpa = macho_file.base.allocator; |
| 558 | const atom_index = try macho_file.createAtom(sym_index, .{ .size = size, .alignment = alignment }); | 558 | const atom_index = try macho_file.createAtom(sym_index, .{ |
| 559 | .size = size, | ||
| 560 | .alignment = alignment, | ||
| 561 | }); | ||
| 559 | const atom = macho_file.getAtomPtr(atom_index); | 562 | const atom = macho_file.getAtomPtr(atom_index); |
| 560 | atom.inner_sym_index = inner_sym_index; | 563 | atom.inner_sym_index = inner_sym_index; |
| 561 | atom.inner_nsyms_trailing = inner_nsyms_trailing; | 564 | atom.inner_nsyms_trailing = inner_nsyms_trailing; |
| ... | @@ -1115,3 +1118,4 @@ const MachO = @import("../MachO.zig"); | ... | @@ -1115,3 +1118,4 @@ const MachO = @import("../MachO.zig"); |
| 1115 | const Platform = @import("load_commands.zig").Platform; | 1118 | const Platform = @import("load_commands.zig").Platform; |
| 1116 | const SymbolWithLoc = MachO.SymbolWithLoc; | 1119 | const SymbolWithLoc = MachO.SymbolWithLoc; |
| 1117 | const UnwindInfo = @import("UnwindInfo.zig"); | 1120 | const UnwindInfo = @import("UnwindInfo.zig"); |
| 1121 | const Alignment = Atom.Alignment; |
src/link/MachO/thunks.zig+7-4| ... | @@ -104,7 +104,7 @@ pub fn createThunks(macho_file: *MachO, sect_id: u8) !void { | ... | @@ -104,7 +104,7 @@ pub fn createThunks(macho_file: *MachO, sect_id: u8) !void { |
| 104 | 104 | ||
| 105 | while (true) { | 105 | while (true) { |
| 106 | const atom = macho_file.getAtom(group_end); | 106 | const atom = macho_file.getAtom(group_end); |
| 107 | offset = mem.alignForward(u64, offset, try math.powi(u32, 2, atom.alignment)); | 107 | offset = atom.alignment.forward(offset); |
| 108 | 108 | ||
| 109 | const sym = macho_file.getSymbolPtr(atom.getSymbolWithLoc()); | 109 | const sym = macho_file.getSymbolPtr(atom.getSymbolWithLoc()); |
| 110 | sym.n_value = offset; | 110 | sym.n_value = offset; |
| ... | @@ -112,7 +112,7 @@ pub fn createThunks(macho_file: *MachO, sect_id: u8) !void { | ... | @@ -112,7 +112,7 @@ pub fn createThunks(macho_file: *MachO, sect_id: u8) !void { |
| 112 | 112 | ||
| 113 | macho_file.logAtom(group_end, log); | 113 | macho_file.logAtom(group_end, log); |
| 114 | 114 | ||
| 115 | header.@"align" = @max(header.@"align", atom.alignment); | 115 | header.@"align" = @max(header.@"align", atom.alignment.toLog2Units()); |
| 116 | 116 | ||
| 117 | allocated.putAssumeCapacityNoClobber(group_end, {}); | 117 | allocated.putAssumeCapacityNoClobber(group_end, {}); |
| 118 | 118 | ||
| ... | @@ -196,7 +196,7 @@ fn allocateThunk( | ... | @@ -196,7 +196,7 @@ fn allocateThunk( |
| 196 | 196 | ||
| 197 | macho_file.logAtom(atom_index, log); | 197 | macho_file.logAtom(atom_index, log); |
| 198 | 198 | ||
| 199 | header.@"align" = @max(header.@"align", atom.alignment); | 199 | header.@"align" = @max(header.@"align", atom.alignment.toLog2Units()); |
| 200 | 200 | ||
| 201 | if (end_atom_index == atom_index) break; | 201 | if (end_atom_index == atom_index) break; |
| 202 | 202 | ||
| ... | @@ -326,7 +326,10 @@ fn isReachable( | ... | @@ -326,7 +326,10 @@ fn isReachable( |
| 326 | 326 | ||
| 327 | fn createThunkAtom(macho_file: *MachO) !Atom.Index { | 327 | fn createThunkAtom(macho_file: *MachO) !Atom.Index { |
| 328 | const sym_index = try macho_file.allocateSymbol(); | 328 | const sym_index = try macho_file.allocateSymbol(); |
| 329 | const atom_index = try macho_file.createAtom(sym_index, .{ .size = @sizeOf(u32) * 3, .alignment = 2 }); | 329 | const atom_index = try macho_file.createAtom(sym_index, .{ |
| 330 | .size = @sizeOf(u32) * 3, | ||
| 331 | .alignment = .@"4", | ||
| 332 | }); | ||
| 330 | const sym = macho_file.getSymbolPtr(.{ .sym_index = sym_index }); | 333 | const sym = macho_file.getSymbolPtr(.{ .sym_index = sym_index }); |
| 331 | sym.n_type = macho.N_SECT; | 334 | sym.n_type = macho.N_SECT; |
| 332 | sym.n_sect = macho_file.text_section_index.? + 1; | 335 | sym.n_sect = macho_file.text_section_index.? + 1; |
src/link/MachO/zld.zig+3-6| ... | @@ -985,19 +985,16 @@ fn calcSectionSizes(macho_file: *MachO) !void { | ... | @@ -985,19 +985,16 @@ fn calcSectionSizes(macho_file: *MachO) !void { |
| 985 | 985 | ||
| 986 | while (true) { | 986 | while (true) { |
| 987 | const atom = macho_file.getAtom(atom_index); | 987 | const atom = macho_file.getAtom(atom_index); |
| 988 | const atom_alignment = try math.powi(u32, 2, atom.alignment); | 988 | const atom_offset = atom.alignment.forward(header.size); |
| 989 | const atom_offset = mem.alignForward(u64, header.size, atom_alignment); | ||
| 990 | const padding = atom_offset - header.size; | 989 | const padding = atom_offset - header.size; |
| 991 | 990 | ||
| 992 | const sym = macho_file.getSymbolPtr(atom.getSymbolWithLoc()); | 991 | const sym = macho_file.getSymbolPtr(atom.getSymbolWithLoc()); |
| 993 | sym.n_value = atom_offset; | 992 | sym.n_value = atom_offset; |
| 994 | 993 | ||
| 995 | header.size += padding + atom.size; | 994 | header.size += padding + atom.size; |
| 996 | header.@"align" = @max(header.@"align", atom.alignment); | 995 | header.@"align" = @max(header.@"align", atom.alignment.toLog2Units()); |
| 997 | 996 | ||
| 998 | if (atom.next_index) |next_index| { | 997 | atom_index = atom.next_index orelse break; |
| 999 | atom_index = next_index; | ||
| 1000 | } else break; | ||
| 1001 | } | 998 | } |
| 1002 | } | 999 | } |
| 1003 | 1000 |
src/link/Plan9.zig+1-1| ... | @@ -1106,7 +1106,7 @@ fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Ind | ... | @@ -1106,7 +1106,7 @@ fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Ind |
| 1106 | const gpa = self.base.allocator; | 1106 | const gpa = self.base.allocator; |
| 1107 | const mod = self.base.options.module.?; | 1107 | const mod = self.base.options.module.?; |
| 1108 | 1108 | ||
| 1109 | var required_alignment: u32 = undefined; | 1109 | var required_alignment: InternPool.Alignment = .none; |
| 1110 | var code_buffer = std.ArrayList(u8).init(gpa); | 1110 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 1111 | defer code_buffer.deinit(); | 1111 | defer code_buffer.deinit(); |
| 1112 | 1112 |
src/link/Wasm.zig+23-21| ... | @@ -187,8 +187,10 @@ debug_pubtypes_atom: ?Atom.Index = null, | ... | @@ -187,8 +187,10 @@ debug_pubtypes_atom: ?Atom.Index = null, |
| 187 | /// rather than by the linker. | 187 | /// rather than by the linker. |
| 188 | synthetic_functions: std.ArrayListUnmanaged(Atom.Index) = .{}, | 188 | synthetic_functions: std.ArrayListUnmanaged(Atom.Index) = .{}, |
| 189 | 189 | ||
| 190 | pub const Alignment = types.Alignment; | ||
| 191 | |||
| 190 | pub const Segment = struct { | 192 | pub const Segment = struct { |
| 191 | alignment: u32, | 193 | alignment: Alignment, |
| 192 | size: u32, | 194 | size: u32, |
| 193 | offset: u32, | 195 | offset: u32, |
| 194 | flags: u32, | 196 | flags: u32, |
| ... | @@ -1490,7 +1492,7 @@ fn finishUpdateDecl(wasm: *Wasm, decl_index: Module.Decl.Index, code: []const u8 | ... | @@ -1490,7 +1492,7 @@ fn finishUpdateDecl(wasm: *Wasm, decl_index: Module.Decl.Index, code: []const u8 |
| 1490 | try atom.code.appendSlice(wasm.base.allocator, code); | 1492 | try atom.code.appendSlice(wasm.base.allocator, code); |
| 1491 | try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {}); | 1493 | try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {}); |
| 1492 | 1494 | ||
| 1493 | atom.size = @as(u32, @intCast(code.len)); | 1495 | atom.size = @intCast(code.len); |
| 1494 | if (code.len == 0) return; | 1496 | if (code.len == 0) return; |
| 1495 | atom.alignment = decl.getAlignment(mod); | 1497 | atom.alignment = decl.getAlignment(mod); |
| 1496 | } | 1498 | } |
| ... | @@ -2050,7 +2052,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { | ... | @@ -2050,7 +2052,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { |
| 2050 | }; | 2052 | }; |
| 2051 | 2053 | ||
| 2052 | const segment: *Segment = &wasm.segments.items[final_index]; | 2054 | const segment: *Segment = &wasm.segments.items[final_index]; |
| 2053 | segment.alignment = @max(segment.alignment, atom.alignment); | 2055 | segment.alignment = segment.alignment.max(atom.alignment); |
| 2054 | 2056 | ||
| 2055 | try wasm.appendAtomAtIndex(final_index, atom_index); | 2057 | try wasm.appendAtomAtIndex(final_index, atom_index); |
| 2056 | } | 2058 | } |
| ... | @@ -2121,7 +2123,7 @@ fn allocateAtoms(wasm: *Wasm) !void { | ... | @@ -2121,7 +2123,7 @@ fn allocateAtoms(wasm: *Wasm) !void { |
| 2121 | } | 2123 | } |
| 2122 | } | 2124 | } |
| 2123 | } | 2125 | } |
| 2124 | offset = std.mem.alignForward(u32, offset, atom.alignment); | 2126 | offset = @intCast(atom.alignment.forward(offset)); |
| 2125 | atom.offset = offset; | 2127 | atom.offset = offset; |
| 2126 | log.debug("Atom '{s}' allocated from 0x{x:0>8} to 0x{x:0>8} size={d}", .{ | 2128 | log.debug("Atom '{s}' allocated from 0x{x:0>8} to 0x{x:0>8} size={d}", .{ |
| 2127 | symbol_loc.getName(wasm), | 2129 | symbol_loc.getName(wasm), |
| ... | @@ -2132,7 +2134,7 @@ fn allocateAtoms(wasm: *Wasm) !void { | ... | @@ -2132,7 +2134,7 @@ fn allocateAtoms(wasm: *Wasm) !void { |
| 2132 | offset += atom.size; | 2134 | offset += atom.size; |
| 2133 | atom_index = atom.prev orelse break; | 2135 | atom_index = atom.prev orelse break; |
| 2134 | } | 2136 | } |
| 2135 | segment.size = std.mem.alignForward(u32, offset, segment.alignment); | 2137 | segment.size = @intCast(segment.alignment.forward(offset)); |
| 2136 | } | 2138 | } |
| 2137 | } | 2139 | } |
| 2138 | 2140 | ||
| ... | @@ -2351,7 +2353,7 @@ fn createSyntheticFunction( | ... | @@ -2351,7 +2353,7 @@ fn createSyntheticFunction( |
| 2351 | .offset = 0, | 2353 | .offset = 0, |
| 2352 | .sym_index = loc.index, | 2354 | .sym_index = loc.index, |
| 2353 | .file = null, | 2355 | .file = null, |
| 2354 | .alignment = 1, | 2356 | .alignment = .@"1", |
| 2355 | .next = null, | 2357 | .next = null, |
| 2356 | .prev = null, | 2358 | .prev = null, |
| 2357 | .code = function_body.moveToUnmanaged(), | 2359 | .code = function_body.moveToUnmanaged(), |
| ... | @@ -2382,11 +2384,11 @@ pub fn createFunction( | ... | @@ -2382,11 +2384,11 @@ pub fn createFunction( |
| 2382 | const atom_index = @as(Atom.Index, @intCast(wasm.managed_atoms.items.len)); | 2384 | const atom_index = @as(Atom.Index, @intCast(wasm.managed_atoms.items.len)); |
| 2383 | const atom = try wasm.managed_atoms.addOne(wasm.base.allocator); | 2385 | const atom = try wasm.managed_atoms.addOne(wasm.base.allocator); |
| 2384 | atom.* = .{ | 2386 | atom.* = .{ |
| 2385 | .size = @as(u32, @intCast(function_body.items.len)), | 2387 | .size = @intCast(function_body.items.len), |
| 2386 | .offset = 0, | 2388 | .offset = 0, |
| 2387 | .sym_index = loc.index, | 2389 | .sym_index = loc.index, |
| 2388 | .file = null, | 2390 | .file = null, |
| 2389 | .alignment = 1, | 2391 | .alignment = .@"1", |
| 2390 | .next = null, | 2392 | .next = null, |
| 2391 | .prev = null, | 2393 | .prev = null, |
| 2392 | .code = function_body.moveToUnmanaged(), | 2394 | .code = function_body.moveToUnmanaged(), |
| ... | @@ -2734,8 +2736,8 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2734,8 +2736,8 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2734 | const page_size = std.wasm.page_size; // 64kb | 2736 | const page_size = std.wasm.page_size; // 64kb |
| 2735 | // Use the user-provided stack size or else we use 1MB by default | 2737 | // Use the user-provided stack size or else we use 1MB by default |
| 2736 | const stack_size = wasm.base.options.stack_size_override orelse page_size * 16; | 2738 | const stack_size = wasm.base.options.stack_size_override orelse page_size * 16; |
| 2737 | const stack_alignment = 16; // wasm's stack alignment as specified by tool-convention | 2739 | const stack_alignment: Alignment = .@"16"; // wasm's stack alignment as specified by tool-convention |
| 2738 | const heap_alignment = 16; // wasm's heap alignment as specified by tool-convention | 2740 | const heap_alignment: Alignment = .@"16"; // wasm's heap alignment as specified by tool-convention |
| 2739 | 2741 | ||
| 2740 | // Always place the stack at the start by default | 2742 | // Always place the stack at the start by default |
| 2741 | // unless the user specified the global-base flag | 2743 | // unless the user specified the global-base flag |
| ... | @@ -2748,7 +2750,7 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2748,7 +2750,7 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2748 | const is_obj = wasm.base.options.output_mode == .Obj; | 2750 | const is_obj = wasm.base.options.output_mode == .Obj; |
| 2749 | 2751 | ||
| 2750 | if (place_stack_first and !is_obj) { | 2752 | if (place_stack_first and !is_obj) { |
| 2751 | memory_ptr = std.mem.alignForward(u64, memory_ptr, stack_alignment); | 2753 | memory_ptr = stack_alignment.forward(memory_ptr); |
| 2752 | memory_ptr += stack_size; | 2754 | memory_ptr += stack_size; |
| 2753 | // We always put the stack pointer global at index 0 | 2755 | // We always put the stack pointer global at index 0 |
| 2754 | wasm.wasm_globals.items[0].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr)))); | 2756 | wasm.wasm_globals.items[0].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr)))); |
| ... | @@ -2758,7 +2760,7 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2758,7 +2760,7 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2758 | var data_seg_it = wasm.data_segments.iterator(); | 2760 | var data_seg_it = wasm.data_segments.iterator(); |
| 2759 | while (data_seg_it.next()) |entry| { | 2761 | while (data_seg_it.next()) |entry| { |
| 2760 | const segment = &wasm.segments.items[entry.value_ptr.*]; | 2762 | const segment = &wasm.segments.items[entry.value_ptr.*]; |
| 2761 | memory_ptr = std.mem.alignForward(u64, memory_ptr, segment.alignment); | 2763 | memory_ptr = segment.alignment.forward(memory_ptr); |
| 2762 | 2764 | ||
| 2763 | // set TLS-related symbols | 2765 | // set TLS-related symbols |
| 2764 | if (mem.eql(u8, entry.key_ptr.*, ".tdata")) { | 2766 | if (mem.eql(u8, entry.key_ptr.*, ".tdata")) { |
| ... | @@ -2768,7 +2770,7 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2768,7 +2770,7 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2768 | } | 2770 | } |
| 2769 | if (wasm.findGlobalSymbol("__tls_align")) |loc| { | 2771 | if (wasm.findGlobalSymbol("__tls_align")) |loc| { |
| 2770 | const sym = loc.getSymbol(wasm); | 2772 | const sym = loc.getSymbol(wasm); |
| 2771 | wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.alignment); | 2773 | wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.alignment.toByteUnitsOptional().?); |
| 2772 | } | 2774 | } |
| 2773 | if (wasm.findGlobalSymbol("__tls_base")) |loc| { | 2775 | if (wasm.findGlobalSymbol("__tls_base")) |loc| { |
| 2774 | const sym = loc.getSymbol(wasm); | 2776 | const sym = loc.getSymbol(wasm); |
| ... | @@ -2795,7 +2797,7 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2795,7 +2797,7 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2795 | } | 2797 | } |
| 2796 | 2798 | ||
| 2797 | if (!place_stack_first and !is_obj) { | 2799 | if (!place_stack_first and !is_obj) { |
| 2798 | memory_ptr = std.mem.alignForward(u64, memory_ptr, stack_alignment); | 2800 | memory_ptr = stack_alignment.forward(memory_ptr); |
| 2799 | memory_ptr += stack_size; | 2801 | memory_ptr += stack_size; |
| 2800 | wasm.wasm_globals.items[0].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr)))); | 2802 | wasm.wasm_globals.items[0].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr)))); |
| 2801 | } | 2803 | } |
| ... | @@ -2804,7 +2806,7 @@ fn setupMemory(wasm: *Wasm) !void { | ... | @@ -2804,7 +2806,7 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2804 | // We must set its virtual address so it can be used in relocations. | 2806 | // We must set its virtual address so it can be used in relocations. |
| 2805 | if (wasm.findGlobalSymbol("__heap_base")) |loc| { | 2807 | if (wasm.findGlobalSymbol("__heap_base")) |loc| { |
| 2806 | const symbol = loc.getSymbol(wasm); | 2808 | const symbol = loc.getSymbol(wasm); |
| 2807 | symbol.virtual_address = @as(u32, @intCast(mem.alignForward(u64, memory_ptr, heap_alignment))); | 2809 | symbol.virtual_address = @intCast(heap_alignment.forward(memory_ptr)); |
| 2808 | } | 2810 | } |
| 2809 | 2811 | ||
| 2810 | // Setup the max amount of pages | 2812 | // Setup the max amount of pages |
| ... | @@ -2879,7 +2881,7 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32 | ... | @@ -2879,7 +2881,7 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32 |
| 2879 | flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE); | 2881 | flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE); |
| 2880 | } | 2882 | } |
| 2881 | try wasm.segments.append(wasm.base.allocator, .{ | 2883 | try wasm.segments.append(wasm.base.allocator, .{ |
| 2882 | .alignment = 1, | 2884 | .alignment = .@"1", |
| 2883 | .size = 0, | 2885 | .size = 0, |
| 2884 | .offset = 0, | 2886 | .offset = 0, |
| 2885 | .flags = flags, | 2887 | .flags = flags, |
| ... | @@ -2954,7 +2956,7 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32 | ... | @@ -2954,7 +2956,7 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32 |
| 2954 | /// Appends a new segment with default field values | 2956 | /// Appends a new segment with default field values |
| 2955 | fn appendDummySegment(wasm: *Wasm) !void { | 2957 | fn appendDummySegment(wasm: *Wasm) !void { |
| 2956 | try wasm.segments.append(wasm.base.allocator, .{ | 2958 | try wasm.segments.append(wasm.base.allocator, .{ |
| 2957 | .alignment = 1, | 2959 | .alignment = .@"1", |
| 2958 | .size = 0, | 2960 | .size = 0, |
| 2959 | .offset = 0, | 2961 | .offset = 0, |
| 2960 | .flags = 0, | 2962 | .flags = 0, |
| ... | @@ -3011,7 +3013,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void { | ... | @@ -3011,7 +3013,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void { |
| 3011 | // the pointers into the list using addends which are appended to the relocation. | 3013 | // the pointers into the list using addends which are appended to the relocation. |
| 3012 | const names_atom_index = try wasm.createAtom(); | 3014 | const names_atom_index = try wasm.createAtom(); |
| 3013 | const names_atom = wasm.getAtomPtr(names_atom_index); | 3015 | const names_atom = wasm.getAtomPtr(names_atom_index); |
| 3014 | names_atom.alignment = 1; | 3016 | names_atom.alignment = .@"1"; |
| 3015 | const sym_name = try wasm.string_table.put(wasm.base.allocator, "__zig_err_names"); | 3017 | const sym_name = try wasm.string_table.put(wasm.base.allocator, "__zig_err_names"); |
| 3016 | const names_symbol = &wasm.symbols.items[names_atom.sym_index]; | 3018 | const names_symbol = &wasm.symbols.items[names_atom.sym_index]; |
| 3017 | names_symbol.* = .{ | 3019 | names_symbol.* = .{ |
| ... | @@ -3085,7 +3087,7 @@ pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) ! | ... | @@ -3085,7 +3087,7 @@ pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) ! |
| 3085 | .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL), | 3087 | .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL), |
| 3086 | }; | 3088 | }; |
| 3087 | 3089 | ||
| 3088 | atom.alignment = 1; // debug sections are always 1-byte-aligned | 3090 | atom.alignment = .@"1"; // debug sections are always 1-byte-aligned |
| 3089 | return atom_index; | 3091 | return atom_index; |
| 3090 | } | 3092 | } |
| 3091 | 3093 | ||
| ... | @@ -4724,12 +4726,12 @@ fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.ArrayList(u8)) !void { | ... | @@ -4724,12 +4726,12 @@ fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.ArrayList(u8)) !void { |
| 4724 | for (wasm.segment_info.values()) |segment_info| { | 4726 | for (wasm.segment_info.values()) |segment_info| { |
| 4725 | log.debug("Emit segment: {s} align({d}) flags({b})", .{ | 4727 | log.debug("Emit segment: {s} align({d}) flags({b})", .{ |
| 4726 | segment_info.name, | 4728 | segment_info.name, |
| 4727 | @ctz(segment_info.alignment), | 4729 | segment_info.alignment, |
| 4728 | segment_info.flags, | 4730 | segment_info.flags, |
| 4729 | }); | 4731 | }); |
| 4730 | try leb.writeULEB128(writer, @as(u32, @intCast(segment_info.name.len))); | 4732 | try leb.writeULEB128(writer, @as(u32, @intCast(segment_info.name.len))); |
| 4731 | try writer.writeAll(segment_info.name); | 4733 | try writer.writeAll(segment_info.name); |
| 4732 | try leb.writeULEB128(writer, @ctz(segment_info.alignment)); | 4734 | try leb.writeULEB128(writer, segment_info.alignment.toLog2Units()); |
| 4733 | try leb.writeULEB128(writer, segment_info.flags); | 4735 | try leb.writeULEB128(writer, segment_info.flags); |
| 4734 | } | 4736 | } |
| 4735 | 4737 |
src/link/Wasm/Atom.zig+2-2| ... | @@ -19,7 +19,7 @@ relocs: std.ArrayListUnmanaged(types.Relocation) = .{}, | ... | @@ -19,7 +19,7 @@ relocs: std.ArrayListUnmanaged(types.Relocation) = .{}, |
| 19 | /// Contains the binary data of an atom, which can be non-relocated | 19 | /// Contains the binary data of an atom, which can be non-relocated |
| 20 | code: std.ArrayListUnmanaged(u8) = .{}, | 20 | code: std.ArrayListUnmanaged(u8) = .{}, |
| 21 | /// For code this is 1, for data this is set to the highest value of all segments | 21 | /// For code this is 1, for data this is set to the highest value of all segments |
| 22 | alignment: u32, | 22 | alignment: Wasm.Alignment, |
| 23 | /// Offset into the section where the atom lives, this already accounts | 23 | /// Offset into the section where the atom lives, this already accounts |
| 24 | /// for alignment. | 24 | /// for alignment. |
| 25 | offset: u32, | 25 | offset: u32, |
| ... | @@ -43,7 +43,7 @@ pub const Index = u32; | ... | @@ -43,7 +43,7 @@ pub const Index = u32; |
| 43 | 43 | ||
| 44 | /// Represents a default empty wasm `Atom` | 44 | /// Represents a default empty wasm `Atom` |
| 45 | pub const empty: Atom = .{ | 45 | pub const empty: Atom = .{ |
| 46 | .alignment = 1, | 46 | .alignment = .@"1", |
| 47 | .file = null, | 47 | .file = null, |
| 48 | .next = null, | 48 | .next = null, |
| 49 | .offset = 0, | 49 | .offset = 0, |
src/link/Wasm/Object.zig+7-9| ... | @@ -8,6 +8,7 @@ const types = @import("types.zig"); | ... | @@ -8,6 +8,7 @@ const types = @import("types.zig"); |
| 8 | const std = @import("std"); | 8 | const std = @import("std"); |
| 9 | const Wasm = @import("../Wasm.zig"); | 9 | const Wasm = @import("../Wasm.zig"); |
| 10 | const Symbol = @import("Symbol.zig"); | 10 | const Symbol = @import("Symbol.zig"); |
| 11 | const Alignment = types.Alignment; | ||
| 11 | 12 | ||
| 12 | const Allocator = std.mem.Allocator; | 13 | const Allocator = std.mem.Allocator; |
| 13 | const leb = std.leb; | 14 | const leb = std.leb; |
| ... | @@ -88,12 +89,9 @@ const RelocatableData = struct { | ... | @@ -88,12 +89,9 @@ const RelocatableData = struct { |
| 88 | /// meta data of the given object file. | 89 | /// meta data of the given object file. |
| 89 | /// NOTE: Alignment is encoded as a power of 2, so we shift the symbol's | 90 | /// NOTE: Alignment is encoded as a power of 2, so we shift the symbol's |
| 90 | /// alignment to retrieve the natural alignment. | 91 | /// alignment to retrieve the natural alignment. |
| 91 | pub fn getAlignment(relocatable_data: RelocatableData, object: *const Object) u32 { | 92 | pub fn getAlignment(relocatable_data: RelocatableData, object: *const Object) Alignment { |
| 92 | if (relocatable_data.type != .data) return 1; | 93 | if (relocatable_data.type != .data) return .@"1"; |
| 93 | const data_alignment = object.segment_info[relocatable_data.index].alignment; | 94 | return object.segment_info[relocatable_data.index].alignment; |
| 94 | if (data_alignment == 0) return 1; | ||
| 95 | // Decode from power of 2 to natural alignment | ||
| 96 | return @as(u32, 1) << @as(u5, @intCast(data_alignment)); | ||
| 97 | } | 95 | } |
| 98 | 96 | ||
| 99 | /// Returns the symbol kind that corresponds to the relocatable section | 97 | /// Returns the symbol kind that corresponds to the relocatable section |
| ... | @@ -671,7 +669,7 @@ fn Parser(comptime ReaderType: type) type { | ... | @@ -671,7 +669,7 @@ fn Parser(comptime ReaderType: type) type { |
| 671 | try reader.readNoEof(name); | 669 | try reader.readNoEof(name); |
| 672 | segment.* = .{ | 670 | segment.* = .{ |
| 673 | .name = name, | 671 | .name = name, |
| 674 | .alignment = try leb.readULEB128(u32, reader), | 672 | .alignment = @enumFromInt(try leb.readULEB128(u32, reader)), |
| 675 | .flags = try leb.readULEB128(u32, reader), | 673 | .flags = try leb.readULEB128(u32, reader), |
| 676 | }; | 674 | }; |
| 677 | log.debug("Found segment: {s} align({d}) flags({b})", .{ | 675 | log.debug("Found segment: {s} align({d}) flags({b})", .{ |
| ... | @@ -919,7 +917,7 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b | ... | @@ -919,7 +917,7 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b |
| 919 | continue; // found unknown section, so skip parsing into atom as we do not know how to handle it. | 917 | continue; // found unknown section, so skip parsing into atom as we do not know how to handle it. |
| 920 | }; | 918 | }; |
| 921 | 919 | ||
| 922 | const atom_index = @as(Atom.Index, @intCast(wasm_bin.managed_atoms.items.len)); | 920 | const atom_index: Atom.Index = @intCast(wasm_bin.managed_atoms.items.len); |
| 923 | const atom = try wasm_bin.managed_atoms.addOne(gpa); | 921 | const atom = try wasm_bin.managed_atoms.addOne(gpa); |
| 924 | atom.* = Atom.empty; | 922 | atom.* = Atom.empty; |
| 925 | atom.file = object_index; | 923 | atom.file = object_index; |
| ... | @@ -984,7 +982,7 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b | ... | @@ -984,7 +982,7 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b |
| 984 | 982 | ||
| 985 | const segment: *Wasm.Segment = &wasm_bin.segments.items[final_index]; | 983 | const segment: *Wasm.Segment = &wasm_bin.segments.items[final_index]; |
| 986 | if (relocatable_data.type == .data) { //code section and debug sections are 1-byte aligned | 984 | if (relocatable_data.type == .data) { //code section and debug sections are 1-byte aligned |
| 987 | segment.alignment = @max(segment.alignment, atom.alignment); | 985 | segment.alignment = segment.alignment.max(atom.alignment); |
| 988 | } | 986 | } |
| 989 | 987 | ||
| 990 | try wasm_bin.appendAtomAtIndex(final_index, atom_index); | 988 | try wasm_bin.appendAtomAtIndex(final_index, atom_index); |
src/link/Wasm/types.zig+3-1| ... | @@ -109,11 +109,13 @@ pub const SubsectionType = enum(u8) { | ... | @@ -109,11 +109,13 @@ pub const SubsectionType = enum(u8) { |
| 109 | WASM_SYMBOL_TABLE = 8, | 109 | WASM_SYMBOL_TABLE = 8, |
| 110 | }; | 110 | }; |
| 111 | 111 | ||
| 112 | pub const Alignment = @import("../../InternPool.zig").Alignment; | ||
| 113 | |||
| 112 | pub const Segment = struct { | 114 | pub const Segment = struct { |
| 113 | /// Segment's name, encoded as UTF-8 bytes. | 115 | /// Segment's name, encoded as UTF-8 bytes. |
| 114 | name: []const u8, | 116 | name: []const u8, |
| 115 | /// The required alignment of the segment, encoded as a power of 2 | 117 | /// The required alignment of the segment, encoded as a power of 2 |
| 116 | alignment: u32, | 118 | alignment: Alignment, |
| 117 | /// Bitfield containing flags for a segment | 119 | /// Bitfield containing flags for a segment |
| 118 | flags: u32, | 120 | flags: u32, |
| 119 | 121 |
src/target.zig+7-6| ... | @@ -1,6 +1,7 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const Type = @import("type.zig").Type; | 2 | const Type = @import("type.zig").Type; |
| 3 | const AddressSpace = std.builtin.AddressSpace; | 3 | const AddressSpace = std.builtin.AddressSpace; |
| 4 | const Alignment = @import("InternPool.zig").Alignment; | ||
| 4 | 5 | ||
| 5 | pub const ArchOsAbi = struct { | 6 | pub const ArchOsAbi = struct { |
| 6 | arch: std.Target.Cpu.Arch, | 7 | arch: std.Target.Cpu.Arch, |
| ... | @@ -595,13 +596,13 @@ pub fn llvmMachineAbi(target: std.Target) ?[:0]const u8 { | ... | @@ -595,13 +596,13 @@ pub fn llvmMachineAbi(target: std.Target) ?[:0]const u8 { |
| 595 | } | 596 | } |
| 596 | 597 | ||
| 597 | /// This function returns 1 if function alignment is not observable or settable. | 598 | /// This function returns 1 if function alignment is not observable or settable. |
| 598 | pub fn defaultFunctionAlignment(target: std.Target) u32 { | 599 | pub fn defaultFunctionAlignment(target: std.Target) Alignment { |
| 599 | return switch (target.cpu.arch) { | 600 | return switch (target.cpu.arch) { |
| 600 | .arm, .armeb => 4, | 601 | .arm, .armeb => .@"4", |
| 601 | .aarch64, .aarch64_32, .aarch64_be => 4, | 602 | .aarch64, .aarch64_32, .aarch64_be => .@"4", |
| 602 | .sparc, .sparcel, .sparc64 => 4, | 603 | .sparc, .sparcel, .sparc64 => .@"4", |
| 603 | .riscv64 => 2, | 604 | .riscv64 => .@"2", |
| 604 | else => 1, | 605 | else => .@"1", |
| 605 | }; | 606 | }; |
| 606 | } | 607 | } |
| 607 | 608 |
src/type.zig+265-402| ... | @@ -9,6 +9,7 @@ const target_util = @import("target.zig"); | ... | @@ -9,6 +9,7 @@ const target_util = @import("target.zig"); |
| 9 | const TypedValue = @import("TypedValue.zig"); | 9 | const TypedValue = @import("TypedValue.zig"); |
| 10 | const Sema = @import("Sema.zig"); | 10 | const Sema = @import("Sema.zig"); |
| 11 | const InternPool = @import("InternPool.zig"); | 11 | const InternPool = @import("InternPool.zig"); |
| 12 | const Alignment = InternPool.Alignment; | ||
| 12 | 13 | ||
| 13 | /// Both types and values are canonically represented by a single 32-bit integer | 14 | /// Both types and values are canonically represented by a single 32-bit integer |
| 14 | /// which is an index into an `InternPool` data structure. | 15 | /// which is an index into an `InternPool` data structure. |
| ... | @@ -196,9 +197,11 @@ pub const Type = struct { | ... | @@ -196,9 +197,11 @@ pub const Type = struct { |
| 196 | info.packed_offset.host_size != 0 or | 197 | info.packed_offset.host_size != 0 or |
| 197 | info.flags.vector_index != .none) | 198 | info.flags.vector_index != .none) |
| 198 | { | 199 | { |
| 199 | const alignment = info.flags.alignment.toByteUnitsOptional() orelse | 200 | const alignment = if (info.flags.alignment != .none) |
| 201 | info.flags.alignment | ||
| 202 | else | ||
| 200 | info.child.toType().abiAlignment(mod); | 203 | info.child.toType().abiAlignment(mod); |
| 201 | try writer.print("align({d}", .{alignment}); | 204 | try writer.print("align({d}", .{alignment.toByteUnits(0)}); |
| 202 | 205 | ||
| 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 | } |
| 808 | 804 | ||
| 809 | /// Returns 0 if the pointer is naturally aligned and the element type is 0-bit. | 805 | /// Returns `none` if the pointer is naturally aligned and the element type is 0-bit. |
| 810 | pub fn ptrAlignment(ty: Type, mod: *Module) u32 { | 806 | pub fn ptrAlignment(ty: Type, mod: *Module) Alignment { |
| 811 | return ptrAlignmentAdvanced(ty, mod, null) catch unreachable; | 807 | return ptrAlignmentAdvanced(ty, mod, null) catch unreachable; |
| 812 | } | 808 | } |
| 813 | 809 | ||
| 814 | pub fn ptrAlignmentAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) !u32 { | 810 | pub fn ptrAlignmentAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) !Alignment { |
| 815 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | 811 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 816 | .ptr_type => |ptr_type| { | 812 | .ptr_type => |ptr_type| { |
| 817 | if (ptr_type.flags.alignment.toByteUnitsOptional()) |a| { | 813 | if (ptr_type.flags.alignment != .none) |
| 818 | return @as(u32, @intCast(a)); | 814 | return ptr_type.flags.alignment; |
| 819 | } else if (opt_sema) |sema| { | 815 | |
| 816 | if (opt_sema) |sema| { | ||
| 820 | const res = try ptr_type.child.toType().abiAlignmentAdvanced(mod, .{ .sema = sema }); | 817 | const res = try ptr_type.child.toType().abiAlignmentAdvanced(mod, .{ .sema = sema }); |
| 821 | return res.scalar; | 818 | return res.scalar; |
| 822 | } else { | ||
| 823 | return (ptr_type.child.toType().abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar; | ||
| 824 | } | 819 | } |
| 820 | |||
| 821 | return (ptr_type.child.toType().abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar; | ||
| 825 | }, | 822 | }, |
| 826 | .opt_type => |child| child.toType().ptrAlignmentAdvanced(mod, opt_sema), | 823 | .opt_type => |child| child.toType().ptrAlignmentAdvanced(mod, opt_sema), |
| 827 | else => unreachable, | 824 | else => unreachable, |
| ... | @@ -836,8 +833,8 @@ pub const Type = struct { | ... | @@ -836,8 +833,8 @@ pub const Type = struct { |
| 836 | }; | 833 | }; |
| 837 | } | 834 | } |
| 838 | 835 | ||
| 839 | /// Returns 0 for 0-bit types. | 836 | /// 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 | } |
| 843 | 840 | ||
| ... | @@ -846,12 +843,12 @@ pub const Type = struct { | ... | @@ -846,12 +843,12 @@ pub const Type = struct { |
| 846 | pub fn lazyAbiAlignment(ty: Type, mod: *Module) !Value { | 843 | pub fn lazyAbiAlignment(ty: Type, mod: *Module) !Value { |
| 847 | switch (try ty.abiAlignmentAdvanced(mod, .lazy)) { | 844 | switch (try ty.abiAlignmentAdvanced(mod, .lazy)) { |
| 848 | .val => |val| return val, | 845 | .val => |val| return val, |
| 849 | .scalar => |x| return mod.intValue(Type.comptime_int, x), | 846 | .scalar => |x| return mod.intValue(Type.comptime_int, x.toByteUnits(0)), |
| 850 | } | 847 | } |
| 851 | } | 848 | } |
| 852 | 849 | ||
| 853 | pub const AbiAlignmentAdvanced = union(enum) { | 850 | pub const AbiAlignmentAdvanced = union(enum) { |
| 854 | scalar: u32, | 851 | scalar: Alignment, |
| 855 | val: Value, | 852 | val: Value, |
| 856 | }; | 853 | }; |
| 857 | 854 | ||
| ... | @@ -881,36 +878,36 @@ pub const Type = struct { | ... | @@ -881,36 +878,36 @@ pub const Type = struct { |
| 881 | }; | 878 | }; |
| 882 | 879 | ||
| 883 | switch (ty.toIntern()) { | 880 | switch (ty.toIntern()) { |
| 884 | .empty_struct_type => return AbiAlignmentAdvanced{ .scalar = 0 }, | 881 | .empty_struct_type => return AbiAlignmentAdvanced{ .scalar = .@"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 | }, |
| 903 | 900 | ||
| 904 | .opt_type => return abiAlignmentAdvancedOptional(ty, mod, strat), | 901 | .opt_type => return abiAlignmentAdvancedOptional(ty, mod, strat), |
| 905 | .error_union_type => |info| return abiAlignmentAdvancedErrorUnion(ty, mod, strat, info.payload_type.toType()), | 902 | .error_union_type => |info| return abiAlignmentAdvancedErrorUnion(ty, mod, strat, info.payload_type.toType()), |
| 906 | 903 | ||
| 907 | // TODO revisit this when we have the concept of the error tag type | 904 | // TODO revisit this when we have the concept of the error tag type |
| 908 | .error_set_type, .inferred_error_set_type => return AbiAlignmentAdvanced{ .scalar = 2 }, | 905 | .error_set_type, .inferred_error_set_type => return .{ .scalar = .@"2" }, |
| 909 | 906 | ||
| 910 | // represents machine code; not a pointer | 907 | // represents machine code; not a pointer |
| 911 | .func_type => |func_type| return AbiAlignmentAdvanced{ | 908 | .func_type => |func_type| return .{ |
| 912 | .scalar = if (func_type.alignment.toByteUnitsOptional()) |a| | 909 | .scalar = if (func_type.alignment != .none) |
| 913 | @as(u32, @intCast(a)) | 910 | func_type.alignment |
| 914 | else | 911 | else |
| 915 | target_util.defaultFunctionAlignment(target), | 912 | target_util.defaultFunctionAlignment(target), |
| 916 | }, | 913 | }, |
| ... | @@ -926,47 +923,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" }, |
| 930 | 927 | ||
| 931 | .usize, | 928 | .usize, |
| 932 | .isize, | 929 | .isize, |
| 933 | .export_options, | 930 | .export_options, |
| 934 | .extern_options, | 931 | .extern_options, |
| 935 | => return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, | 932 | .type_info, |
| 936 | 933 | => 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) }, |
| 947 | 944 | .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 | }, |
| 965 | 965 | ||
| 966 | // TODO revisit this when we have the concept of the error tag type | 966 | // 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" }, |
| 970 | 970 | ||
| 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 }, | ||
| 980 | 979 | ||
| 981 | .noreturn => unreachable, | 980 | .noreturn => unreachable, |
| 982 | .generic_poison => unreachable, | 981 | .generic_poison => unreachable, |
| 983 | }, | 982 | }, |
| 984 | .struct_type => |struct_type| { | 983 | .struct_type => |struct_type| { |
| 985 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse | 984 | if (struct_type.layout == .Packed) { |
| 986 | return AbiAlignmentAdvanced{ .scalar = 0 }; | ||
| 987 | |||
| 988 | if (opt_sema) |sema| { | ||
| 989 | if (struct_obj.status == .field_types_wip) { | ||
| 990 | // We'll guess "pointer-aligned", if the struct has an | ||
| 991 | // underaligned pointer field then some allocations | ||
| 992 | // might require explicit alignment. | ||
| 993 | return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }; | ||
| 994 | } | ||
| 995 | _ = try sema.resolveTypeFields(ty); | ||
| 996 | } | ||
| 997 | if (!struct_obj.haveFieldTypes()) switch (strat) { | ||
| 998 | .eager => unreachable, // struct layout not resolved | ||
| 999 | .sema => unreachable, // handled above | ||
| 1000 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ | ||
| 1001 | .ty = .comptime_int_type, | ||
| 1002 | .storage = .{ .lazy_align = ty.toIntern() }, | ||
| 1003 | } })).toValue() }, | ||
| 1004 | }; | ||
| 1005 | if (struct_obj.layout == .Packed) { | ||
| 1006 | switch (strat) { | 985 | switch (strat) { |
| 1007 | .sema => |sema| try sema.resolveTypeLayout(ty), | 986 | .sema => |sema| try sema.resolveTypeLayout(ty), |
| 1008 | .lazy => if (!struct_obj.haveLayout()) return .{ .val = (try mod.intern(.{ .int = .{ | 987 | .lazy => if (struct_type.backingIntType(ip).* == .none) return .{ |
| 1009 | .ty = .comptime_int_type, | 988 | .val = (try mod.intern(.{ .int = .{ |
| 1010 | .storage = .{ .lazy_align = ty.toIntern() }, | ||
| 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 field | 1015 | 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 resolved | 1019 | .eager => unreachable, // field type alignment not resolved |
| 1064 | .sema => unreachable, // passed to abiAlignmentAdvanced above | 1020 | .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 | }, |
| 1074 | 1030 | ||
| 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 an | 1034 | // We'll guess "pointer-aligned", if the union has an |
| 1079 | // underaligned pointer field then some allocations | 1035 | // 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 | } |
| 1103 | 1057 | ||
| 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; |
| 1119 | 1073 | ||
| 1120 | const field_align_bytes: u32 = @intCast(field_align.toByteUnitsOptional() orelse | 1074 | 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 resolved | 1079 | .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) }, | ||
| 1138 | 1095 | ||
| 1139 | // values, not types | 1096 | // 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); |
| 1213 | 1165 | ||
| 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 | } |
| 1220 | 1174 | ||
| ... | @@ -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 | }, |
| 1327 | 1279 | ||
| 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 | }; |
| 1361 | 1313 | ||
| 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) orelse | 1392 | .sema => |sema| try sema.resolveTypeLayout(ty), |
| 1441 | return AbiSizeAdvanced{ .scalar = 0 }; | 1393 | .lazy => switch (struct_type.layout) { |
| 1442 | 1394 | .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 equal | 1511 | // 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 | } |
| 1571 | 1517 | ||
| 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 | } |
| 1576 | 1521 | ||
| 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 | } |
| 1583 | 1528 | ||
| 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, |
| 1677 | 1622 | ||
| 1678 | .atomic_order => unreachable, // missing call to resolveTypeFields | 1623 | .atomic_order => unreachable, |
| 1679 | .atomic_rmw_op => unreachable, // missing call to resolveTypeFields | 1624 | .atomic_rmw_op => unreachable, |
| 1680 | .calling_convention => unreachable, // missing call to resolveTypeFields | 1625 | .calling_convention => unreachable, |
| 1681 | .address_space => unreachable, // missing call to resolveTypeFields | 1626 | .address_space => unreachable, |
| 1682 | .float_mode => unreachable, // missing call to resolveTypeFields | 1627 | .float_mode => unreachable, |
| 1683 | .reduce_op => unreachable, // missing call to resolveTypeFields | 1628 | .reduce_op => unreachable, |
| 1684 | .call_modifier => unreachable, // missing call to resolveTypeFields | 1629 | .call_modifier => unreachable, |
| 1685 | .prefetch_options => unreachable, // missing call to resolveTypeFields | 1630 | .prefetch_options => unreachable, |
| 1686 | .export_options => unreachable, // missing call to resolveTypeFields | 1631 | .export_options => unreachable, |
| 1687 | .extern_options => unreachable, // missing call to resolveTypeFields | 1632 | .extern_options => unreachable, |
| 1688 | .type_info => unreachable, // missing call to resolveTypeFields | 1633 | .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 | }, |
| 1699 | 1642 | ||
| 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 | }, |
| 1704 | 1647 | ||
| 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, |
| 2144 | 2075 | ||
| 2145 | else => unreachable, | 2076 | else => unreachable, |
| ... | @@ -2214,6 +2145,7 @@ pub const Type = struct { | ... | @@ -2214,6 +2145,7 @@ pub const Type = struct { |
| 2214 | 2145 | ||
| 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; |
| 2219 | 2151 | ||
| ... | @@ -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(), |
| 2245 | 2173 | ||
| ... | @@ -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 | } |
| 2519 | 2445 | const field_ty = struct_type.field_types.get(ip)[i].toType(); | |
| 2520 | // In this case the struct has no runtime-known fields and | 2446 | 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 | } |
| 2527 | 2450 | ||
| 2528 | // In this case the struct has no fields at all and | 2451 | // 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 | }, |
| 2535 | 2458 | ||
| ... | @@ -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 with | 2651 | .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 | }, |
| 2731 | 2656 | ||
| 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 | } |
| 2984 | 2909 | ||
| 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 | } |
| 3008 | 2919 | ||
| 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 | } |
| 3038 | 2953 | ||
| 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 | } |
| 3115 | 3023 | ||
| 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); |
| 3121 | 3029 | ||
| 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; |
| 3127 | 3035 | ||
| 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 | }; |
| 3143 | 3051 | ||
| 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 | }, |
| 3202 | 3061 | ||
| 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; |
| 3206 | 3065 | ||
| 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 | } |
| 3213 | 3072 | ||
| 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 | }, |
| 3223 | 3082 | ||
| ... | @@ -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 { |
| 3264 | 3122 | ||
| 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 | } |
| 3281 | 3136 | ||
| 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 | } |
| 3300 | 3157 | ||
| 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 | |||
| 3254 | fn 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 })).scalar | 526 | (try ty.toType().abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar.toByteUnits(0) |
| 527 | else | 527 | else |
| 528 | ty.toType().abiAlignment(mod), | 528 | ty.toType().abiAlignment(mod).toByteUnits(0), |
| 529 | .lazy_size => |ty| if (opt_sema) |sema| | 529 | .lazy_size => |ty| if (opt_sema) |sema| |
| 530 | (try ty.toType().abiSizeAdvanced(mod, .{ .sema = sema })).scalar | 530 | (try ty.toType().abiSizeAdvanced(mod, .{ .sema = sema })).scalar |
| 531 | else | 531 | else |
| ... | @@ -569,9 +569,9 @@ pub const Value = struct { | ... | @@ -569,9 +569,9 @@ pub const Value = struct { |
| 569 | .int => |int| switch (int.storage) { | 569 | .int => |int| switch (int.storage) { |
| 570 | .big_int => |big_int| big_int.to(i64) catch unreachable, | 570 | .big_int => |big_int| big_int.to(i64) catch unreachable, |
| 571 | .i64 => |x| x, | 571 | .i64 => |x| x, |
| 572 | .u64 => |x| @as(i64, @intCast(x)), | 572 | .u64 => |x| @intCast(x), |
| 573 | .lazy_align => |ty| @as(i64, @intCast(ty.toType().abiAlignment(mod))), | 573 | .lazy_align => |ty| @intCast(ty.toType().abiAlignment(mod).toByteUnits(0)), |
| 574 | .lazy_size => |ty| @as(i64, @intCast(ty.toType().abiSize(mod))), | 574 | .lazy_size => |ty| @intCast(ty.toType().abiSize(mod)), |
| 575 | }, | 575 | }, |
| 576 | else => unreachable, | 576 | else => unreachable, |
| 577 | }, | 577 | }, |
| ... | @@ -612,10 +612,11 @@ pub const Value = struct { | ... | @@ -612,10 +612,11 @@ pub const Value = struct { |
| 612 | const target = mod.getTarget(); | 612 | const target = mod.getTarget(); |
| 613 | const endian = target.cpu.arch.endian(); | 613 | const endian = target.cpu.arch.endian(); |
| 614 | if (val.isUndef(mod)) { | 614 | if (val.isUndef(mod)) { |
| 615 | const size = @as(usize, @intCast(ty.abiSize(mod))); | 615 | const size: usize = @intCast(ty.abiSize(mod)); |
| 616 | @memset(buffer[0..size], 0xaa); | 616 | @memset(buffer[0..size], 0xaa); |
| 617 | return; | 617 | return; |
| 618 | } | 618 | } |
| 619 | const ip = &mod.intern_pool; | ||
| 619 | switch (ty.zigTypeTag(mod)) { | 620 | switch (ty.zigTypeTag(mod)) { |
| 620 | .Void => {}, | 621 | .Void => {}, |
| 621 | .Bool => { | 622 | .Bool => { |
| ... | @@ -656,40 +657,44 @@ pub const Value = struct { | ... | @@ -656,40 +657,44 @@ pub const Value = struct { |
| 656 | const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; | 657 | const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; |
| 657 | return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0); | 658 | return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0); |
| 658 | }, | 659 | }, |
| 659 | .Struct => switch (ty.containerLayout(mod)) { | 660 | .Struct => { |
| 660 | .Auto => return error.IllDefinedMemoryLayout, | 661 | const struct_type = mod.typeToStruct(ty) orelse return error.IllDefinedMemoryLayout; |
| 661 | .Extern => for (ty.structFields(mod).values(), 0..) |field, i| { | 662 | switch (struct_type.layout) { |
| 662 | const off = @as(usize, @intCast(ty.structFieldOffset(i, mod))); | 663 | .Auto => return error.IllDefinedMemoryLayout, |
| 663 | const field_val = switch (val.ip_index) { | 664 | .Extern => for (0..struct_type.field_types.len) |i| { |
| 664 | .none => switch (val.tag()) { | 665 | const off: usize = @intCast(ty.structFieldOffset(i, mod)); |
| 665 | .bytes => { | 666 | const field_val = switch (val.ip_index) { |
| 666 | buffer[off] = val.castTag(.bytes).?.data[i]; | 667 | .none => switch (val.tag()) { |
| 667 | continue; | 668 | .bytes => { |
| 668 | }, | 669 | buffer[off] = val.castTag(.bytes).?.data[i]; |
| 669 | .aggregate => val.castTag(.aggregate).?.data[i], | 670 | continue; |
| 670 | .repeated => val.castTag(.repeated).?.data, | 671 | }, |
| 671 | else => unreachable, | 672 | .aggregate => val.castTag(.aggregate).?.data[i], |
| 672 | }, | 673 | .repeated => val.castTag(.repeated).?.data, |
| 673 | else => switch (mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage) { | 674 | else => unreachable, |
| 674 | .bytes => |bytes| { | ||
| 675 | buffer[off] = bytes[i]; | ||
| 676 | continue; | ||
| 677 | }, | 675 | }, |
| 678 | .elems => |elems| elems[i], | 676 | else => switch (ip.indexToKey(val.toIntern()).aggregate.storage) { |
| 679 | .repeated_elem => |elem| elem, | 677 | .bytes => |bytes| { |
| 680 | }.toValue(), | 678 | buffer[off] = bytes[i]; |
| 681 | }; | 679 | continue; |
| 682 | try writeToMemory(field_val, field.ty, mod, buffer[off..]); | 680 | }, |
| 683 | }, | 681 | .elems => |elems| elems[i], |
| 684 | .Packed => { | 682 | .repeated_elem => |elem| elem, |
| 685 | const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; | 683 | }.toValue(), |
| 686 | return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0); | 684 | }; |
| 687 | }, | 685 | const field_ty = struct_type.field_types.get(ip)[i].toType(); |
| 686 | try writeToMemory(field_val, field_ty, mod, buffer[off..]); | ||
| 687 | }, | ||
| 688 | .Packed => { | ||
| 689 | const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; | ||
| 690 | return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0); | ||
| 691 | }, | ||
| 692 | } | ||
| 688 | }, | 693 | }, |
| 689 | .ErrorSet => { | 694 | .ErrorSet => { |
| 690 | // TODO revisit this when we have the concept of the error tag type | 695 | // TODO revisit this when we have the concept of the error tag type |
| 691 | const Int = u16; | 696 | const Int = u16; |
| 692 | const name = switch (mod.intern_pool.indexToKey(val.toIntern())) { | 697 | const name = switch (ip.indexToKey(val.toIntern())) { |
| 693 | .err => |err| err.name, | 698 | .err => |err| err.name, |
| 694 | .error_union => |error_union| error_union.val.err_name, | 699 | .error_union => |error_union| error_union.val.err_name, |
| 695 | else => unreachable, | 700 | else => unreachable, |
| ... | @@ -790,24 +795,24 @@ pub const Value = struct { | ... | @@ -790,24 +795,24 @@ pub const Value = struct { |
| 790 | bits += elem_bit_size; | 795 | bits += elem_bit_size; |
| 791 | } | 796 | } |
| 792 | }, | 797 | }, |
| 793 | .Struct => switch (ty.containerLayout(mod)) { | 798 | .Struct => { |
| 794 | .Auto => unreachable, // Sema is supposed to have emitted a compile error already | 799 | const struct_type = ip.indexToKey(ty.toIntern()).struct_type; |
| 795 | .Extern => unreachable, // Handled in non-packed writeToMemory | 800 | // Sema is supposed to have emitted a compile error already in the case of Auto, |
| 796 | .Packed => { | 801 | // and Extern is handled in non-packed writeToMemory. |
| 797 | var bits: u16 = 0; | 802 | assert(struct_type.layout == .Packed); |
| 798 | const fields = ty.structFields(mod).values(); | 803 | var bits: u16 = 0; |
| 799 | const storage = ip.indexToKey(val.toIntern()).aggregate.storage; | 804 | const storage = ip.indexToKey(val.toIntern()).aggregate.storage; |
| 800 | for (fields, 0..) |field, i| { | 805 | for (0..struct_type.field_types.len) |i| { |
| 801 | const field_bits = @as(u16, @intCast(field.ty.bitSize(mod))); | 806 | const field_ty = struct_type.field_types.get(ip)[i].toType(); |
| 802 | const field_val = switch (storage) { | 807 | const field_bits: u16 = @intCast(field_ty.bitSize(mod)); |
| 803 | .bytes => unreachable, | 808 | const field_val = switch (storage) { |
| 804 | .elems => |elems| elems[i], | 809 | .bytes => unreachable, |
| 805 | .repeated_elem => |elem| elem, | 810 | .elems => |elems| elems[i], |
| 806 | }; | 811 | .repeated_elem => |elem| elem, |
| 807 | try field_val.toValue().writeToPackedMemory(field.ty, mod, buffer, bit_offset + bits); | 812 | }; |
| 808 | bits += field_bits; | 813 | try field_val.toValue().writeToPackedMemory(field_ty, mod, buffer, bit_offset + bits); |
| 809 | } | 814 | bits += field_bits; |
| 810 | }, | 815 | } |
| 811 | }, | 816 | }, |
| 812 | .Union => { | 817 | .Union => { |
| 813 | const union_obj = mod.typeToUnion(ty).?; | 818 | const union_obj = mod.typeToUnion(ty).?; |
| ... | @@ -852,6 +857,7 @@ pub const Value = struct { | ... | @@ -852,6 +857,7 @@ pub const Value = struct { |
| 852 | buffer: []const u8, | 857 | buffer: []const u8, |
| 853 | arena: Allocator, | 858 | arena: Allocator, |
| 854 | ) Allocator.Error!Value { | 859 | ) Allocator.Error!Value { |
| 860 | const ip = &mod.intern_pool; | ||
| 855 | const target = mod.getTarget(); | 861 | const target = mod.getTarget(); |
| 856 | const endian = target.cpu.arch.endian(); | 862 | const endian = target.cpu.arch.endian(); |
| 857 | switch (ty.zigTypeTag(mod)) { | 863 | switch (ty.zigTypeTag(mod)) { |
| ... | @@ -926,25 +932,29 @@ pub const Value = struct { | ... | @@ -926,25 +932,29 @@ pub const Value = struct { |
| 926 | const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; | 932 | const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; |
| 927 | return readFromPackedMemory(ty, mod, buffer[0..byte_count], 0, arena); | 933 | return readFromPackedMemory(ty, mod, buffer[0..byte_count], 0, arena); |
| 928 | }, | 934 | }, |
| 929 | .Struct => switch (ty.containerLayout(mod)) { | 935 | .Struct => { |
| 930 | .Auto => unreachable, // Sema is supposed to have emitted a compile error already | 936 | const struct_type = mod.typeToStruct(ty).?; |
| 931 | .Extern => { | 937 | switch (struct_type.layout) { |
| 932 | const fields = ty.structFields(mod).values(); | 938 | .Auto => unreachable, // Sema is supposed to have emitted a compile error already |
| 933 | const field_vals = try arena.alloc(InternPool.Index, fields.len); | 939 | .Extern => { |
| 934 | for (field_vals, fields, 0..) |*field_val, field, i| { | 940 | const field_types = struct_type.field_types; |
| 935 | const off = @as(usize, @intCast(ty.structFieldOffset(i, mod))); | 941 | const field_vals = try arena.alloc(InternPool.Index, field_types.len); |
| 936 | const sz = @as(usize, @intCast(field.ty.abiSize(mod))); | 942 | for (field_vals, 0..) |*field_val, i| { |
| 937 | field_val.* = try (try readFromMemory(field.ty, mod, buffer[off..(off + sz)], arena)).intern(field.ty, mod); | 943 | const field_ty = field_types.get(ip)[i].toType(); |
| 938 | } | 944 | const off: usize = @intCast(ty.structFieldOffset(i, mod)); |
| 939 | return (try mod.intern(.{ .aggregate = .{ | 945 | const sz: usize = @intCast(field_ty.abiSize(mod)); |
| 940 | .ty = ty.toIntern(), | 946 | field_val.* = try (try readFromMemory(field_ty, mod, buffer[off..(off + sz)], arena)).intern(field_ty, mod); |
| 941 | .storage = .{ .elems = field_vals }, | 947 | } |
| 942 | } })).toValue(); | 948 | return (try mod.intern(.{ .aggregate = .{ |
| 943 | }, | 949 | .ty = ty.toIntern(), |
| 944 | .Packed => { | 950 | .storage = .{ .elems = field_vals }, |
| 945 | const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; | 951 | } })).toValue(); |
| 946 | return readFromPackedMemory(ty, mod, buffer[0..byte_count], 0, arena); | 952 | }, |
| 947 | }, | 953 | .Packed => { |
| 954 | const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; | ||
| 955 | return readFromPackedMemory(ty, mod, buffer[0..byte_count], 0, arena); | ||
| 956 | }, | ||
| 957 | } | ||
| 948 | }, | 958 | }, |
| 949 | .ErrorSet => { | 959 | .ErrorSet => { |
| 950 | // TODO revisit this when we have the concept of the error tag type | 960 | // TODO revisit this when we have the concept of the error tag type |
| ... | @@ -992,6 +1002,7 @@ pub const Value = struct { | ... | @@ -992,6 +1002,7 @@ pub const Value = struct { |
| 992 | bit_offset: usize, | 1002 | bit_offset: usize, |
| 993 | arena: Allocator, | 1003 | arena: Allocator, |
| 994 | ) Allocator.Error!Value { | 1004 | ) Allocator.Error!Value { |
| 1005 | const ip = &mod.intern_pool; | ||
| 995 | const target = mod.getTarget(); | 1006 | const target = mod.getTarget(); |
| 996 | const endian = target.cpu.arch.endian(); | 1007 | const endian = target.cpu.arch.endian(); |
| 997 | switch (ty.zigTypeTag(mod)) { | 1008 | switch (ty.zigTypeTag(mod)) { |
| ... | @@ -1070,23 +1081,22 @@ pub const Value = struct { | ... | @@ -1070,23 +1081,22 @@ pub const Value = struct { |
| 1070 | .storage = .{ .elems = elems }, | 1081 | .storage = .{ .elems = elems }, |
| 1071 | } })).toValue(); | 1082 | } })).toValue(); |
| 1072 | }, | 1083 | }, |
| 1073 | .Struct => switch (ty.containerLayout(mod)) { | 1084 | .Struct => { |
| 1074 | .Auto => unreachable, // Sema is supposed to have emitted a compile error already | 1085 | // Sema is supposed to have emitted a compile error already for Auto layout structs, |
| 1075 | .Extern => unreachable, // Handled by non-packed readFromMemory | 1086 | // and Extern is handled by non-packed readFromMemory. |
| 1076 | .Packed => { | 1087 | const struct_type = mod.typeToPackedStruct(ty).?; |
| 1077 | var bits: u16 = 0; | 1088 | var bits: u16 = 0; |
| 1078 | const fields = ty.structFields(mod).values(); | 1089 | const field_vals = try arena.alloc(InternPool.Index, struct_type.field_types.len); |
| 1079 | const field_vals = try arena.alloc(InternPool.Index, fields.len); | 1090 | for (field_vals, 0..) |*field_val, i| { |
| 1080 | for (fields, 0..) |field, i| { | 1091 | const field_ty = struct_type.field_types.get(ip)[i].toType(); |
| 1081 | const field_bits = @as(u16, @intCast(field.ty.bitSize(mod))); | 1092 | const field_bits: u16 = @intCast(field_ty.bitSize(mod)); |
| 1082 | field_vals[i] = try (try readFromPackedMemory(field.ty, mod, buffer, bit_offset + bits, arena)).intern(field.ty, mod); | 1093 | field_val.* = try (try readFromPackedMemory(field_ty, mod, buffer, bit_offset + bits, arena)).intern(field_ty, mod); |
| 1083 | bits += field_bits; | 1094 | bits += field_bits; |
| 1084 | } | 1095 | } |
| 1085 | return (try mod.intern(.{ .aggregate = .{ | 1096 | return (try mod.intern(.{ .aggregate = .{ |
| 1086 | .ty = ty.toIntern(), | 1097 | .ty = ty.toIntern(), |
| 1087 | .storage = .{ .elems = field_vals }, | 1098 | .storage = .{ .elems = field_vals }, |
| 1088 | } })).toValue(); | 1099 | } })).toValue(); |
| 1089 | }, | ||
| 1090 | }, | 1100 | }, |
| 1091 | .Pointer => { | 1101 | .Pointer => { |
| 1092 | assert(!ty.isSlice(mod)); // No well defined layout. | 1102 | assert(!ty.isSlice(mod)); // No well defined layout. |
| ... | @@ -1105,18 +1115,18 @@ pub const Value = struct { | ... | @@ -1105,18 +1115,18 @@ pub const Value = struct { |
| 1105 | pub fn toFloat(val: Value, comptime T: type, mod: *Module) T { | 1115 | pub fn toFloat(val: Value, comptime T: type, mod: *Module) T { |
| 1106 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { | 1116 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 1107 | .int => |int| switch (int.storage) { | 1117 | .int => |int| switch (int.storage) { |
| 1108 | .big_int => |big_int| @as(T, @floatCast(bigIntToFloat(big_int.limbs, big_int.positive))), | 1118 | .big_int => |big_int| @floatCast(bigIntToFloat(big_int.limbs, big_int.positive)), |
| 1109 | inline .u64, .i64 => |x| { | 1119 | inline .u64, .i64 => |x| { |
| 1110 | if (T == f80) { | 1120 | if (T == f80) { |
| 1111 | @panic("TODO we can't lower this properly on non-x86 llvm backend yet"); | 1121 | @panic("TODO we can't lower this properly on non-x86 llvm backend yet"); |
| 1112 | } | 1122 | } |
| 1113 | return @as(T, @floatFromInt(x)); | 1123 | return @floatFromInt(x); |
| 1114 | }, | 1124 | }, |
| 1115 | .lazy_align => |ty| @as(T, @floatFromInt(ty.toType().abiAlignment(mod))), | 1125 | .lazy_align => |ty| @floatFromInt(ty.toType().abiAlignment(mod).toByteUnits(0)), |
| 1116 | .lazy_size => |ty| @as(T, @floatFromInt(ty.toType().abiSize(mod))), | 1126 | .lazy_size => |ty| @floatFromInt(ty.toType().abiSize(mod)), |
| 1117 | }, | 1127 | }, |
| 1118 | .float => |float| switch (float.storage) { | 1128 | .float => |float| switch (float.storage) { |
| 1119 | inline else => |x| @as(T, @floatCast(x)), | 1129 | inline else => |x| @floatCast(x), |
| 1120 | }, | 1130 | }, |
| 1121 | else => unreachable, | 1131 | else => unreachable, |
| 1122 | }; | 1132 | }; |
| ... | @@ -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 | |||
| 623 | test "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 | |||
| 650 | test "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 | } |
| 19 | 19 | ||
| 20 | test "comparison of @alignOf(T) against zero" { | 20 | test "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 | } |
| 40 | 29 | ||
| 41 | test "correct alignment for elements and slices of aligned array" { | 30 | test "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" { |
| 37 | test "empty union" { | 37 | test "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 | } |
| 42 | 42 | ||
| 43 | test "empty extern union" { | 43 | test "empty extern union" { |