| 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 | 4758 | .known_non_opv = false, |
| 4759 | 4759 | .known_comptime_only = false, |
| 4760 | 4760 | .is_tuple = false, |
| 4761 | .any_comptime_fields = false, | |
| 4762 | .any_default_inits = false, | |
| 4763 | .any_aligned_fields = false, | |
| 4761 | 4764 | }); |
| 4762 | 4765 | return indexToRef(decl_inst); |
| 4763 | 4766 | } |
| ... | ... | @@ -4881,6 +4884,9 @@ fn structDeclInner( |
| 4881 | 4884 | |
| 4882 | 4885 | var known_non_opv = false; |
| 4883 | 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 | 4890 | for (container_decl.ast.members) |member_node| { |
| 4885 | 4891 | var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) { |
| 4886 | 4892 | .decl => continue, |
| ... | ... | @@ -4910,13 +4916,13 @@ fn structDeclInner( |
| 4910 | 4916 | const have_value = member.ast.value_expr != 0; |
| 4911 | 4917 | const is_comptime = member.comptime_token != null; |
| 4912 | 4918 | |
| 4913 | if (is_comptime and layout == .Packed) { | |
| 4914 | return astgen.failTok(member.comptime_token.?, "packed struct fields cannot be marked comptime", .{}); | |
| 4915 | } else if (is_comptime and layout == .Extern) { | |
| 4916 | return astgen.failTok(member.comptime_token.?, "extern struct fields cannot be marked comptime", .{}); | |
| 4917 | } | |
| 4918 | ||
| 4919 | if (!is_comptime) { | |
| 4919 | if (is_comptime) { | |
| 4920 | switch (layout) { | |
| 4921 | .Packed => return astgen.failTok(member.comptime_token.?, "packed struct fields cannot be marked comptime", .{}), | |
| 4922 | .Extern => return astgen.failTok(member.comptime_token.?, "extern struct fields cannot be marked comptime", .{}), | |
| 4923 | .Auto => any_comptime_fields = true, | |
| 4924 | } | |
| 4925 | } else { | |
| 4920 | 4926 | known_non_opv = known_non_opv or |
| 4921 | 4927 | nodeImpliesMoreThanOnePossibleValue(tree, member.ast.type_expr); |
| 4922 | 4928 | known_comptime_only = known_comptime_only or |
| ... | ... | @@ -4942,6 +4948,7 @@ fn structDeclInner( |
| 4942 | 4948 | if (layout == .Packed) { |
| 4943 | 4949 | try astgen.appendErrorNode(member.ast.align_expr, "unable to override alignment of packed struct fields", .{}); |
| 4944 | 4950 | } |
| 4951 | any_aligned_fields = true; | |
| 4945 | 4952 | const align_ref = try expr(&block_scope, &namespace.base, coerced_align_ri, member.ast.align_expr); |
| 4946 | 4953 | if (!block_scope.endsWithNoReturn()) { |
| 4947 | 4954 | _ = try block_scope.addBreak(.break_inline, decl_inst, align_ref); |
| ... | ... | @@ -4955,6 +4962,7 @@ fn structDeclInner( |
| 4955 | 4962 | } |
| 4956 | 4963 | |
| 4957 | 4964 | if (have_value) { |
| 4965 | any_default_inits = true; | |
| 4958 | 4966 | const ri: ResultInfo = .{ .rl = if (field_type == .none) .none else .{ .coerced_ty = field_type } }; |
| 4959 | 4967 | |
| 4960 | 4968 | const default_inst = try expr(&block_scope, &namespace.base, ri, member.ast.value_expr); |
| ... | ... | @@ -4982,6 +4990,9 @@ fn structDeclInner( |
| 4982 | 4990 | .known_non_opv = known_non_opv, |
| 4983 | 4991 | .known_comptime_only = known_comptime_only, |
| 4984 | 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 | 4998 | wip_members.finishBits(bits_per_field); |
| ... | ... | @@ -12080,6 +12091,9 @@ const GenZir = struct { |
| 12080 | 12091 | known_non_opv: bool, |
| 12081 | 12092 | known_comptime_only: bool, |
| 12082 | 12093 | is_tuple: bool, |
| 12094 | any_comptime_fields: bool, | |
| 12095 | any_default_inits: bool, | |
| 12096 | any_aligned_fields: bool, | |
| 12083 | 12097 | }) !void { |
| 12084 | 12098 | const astgen = gz.astgen; |
| 12085 | 12099 | const gpa = astgen.gpa; |
| ... | ... | @@ -12117,6 +12131,9 @@ const GenZir = struct { |
| 12117 | 12131 | .is_tuple = args.is_tuple, |
| 12118 | 12132 | .name_strategy = gz.anon_name_strategy, |
| 12119 | 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 | 12138 | .operand = payload_index, |
| 12122 | 12139 | } }, |
src/InternPool.zig+911-195| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | //! All interned objects have both a value and a type. |
| 2 | 2 | //! This data structure is self-contained, with the following exceptions: |
| 3 | //! * type_struct via Module.Struct.Index | |
| 4 | //! * type_opaque via Module.Namespace.Index and Module.Decl.Index | |
| 3 | //! * Module.Namespace has a pointer to Module.File | |
| 4 | //! * Module.Decl has a pointer to Module.CaptureScope | |
| 5 | 5 | |
| 6 | 6 | /// Maps `Key` to `Index`. `Key` objects are not stored anywhere; they are |
| 7 | 7 | /// constructed lazily. |
| ... | ... | @@ -39,17 +39,11 @@ allocated_namespaces: std.SegmentedList(Module.Namespace, 0) = .{}, |
| 39 | 39 | /// Same pattern as with `decls_free_list`. |
| 40 | 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 | 42 | /// Some types such as enums, structs, and unions need to store mappings from field names |
| 50 | 43 | /// to field index, or value to field index. In such cases, they will store the underlying |
| 51 | 44 | /// field names and values directly, relying on one of these maps, stored separately, |
| 52 | 45 | /// to provide lookup. |
| 46 | /// These are not serialized; it is computed upon deserialization. | |
| 53 | 47 | maps: std.ArrayListUnmanaged(FieldMap) = .{}, |
| 54 | 48 | |
| 55 | 49 | /// Used for finding the index inside `string_bytes`. |
| ... | ... | @@ -365,11 +359,291 @@ pub const Key = union(enum) { |
| 365 | 359 | namespace: Module.Namespace.Index, |
| 366 | 360 | }; |
| 367 | 361 | |
| 368 | pub const StructType = extern struct { | |
| 369 | /// The `none` tag is used to represent a struct with no fields. | |
| 370 | index: Module.Struct.OptionalIndex, | |
| 371 | /// May be `none` if the struct has no declarations. | |
| 362 | /// Although packed structs and non-packed structs are encoded differently, | |
| 363 | /// this struct is used for both categories since they share some common | |
| 364 | /// functionality. | |
| 365 | pub const StructType = struct { | |
| 366 | extra_index: u32, | |
| 367 | /// `none` when the struct is `@TypeOf(.{})`. | |
| 368 | decl: Module.Decl.OptionalIndex, | |
| 369 | /// `none` when the struct has no declarations. | |
| 372 | 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 | 649 | pub const AnonStructType = struct { |
| ... | ... | @@ -382,6 +656,17 @@ pub const Key = union(enum) { |
| 382 | 656 | pub fn isTuple(self: AnonStructType) bool { |
| 383 | 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 | 672 | /// Serves two purposes: |
| ... | ... | @@ -870,7 +1155,6 @@ pub const Key = union(enum) { |
| 870 | 1155 | .simple_type, |
| 871 | 1156 | .simple_value, |
| 872 | 1157 | .opt, |
| 873 | .struct_type, | |
| 874 | 1158 | .undef, |
| 875 | 1159 | .err, |
| 876 | 1160 | .enum_literal, |
| ... | ... | @@ -893,6 +1177,7 @@ pub const Key = union(enum) { |
| 893 | 1177 | .enum_type, |
| 894 | 1178 | .variable, |
| 895 | 1179 | .union_type, |
| 1180 | .struct_type, | |
| 896 | 1181 | => |x| Hash.hash(seed, asBytes(&x.decl)), |
| 897 | 1182 | |
| 898 | 1183 | .int => |int| { |
| ... | ... | @@ -969,11 +1254,11 @@ pub const Key = union(enum) { |
| 969 | 1254 | |
| 970 | 1255 | if (child == .u8_type) { |
| 971 | 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 | 1258 | std.hash.autoHash(&hasher, KeyTag.int); |
| 974 | 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 | 1262 | const elem_key = ip.indexToKey(elem); |
| 978 | 1263 | std.hash.autoHash(&hasher, @as(KeyTag, elem_key)); |
| 979 | 1264 | switch (elem_key) { |
| ... | ... | @@ -1123,10 +1408,6 @@ pub const Key = union(enum) { |
| 1123 | 1408 | const b_info = b.opt; |
| 1124 | 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 | 1411 | .un => |a_info| { |
| 1131 | 1412 | const b_info = b.un; |
| 1132 | 1413 | return std.meta.eql(a_info, b_info); |
| ... | ... | @@ -1298,6 +1579,10 @@ pub const Key = union(enum) { |
| 1298 | 1579 | const b_info = b.union_type; |
| 1299 | 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 | 1586 | .aggregate => |a_info| { |
| 1302 | 1587 | const b_info = b.aggregate; |
| 1303 | 1588 | if (a_info.ty != b_info.ty) return false; |
| ... | ... | @@ -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 | 1723 | // Unlike `Tag.TypeUnion` which is an encoding, and `Key.UnionType` which is a |
| 1437 | 1724 | // minimal hashmap key, this type is a convenience type that contains info |
| 1438 | 1725 | // needed by semantic analysis. |
| ... | ... | @@ -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 | 1764 | pub const Status = enum(u3) { |
| 1480 | 1765 | none, |
| 1481 | 1766 | field_types_wip, |
| ... | ... | @@ -1814,9 +2099,11 @@ pub const Index = enum(u32) { |
| 1814 | 2099 | type_enum_nonexhaustive: DataIsExtraIndexOfEnumExplicit, |
| 1815 | 2100 | simple_type: struct { data: SimpleType }, |
| 1816 | 2101 | type_opaque: struct { data: *Key.OpaqueType }, |
| 1817 | type_struct: struct { data: Module.Struct.OptionalIndex }, | |
| 2102 | type_struct: struct { data: *Tag.TypeStruct }, | |
| 1818 | 2103 | type_struct_ns: struct { data: Module.Namespace.Index }, |
| 1819 | 2104 | type_struct_anon: DataIsExtraIndexOfTypeStructAnon, |
| 2105 | type_struct_packed: struct { data: *Tag.TypeStructPacked }, | |
| 2106 | type_struct_packed_inits: struct { data: *Tag.TypeStructPacked }, | |
| 1820 | 2107 | type_tuple_anon: DataIsExtraIndexOfTypeStructAnon, |
| 1821 | 2108 | type_union: struct { data: *Tag.TypeUnion }, |
| 1822 | 2109 | type_function: struct { |
| ... | ... | @@ -2241,17 +2528,22 @@ pub const Tag = enum(u8) { |
| 2241 | 2528 | /// An opaque type. |
| 2242 | 2529 | /// data is index of Key.OpaqueType in extra. |
| 2243 | 2530 | type_opaque, |
| 2244 | /// A struct type. | |
| 2245 | /// data is Module.Struct.OptionalIndex | |
| 2246 | /// The `none` tag is used to represent `@TypeOf(.{})`. | |
| 2531 | /// A non-packed struct type. | |
| 2532 | /// data is 0 or extra index of `TypeStruct`. | |
| 2533 | /// data == 0 represents `@TypeOf(.{})`. | |
| 2247 | 2534 | type_struct, |
| 2248 | /// A struct type that has only a namespace; no fields, and there is no | |
| 2249 | /// Module.Struct object allocated for it. | |
| 2535 | /// A non-packed struct type that has only a namespace; no fields. | |
| 2250 | 2536 | /// data is Module.Namespace.Index. |
| 2251 | 2537 | type_struct_ns, |
| 2252 | 2538 | /// An AnonStructType which stores types, names, and values for fields. |
| 2253 | 2539 | /// data is extra index of `TypeStructAnon`. |
| 2254 | 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 | 2547 | /// An AnonStructType which has only types and values for fields. |
| 2256 | 2548 | /// data is extra index of `TypeStructAnon`. |
| 2257 | 2549 | type_tuple_anon, |
| ... | ... | @@ -2461,9 +2753,10 @@ pub const Tag = enum(u8) { |
| 2461 | 2753 | .type_enum_nonexhaustive => EnumExplicit, |
| 2462 | 2754 | .simple_type => unreachable, |
| 2463 | 2755 | .type_opaque => OpaqueType, |
| 2464 | .type_struct => unreachable, | |
| 2756 | .type_struct => TypeStruct, | |
| 2465 | 2757 | .type_struct_ns => unreachable, |
| 2466 | 2758 | .type_struct_anon => TypeStructAnon, |
| 2759 | .type_struct_packed, .type_struct_packed_inits => TypeStructPacked, | |
| 2467 | 2760 | .type_tuple_anon => TypeStructAnon, |
| 2468 | 2761 | .type_union => TypeUnion, |
| 2469 | 2762 | .type_function => TypeFunction, |
| ... | ... | @@ -2634,11 +2927,90 @@ pub const Tag = enum(u8) { |
| 2634 | 2927 | any_aligned_fields: bool, |
| 2635 | 2928 | layout: std.builtin.Type.ContainerLayout, |
| 2636 | 2929 | status: UnionType.Status, |
| 2637 | requires_comptime: UnionType.RequiresComptime, | |
| 2930 | requires_comptime: RequiresComptime, | |
| 2638 | 2931 | assumed_runtime_bits: bool, |
| 2639 | 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 | 3016 | /// State that is mutable during semantic analysis. This data is not used for |
| ... | ... | @@ -2764,20 +3136,26 @@ pub const SimpleValue = enum(u32) { |
| 2764 | 3136 | |
| 2765 | 3137 | /// Stored as a power-of-two, with one special value to indicate none. |
| 2766 | 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 | 3145 | none = std.math.maxInt(u6), |
| 2768 | 3146 | _, |
| 2769 | 3147 | |
| 2770 | 3148 | pub fn toByteUnitsOptional(a: Alignment) ?u64 { |
| 2771 | 3149 | return switch (a) { |
| 2772 | 3150 | .none => null, |
| 2773 | _ => @as(u64, 1) << @intFromEnum(a), | |
| 3151 | else => @as(u64, 1) << @intFromEnum(a), | |
| 2774 | 3152 | }; |
| 2775 | 3153 | } |
| 2776 | 3154 | |
| 2777 | 3155 | pub fn toByteUnits(a: Alignment, default: u64) u64 { |
| 2778 | 3156 | return switch (a) { |
| 2779 | 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 | 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 | 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 | 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 | 3256 | /// An array of `Alignment` objects existing within the `extra` array. |
| 2801 | 3257 | /// This type exists to provide a struct with lifetime that is |
| 2802 | 3258 | /// not invalidated when items are added to the `InternPool`. |
| 2803 | 3259 | pub const Slice = struct { |
| 2804 | 3260 | start: u32, |
| 3261 | /// This is the number of alignment values, not the number of u32 elements. | |
| 2805 | 3262 | len: u32, |
| 2806 | 3263 | |
| 2807 | 3264 | pub fn get(slice: Slice, ip: *const InternPool) []Alignment { |
| ... | ... | @@ -2811,6 +3268,23 @@ pub const Alignment = enum(u6) { |
| 2811 | 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 | 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 | 3539 | ip.limbs.deinit(gpa); |
| 3066 | 3540 | ip.string_bytes.deinit(gpa); |
| 3067 | 3541 | |
| 3068 | ip.structs_free_list.deinit(gpa); | |
| 3069 | ip.allocated_structs.deinit(gpa); | |
| 3070 | ||
| 3071 | 3542 | ip.decls_free_list.deinit(gpa); |
| 3072 | 3543 | ip.allocated_decls.deinit(gpa); |
| 3073 | 3544 | |
| ... | ... | @@ -3149,24 +3620,43 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 3149 | 3620 | }, |
| 3150 | 3621 | |
| 3151 | 3622 | .type_opaque => .{ .opaque_type = ip.extraData(Key.OpaqueType, data) }, |
| 3152 | .type_struct => { | |
| 3153 | const struct_index: Module.Struct.OptionalIndex = @enumFromInt(data); | |
| 3154 | const namespace = if (struct_index.unwrap()) |i| | |
| 3155 | ip.structPtrConst(i).namespace.toOptional() | |
| 3156 | else | |
| 3157 | .none; | |
| 3158 | return .{ .struct_type = .{ | |
| 3159 | .index = struct_index, | |
| 3160 | .namespace = namespace, | |
| 3161 | } }; | |
| 3162 | }, | |
| 3623 | ||
| 3624 | .type_struct => .{ .struct_type = if (data == 0) .{ | |
| 3625 | .extra_index = 0, | |
| 3626 | .namespace = .none, | |
| 3627 | .decl = .none, | |
| 3628 | .zir_index = @as(u32, undefined), | |
| 3629 | .layout = .Auto, | |
| 3630 | .field_names = .{ .start = 0, .len = 0 }, | |
| 3631 | .field_types = .{ .start = 0, .len = 0 }, | |
| 3632 | .field_inits = .{ .start = 0, .len = 0 }, | |
| 3633 | .field_aligns = .{ .start = 0, .len = 0 }, | |
| 3634 | .runtime_order = .{ .start = 0, .len = 0 }, | |
| 3635 | .comptime_bits = .{ .start = 0, .len = 0 }, | |
| 3636 | .offsets = .{ .start = 0, .len = 0 }, | |
| 3637 | .names_map = undefined, | |
| 3638 | } else extraStructType(ip, data) }, | |
| 3639 | ||
| 3163 | 3640 | .type_struct_ns => .{ .struct_type = .{ |
| 3164 | .index = .none, | |
| 3641 | .extra_index = 0, | |
| 3165 | 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 | 3656 | .type_struct_anon => .{ .anon_struct_type = extraTypeStructAnon(ip, data) }, |
| 3169 | 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 | 3660 | .type_union => .{ .union_type = extraUnionType(ip, data) }, |
| 3171 | 3661 | |
| 3172 | 3662 | .type_enum_auto => { |
| ... | ... | @@ -3441,7 +3931,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 3441 | 3931 | .func_decl => .{ .func = ip.extraFuncDecl(data) }, |
| 3442 | 3932 | .func_coerced => .{ .func = ip.extraFuncCoerced(data) }, |
| 3443 | 3933 | .only_possible_value => { |
| 3444 | const ty = @as(Index, @enumFromInt(data)); | |
| 3934 | const ty: Index = @enumFromInt(data); | |
| 3445 | 3935 | const ty_item = ip.items.get(@intFromEnum(ty)); |
| 3446 | 3936 | return switch (ty_item.tag) { |
| 3447 | 3937 | .type_array_big => { |
| ... | ... | @@ -3454,20 +3944,33 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 3454 | 3944 | .storage = .{ .elems = sentinel[0..@intFromBool(sentinel[0] != .none)] }, |
| 3455 | 3945 | } }; |
| 3456 | 3946 | }, |
| 3457 | .type_array_small, .type_vector => .{ .aggregate = .{ | |
| 3458 | .ty = ty, | |
| 3459 | .storage = .{ .elems = &.{} }, | |
| 3460 | } }, | |
| 3461 | // TODO: migrate structs to properly use the InternPool rather | |
| 3462 | // than using the SegmentedList trick, then the struct type will | |
| 3463 | // have a slice of comptime values that can be used here for when | |
| 3464 | // the struct has one possible value due to all fields comptime (same | |
| 3465 | // as the tuple case below). | |
| 3466 | .type_struct, .type_struct_ns => .{ .aggregate = .{ | |
| 3947 | .type_array_small, | |
| 3948 | .type_vector, | |
| 3949 | .type_struct_ns, | |
| 3950 | .type_struct_packed, | |
| 3951 | => .{ .aggregate = .{ | |
| 3467 | 3952 | .ty = ty, |
| 3468 | 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 | 3974 | // There is only one possible value precisely due to the |
| 3472 | 3975 | // fact that this values slice is fully populated! |
| 3473 | 3976 | .type_struct_anon, .type_tuple_anon => { |
| ... | ... | @@ -3476,7 +3979,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 3476 | 3979 | const values = ip.extra.items[type_struct_anon.end + fields_len ..][0..fields_len]; |
| 3477 | 3980 | return .{ .aggregate = .{ |
| 3478 | 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 | 3993 | }, |
| 3491 | 3994 | .bytes => { |
| 3492 | 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 | 3997 | return .{ .aggregate = .{ |
| 3495 | 3998 | .ty = extra.ty, |
| 3496 | 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 | 4001 | }, |
| 3499 | 4002 | .aggregate => { |
| 3500 | 4003 | const extra = ip.extraDataTrail(Tag.Aggregate, data); |
| 3501 | const len = @as(u32, @intCast(ip.aggregateTypeLenIncludingSentinel(extra.data.ty))); | |
| 3502 | const fields = @as([]const Index, @ptrCast(ip.extra.items[extra.end..][0..len])); | |
| 4004 | const len: u32 = @intCast(ip.aggregateTypeLenIncludingSentinel(extra.data.ty)); | |
| 4005 | const fields: []const Index = @ptrCast(ip.extra.items[extra.end..][0..len]); | |
| 3503 | 4006 | return .{ .aggregate = .{ |
| 3504 | 4007 | .ty = extra.data.ty, |
| 3505 | 4008 | .storage = .{ .elems = fields }, |
| ... | ... | @@ -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 | 4212 | fn extraFuncType(ip: *const InternPool, extra_index: u32) Key.FuncType { |
| 3607 | 4213 | const type_function = ip.extraDataTrail(Tag.TypeFunction, extra_index); |
| 3608 | 4214 | var index: usize = type_function.end; |
| ... | ... | @@ -3831,8 +4437,9 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 3831 | 4437 | .error_set_type => |error_set_type| { |
| 3832 | 4438 | assert(error_set_type.names_map == .none); |
| 3833 | 4439 | assert(std.sort.isSorted(NullTerminatedString, error_set_type.names.get(ip), {}, NullTerminatedString.indexLessThan)); |
| 3834 | const names_map = try ip.addMap(gpa); | |
| 3835 | try addStringsToMap(ip, gpa, names_map, error_set_type.names.get(ip)); | |
| 4440 | const names = error_set_type.names.get(ip); | |
| 4441 | const names_map = try ip.addMap(gpa, names.len); | |
| 4442 | addStringsToMap(ip, names_map, names); | |
| 3836 | 4443 | const names_len = error_set_type.names.len; |
| 3837 | 4444 | try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.ErrorSet).Struct.fields.len + names_len); |
| 3838 | 4445 | ip.items.appendAssumeCapacity(.{ |
| ... | ... | @@ -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| { | |
| 3881 | ip.items.appendAssumeCapacity(if (struct_type.index.unwrap()) |i| .{ | |
| 3882 | .tag = .type_struct, | |
| 3883 | .data = @intFromEnum(i), | |
| 3884 | } else if (struct_type.namespace.unwrap()) |i| .{ | |
| 3885 | .tag = .type_struct_ns, | |
| 3886 | .data = @intFromEnum(i), | |
| 3887 | } else .{ | |
| 3888 | .tag = .type_struct, | |
| 3889 | .data = @intFromEnum(Module.Struct.OptionalIndex.none), | |
| 3890 | }); | |
| 3891 | }, | |
| 3892 | ||
| 4487 | .struct_type => unreachable, // use getStructType() instead | |
| 3893 | 4488 | .anon_struct_type => unreachable, // use getAnonStructType() instead |
| 3894 | ||
| 3895 | 4489 | .union_type => unreachable, // use getUnionType() instead |
| 3896 | 4490 | |
| 3897 | 4491 | .opaque_type => |opaque_type| { |
| ... | ... | @@ -3994,7 +4588,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 3994 | 4588 | }, |
| 3995 | 4589 | .struct_type => |struct_type| { |
| 3996 | 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 | 4593 | .union_type => |union_key| { |
| 4000 | 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 | 4982 | assert(ip.typeOf(elem) == child); |
| 4389 | 4983 | } |
| 4390 | 4984 | }, |
| 4391 | .struct_type => |struct_type| { | |
| 4392 | for ( | |
| 4393 | aggregate.storage.values(), | |
| 4394 | ip.structPtrUnwrapConst(struct_type.index).?.fields.values(), | |
| 4395 | ) |elem, field| { | |
| 4396 | assert(ip.typeOf(elem) == field.ty.toIntern()); | |
| 4985 | .struct_type => |t| { | |
| 4986 | for (aggregate.storage.values(), t.field_types.get(ip)) |elem, field_ty| { | |
| 4987 | assert(ip.typeOf(elem) == field_ty); | |
| 4397 | 4988 | } |
| 4398 | 4989 | }, |
| 4399 | 4990 | .anon_struct_type => |anon_struct_type| { |
| ... | ... | @@ -4635,6 +5226,138 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, ini: UnionTypeInit) Allocat |
| 4635 | 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 | 5361 | pub const AnonStructTypeInit = struct { |
| 4639 | 5362 | types: []const Index, |
| 4640 | 5363 | /// This may be empty, indicating this is a tuple. |
| ... | ... | @@ -4997,10 +5720,11 @@ pub fn getErrorSetType( |
| 4997 | 5720 | }); |
| 4998 | 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 | 5725 | errdefer _ = ip.maps.pop(); |
| 5002 | 5726 | |
| 5003 | try addStringsToMap(ip, gpa, names_map, names); | |
| 5727 | addStringsToMap(ip, names_map, names); | |
| 5004 | 5728 | |
| 5005 | 5729 | return @enumFromInt(ip.items.len - 1); |
| 5006 | 5730 | } |
| ... | ... | @@ -5299,19 +6023,9 @@ pub const IncompleteEnumType = struct { |
| 5299 | 6023 | pub fn addFieldName( |
| 5300 | 6024 | self: @This(), |
| 5301 | 6025 | ip: *InternPool, |
| 5302 | gpa: Allocator, | |
| 5303 | 6026 | name: NullTerminatedString, |
| 5304 | ) Allocator.Error!?u32 { | |
| 5305 | const map = &ip.maps.items[@intFromEnum(self.names_map)]; | |
| 5306 | const field_index = map.count(); | |
| 5307 | const strings = ip.extra.items[self.names_start..][0..field_index]; | |
| 5308 | const adapter: NullTerminatedString.Adapter = .{ | |
| 5309 | .strings = @as([]const NullTerminatedString, @ptrCast(strings)), | |
| 5310 | }; | |
| 5311 | const gop = try map.getOrPutAdapted(gpa, name, adapter); | |
| 5312 | if (gop.found_existing) return @intCast(gop.index); | |
| 5313 | ip.extra.items[self.names_start + field_index] = @intFromEnum(name); | |
| 5314 | return null; | |
| 6027 | ) ?u32 { | |
| 6028 | return ip.addFieldName(self.names_map, self.names_start, name); | |
| 5315 | 6029 | } |
| 5316 | 6030 | |
| 5317 | 6031 | /// Returns the already-existing field with the same value, if any. |
| ... | ... | @@ -5319,17 +6033,14 @@ pub const IncompleteEnumType = struct { |
| 5319 | 6033 | pub fn addFieldValue( |
| 5320 | 6034 | self: @This(), |
| 5321 | 6035 | ip: *InternPool, |
| 5322 | gpa: Allocator, | |
| 5323 | 6036 | value: Index, |
| 5324 | ) Allocator.Error!?u32 { | |
| 6037 | ) ?u32 { | |
| 5325 | 6038 | assert(ip.typeOf(value) == @as(Index, @enumFromInt(ip.extra.items[self.tag_ty_index]))); |
| 5326 | 6039 | const map = &ip.maps.items[@intFromEnum(self.values_map.unwrap().?)]; |
| 5327 | 6040 | const field_index = map.count(); |
| 5328 | 6041 | const indexes = ip.extra.items[self.values_start..][0..field_index]; |
| 5329 | const adapter: Index.Adapter = .{ | |
| 5330 | .indexes = @as([]const Index, @ptrCast(indexes)), | |
| 5331 | }; | |
| 5332 | const gop = try map.getOrPutAdapted(gpa, value, adapter); | |
| 6042 | const adapter: Index.Adapter = .{ .indexes = @ptrCast(indexes) }; | |
| 6043 | const gop = map.getOrPutAssumeCapacityAdapted(value, adapter); | |
| 5333 | 6044 | if (gop.found_existing) return @intCast(gop.index); |
| 5334 | 6045 | ip.extra.items[self.values_start + field_index] = @intFromEnum(value); |
| 5335 | 6046 | return null; |
| ... | ... | @@ -5370,7 +6081,7 @@ fn getIncompleteEnumAuto( |
| 5370 | 6081 | const gop = try ip.map.getOrPutAdapted(gpa, enum_type.toKey(), adapter); |
| 5371 | 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 | 6086 | const extra_fields_len: u32 = @typeInfo(EnumAuto).Struct.fields.len; |
| 5376 | 6087 | try ip.extra.ensureUnusedCapacity(gpa, extra_fields_len + enum_type.fields_len); |
| ... | ... | @@ -5390,7 +6101,7 @@ fn getIncompleteEnumAuto( |
| 5390 | 6101 | }); |
| 5391 | 6102 | ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), enum_type.fields_len); |
| 5392 | 6103 | return .{ |
| 5393 | .index = @as(Index, @enumFromInt(ip.items.len - 1)), | |
| 6104 | .index = @enumFromInt(ip.items.len - 1), | |
| 5394 | 6105 | .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?, |
| 5395 | 6106 | .names_map = names_map, |
| 5396 | 6107 | .names_start = extra_index + extra_fields_len, |
| ... | ... | @@ -5412,9 +6123,9 @@ fn getIncompleteEnumExplicit( |
| 5412 | 6123 | const gop = try ip.map.getOrPutAdapted(gpa, enum_type.toKey(), adapter); |
| 5413 | 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 | 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 | 6129 | break :m values_map.toOptional(); |
| 5419 | 6130 | }; |
| 5420 | 6131 | |
| ... | ... | @@ -5441,7 +6152,7 @@ fn getIncompleteEnumExplicit( |
| 5441 | 6152 | // This is both fields and values (if present). |
| 5442 | 6153 | ip.extra.appendNTimesAssumeCapacity(@intFromEnum(Index.none), reserved_len); |
| 5443 | 6154 | return .{ |
| 5444 | .index = @as(Index, @enumFromInt(ip.items.len - 1)), | |
| 6155 | .index = @enumFromInt(ip.items.len - 1), | |
| 5445 | 6156 | .tag_ty_index = extra_index + std.meta.fieldIndex(EnumExplicit, "int_tag_type").?, |
| 5446 | 6157 | .names_map = names_map, |
| 5447 | 6158 | .names_start = extra_index + extra_fields_len, |
| ... | ... | @@ -5484,8 +6195,8 @@ pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Erro |
| 5484 | 6195 | |
| 5485 | 6196 | switch (ini.tag_mode) { |
| 5486 | 6197 | .auto => { |
| 5487 | const names_map = try ip.addMap(gpa); | |
| 5488 | try addStringsToMap(ip, gpa, names_map, ini.names); | |
| 6198 | const names_map = try ip.addMap(gpa, ini.names.len); | |
| 6199 | addStringsToMap(ip, names_map, ini.names); | |
| 5489 | 6200 | |
| 5490 | 6201 | const fields_len: u32 = @intCast(ini.names.len); |
| 5491 | 6202 | try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumAuto).Struct.fields.len + |
| ... | ... | @@ -5514,12 +6225,12 @@ pub fn finishGetEnum( |
| 5514 | 6225 | ini: GetEnumInit, |
| 5515 | 6226 | tag: Tag, |
| 5516 | 6227 | ) Allocator.Error!Index { |
| 5517 | const names_map = try ip.addMap(gpa); | |
| 5518 | try addStringsToMap(ip, gpa, names_map, ini.names); | |
| 6228 | const names_map = try ip.addMap(gpa, ini.names.len); | |
| 6229 | addStringsToMap(ip, names_map, ini.names); | |
| 5519 | 6230 | |
| 5520 | 6231 | const values_map: OptionalMapIndex = if (ini.values.len == 0) .none else m: { |
| 5521 | const values_map = try ip.addMap(gpa); | |
| 5522 | try addIndexesToMap(ip, gpa, values_map, ini.values); | |
| 6232 | const values_map = try ip.addMap(gpa, ini.values.len); | |
| 6233 | addIndexesToMap(ip, values_map, ini.values); | |
| 5523 | 6234 | break :m values_map.toOptional(); |
| 5524 | 6235 | }; |
| 5525 | 6236 | const fields_len: u32 = @intCast(ini.names.len); |
| ... | ... | @@ -5553,35 +6264,35 @@ pub fn getAssumeExists(ip: *const InternPool, key: Key) Index { |
| 5553 | 6264 | |
| 5554 | 6265 | fn addStringsToMap( |
| 5555 | 6266 | ip: *InternPool, |
| 5556 | gpa: Allocator, | |
| 5557 | 6267 | map_index: MapIndex, |
| 5558 | 6268 | strings: []const NullTerminatedString, |
| 5559 | ) Allocator.Error!void { | |
| 6269 | ) void { | |
| 5560 | 6270 | const map = &ip.maps.items[@intFromEnum(map_index)]; |
| 5561 | 6271 | const adapter: NullTerminatedString.Adapter = .{ .strings = strings }; |
| 5562 | 6272 | for (strings) |string| { |
| 5563 | const gop = try map.getOrPutAdapted(gpa, string, adapter); | |
| 6273 | const gop = map.getOrPutAssumeCapacityAdapted(string, adapter); | |
| 5564 | 6274 | assert(!gop.found_existing); |
| 5565 | 6275 | } |
| 5566 | 6276 | } |
| 5567 | 6277 | |
| 5568 | 6278 | fn addIndexesToMap( |
| 5569 | 6279 | ip: *InternPool, |
| 5570 | gpa: Allocator, | |
| 5571 | 6280 | map_index: MapIndex, |
| 5572 | 6281 | indexes: []const Index, |
| 5573 | ) Allocator.Error!void { | |
| 6282 | ) void { | |
| 5574 | 6283 | const map = &ip.maps.items[@intFromEnum(map_index)]; |
| 5575 | 6284 | const adapter: Index.Adapter = .{ .indexes = indexes }; |
| 5576 | 6285 | for (indexes) |index| { |
| 5577 | const gop = try map.getOrPutAdapted(gpa, index, adapter); | |
| 6286 | const gop = map.getOrPutAssumeCapacityAdapted(index, adapter); | |
| 5578 | 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 | 6292 | const ptr = try ip.maps.addOne(gpa); |
| 6293 | errdefer _ = ip.maps.pop(); | |
| 5584 | 6294 | ptr.* = .{}; |
| 6295 | try ptr.ensureTotalCapacity(gpa, cap); | |
| 5585 | 6296 | return @enumFromInt(ip.maps.items.len - 1); |
| 5586 | 6297 | } |
| 5587 | 6298 | |
| ... | ... | @@ -5632,8 +6343,9 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 { |
| 5632 | 6343 | Tag.TypePointer.Flags, |
| 5633 | 6344 | Tag.TypeFunction.Flags, |
| 5634 | 6345 | Tag.TypePointer.PackedOffset, |
| 5635 | Tag.Variable.Flags, | |
| 5636 | 6346 | Tag.TypeUnion.Flags, |
| 6347 | Tag.TypeStruct.Flags, | |
| 6348 | Tag.Variable.Flags, | |
| 5637 | 6349 | => @bitCast(@field(extra, field.name)), |
| 5638 | 6350 | |
| 5639 | 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 | 6417 | Tag.TypeFunction.Flags, |
| 5706 | 6418 | Tag.TypePointer.PackedOffset, |
| 5707 | 6419 | Tag.TypeUnion.Flags, |
| 6420 | Tag.TypeStruct.Flags, | |
| 5708 | 6421 | Tag.Variable.Flags, |
| 5709 | 6422 | FuncAnalysis, |
| 5710 | 6423 | => @bitCast(int32), |
| ... | ... | @@ -6093,8 +6806,7 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al |
| 6093 | 6806 | const new_elem_ty = switch (ip.indexToKey(new_ty)) { |
| 6094 | 6807 | inline .array_type, .vector_type => |seq_type| seq_type.child, |
| 6095 | 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().?) | |
| 6097 | .fields.values()[i].ty.toIntern(), | |
| 6809 | .struct_type => |struct_type| struct_type.field_types.get(ip)[i], | |
| 6098 | 6810 | else => unreachable, |
| 6099 | 6811 | }; |
| 6100 | 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 | 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 | 6921 | pub fn indexToFuncType(ip: *const InternPool, val: Index) ?Key.FuncType { |
| 6229 | 6922 | assert(val != .none); |
| 6230 | 6923 | const tags = ip.items.items(.tag); |
| ... | ... | @@ -6337,20 +7030,16 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void { |
| 6337 | 7030 | const items_size = (1 + 4) * ip.items.len; |
| 6338 | 7031 | const extra_size = 4 * ip.extra.items.len; |
| 6339 | 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 | 7033 | const decls_size = ip.allocated_decls.len * @sizeOf(Module.Decl); |
| 6344 | 7034 | |
| 6345 | 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 | 7038 | std.debug.print( |
| 6349 | 7039 | \\InternPool size: {d} bytes |
| 6350 | 7040 | \\ {d} items: {d} bytes |
| 6351 | 7041 | \\ {d} extra: {d} bytes |
| 6352 | 7042 | \\ {d} limbs: {d} bytes |
| 6353 | \\ {d} structs: {d} bytes | |
| 6354 | 7043 | \\ {d} decls: {d} bytes |
| 6355 | 7044 | \\ |
| 6356 | 7045 | , .{ |
| ... | ... | @@ -6361,8 +7050,6 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void { |
| 6361 | 7050 | extra_size, |
| 6362 | 7051 | ip.limbs.items.len, |
| 6363 | 7052 | limbs_size, |
| 6364 | ip.allocated_structs.len, | |
| 6365 | structs_size, | |
| 6366 | 7053 | ip.allocated_decls.len, |
| 6367 | 7054 | decls_size, |
| 6368 | 7055 | }); |
| ... | ... | @@ -6399,17 +7086,40 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void { |
| 6399 | 7086 | .type_enum_auto => @sizeOf(EnumAuto), |
| 6400 | 7087 | .type_opaque => @sizeOf(Key.OpaqueType), |
| 6401 | 7088 | .type_struct => b: { |
| 6402 | const struct_index = @as(Module.Struct.Index, @enumFromInt(data)); | |
| 6403 | const struct_obj = ip.structPtrConst(struct_index); | |
| 6404 | break :b @sizeOf(Module.Struct) + | |
| 6405 | @sizeOf(Module.Namespace) + | |
| 6406 | (struct_obj.fields.count() * @sizeOf(Module.Struct.Field)); | |
| 7089 | const info = ip.extraData(Tag.TypeStruct, data); | |
| 7090 | var ints: usize = @typeInfo(Tag.TypeStruct).Struct.fields.len; | |
| 7091 | ints += info.fields_len; // types | |
| 7092 | if (!info.flags.is_tuple) { | |
| 7093 | ints += 1; // names_map | |
| 7094 | ints += info.fields_len; // names | |
| 7095 | } | |
| 7096 | if (info.flags.any_default_inits) | |
| 7097 | ints += info.fields_len; // inits | |
| 7098 | ints += @intFromBool(info.flags.has_namespace); // namespace | |
| 7099 | if (info.flags.any_aligned_fields) | |
| 7100 | ints += (info.fields_len + 3) / 4; // aligns | |
| 7101 | if (info.flags.any_comptime_fields) | |
| 7102 | ints += (info.fields_len + 31) / 32; // comptime bits | |
| 7103 | if (!info.flags.is_extern) | |
| 7104 | ints += info.fields_len; // runtime order | |
| 7105 | ints += info.fields_len; // offsets | |
| 7106 | break :b @sizeOf(u32) * ints; | |
| 6407 | 7107 | }, |
| 6408 | 7108 | .type_struct_ns => @sizeOf(Module.Namespace), |
| 6409 | 7109 | .type_struct_anon => b: { |
| 6410 | 7110 | const info = ip.extraData(TypeStructAnon, data); |
| 6411 | 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 | 7123 | .type_tuple_anon => b: { |
| 6414 | 7124 | const info = ip.extraData(TypeStructAnon, data); |
| 6415 | 7125 | break :b @sizeOf(TypeStructAnon) + (@sizeOf(u32) * 2 * info.fields_len); |
| ... | ... | @@ -6562,6 +7272,8 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void { |
| 6562 | 7272 | .type_struct, |
| 6563 | 7273 | .type_struct_ns, |
| 6564 | 7274 | .type_struct_anon, |
| 7275 | .type_struct_packed, | |
| 7276 | .type_struct_packed_inits, | |
| 6565 | 7277 | .type_tuple_anon, |
| 6566 | 7278 | .type_union, |
| 6567 | 7279 | .type_function, |
| ... | ... | @@ -6677,18 +7389,6 @@ pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator) |
| 6677 | 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 | 7392 | pub fn declPtr(ip: *InternPool, index: Module.Decl.Index) *Module.Decl { |
| 6693 | 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 | 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 | 7404 | pub fn createDecl( |
| 6727 | 7405 | ip: *InternPool, |
| 6728 | 7406 | gpa: Allocator, |
| ... | ... | @@ -6967,6 +7645,8 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index { |
| 6967 | 7645 | .type_struct, |
| 6968 | 7646 | .type_struct_ns, |
| 6969 | 7647 | .type_struct_anon, |
| 7648 | .type_struct_packed, | |
| 7649 | .type_struct_packed_inits, | |
| 6970 | 7650 | .type_tuple_anon, |
| 6971 | 7651 | .type_union, |
| 6972 | 7652 | .type_function, |
| ... | ... | @@ -7056,7 +7736,7 @@ pub fn toEnum(ip: *const InternPool, comptime E: type, i: Index) E { |
| 7056 | 7736 | |
| 7057 | 7737 | pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 { |
| 7058 | 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 | 7740 | .anon_struct_type => |anon_struct_type| anon_struct_type.types.len, |
| 7061 | 7741 | .array_type => |array_type| array_type.len, |
| 7062 | 7742 | .vector_type => |vector_type| vector_type.len, |
| ... | ... | @@ -7066,7 +7746,7 @@ pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 { |
| 7066 | 7746 | |
| 7067 | 7747 | pub fn aggregateTypeLenIncludingSentinel(ip: *const InternPool, ty: Index) u64 { |
| 7068 | 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 | 7750 | .anon_struct_type => |anon_struct_type| anon_struct_type.types.len, |
| 7071 | 7751 | .array_type => |array_type| array_type.len + @intFromBool(array_type.sentinel != .none), |
| 7072 | 7752 | .vector_type => |vector_type| vector_type.len, |
| ... | ... | @@ -7301,6 +7981,8 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois |
| 7301 | 7981 | .type_struct, |
| 7302 | 7982 | .type_struct_ns, |
| 7303 | 7983 | .type_struct_anon, |
| 7984 | .type_struct_packed, | |
| 7985 | .type_struct_packed_inits, | |
| 7304 | 7986 | .type_tuple_anon, |
| 7305 | 7987 | => .Struct, |
| 7306 | 7988 | |
| ... | ... | @@ -7526,6 +8208,40 @@ pub fn resolveBuiltinType(ip: *InternPool, want_index: Index, resolved_index: In |
| 7526 | 8208 | .data = @intFromEnum(SimpleValue.@"unreachable"), |
| 7527 | 8209 | }); |
| 7528 | 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 | 105 | |
| 106 | 106 | /// To be eliminated in a future commit by moving more data into InternPool. |
| 107 | 107 | /// Current uses that must be eliminated: |
| 108 | /// * Struct comptime_args | |
| 109 | /// * Struct optimized_order | |
| 110 | 108 | /// * comptime pointer mutation |
| 111 | 109 | /// This memory lives until the Module is destroyed. |
| 112 | 110 | tmp_hack_arena: std.heap.ArenaAllocator, |
| ... | ... | @@ -678,14 +676,10 @@ pub const Decl = struct { |
| 678 | 676 | |
| 679 | 677 | /// If the Decl owns its value and it is a struct, return it, |
| 680 | 678 | /// otherwise null. |
| 681 | pub fn getOwnedStruct(decl: Decl, mod: *Module) ?*Struct { | |
| 682 | return mod.structPtrUnwrap(decl.getOwnedStructIndex(mod)); | |
| 683 | } | |
| 684 | ||
| 685 | pub fn getOwnedStructIndex(decl: Decl, mod: *Module) Struct.OptionalIndex { | |
| 686 | if (!decl.owns_tv) return .none; | |
| 687 | if (decl.val.ip_index == .none) return .none; | |
| 688 | return mod.intern_pool.indexToStructType(decl.val.toIntern()); | |
| 679 | pub fn getOwnedStruct(decl: Decl, mod: *Module) ?InternPool.Key.StructType { | |
| 680 | if (!decl.owns_tv) return null; | |
| 681 | if (decl.val.ip_index == .none) return null; | |
| 682 | return mod.typeToStruct(decl.val.toType()); | |
| 689 | 683 | } |
| 690 | 684 | |
| 691 | 685 | /// If the Decl owns its value and it is a union, return it, |
| ... | ... | @@ -795,9 +789,10 @@ pub const Decl = struct { |
| 795 | 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 | 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 | 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 | 804 | pub const DeclAdapter = struct { |
| 1022 | 805 | mod: *Module, |
| 1023 | 806 | |
| ... | ... | @@ -2893,20 +2676,10 @@ pub fn namespacePtr(mod: *Module, index: Namespace.Index) *Namespace { |
| 2893 | 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 | 2679 | pub fn namespacePtrUnwrap(mod: *Module, index: Namespace.OptionalIndex) ?*Namespace { |
| 2901 | 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 | 2683 | /// Returns true if and only if the Decl is the top level struct associated with a File. |
| 2911 | 2684 | pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool { |
| 2912 | 2685 | const decl = mod.declPtr(decl_index); |
| ... | ... | @@ -3351,11 +3124,11 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void { |
| 3351 | 3124 | |
| 3352 | 3125 | if (!decl.owns_tv) continue; |
| 3353 | 3126 | |
| 3354 | if (decl.getOwnedStruct(mod)) |struct_obj| { | |
| 3355 | struct_obj.zir_index = inst_map.get(struct_obj.zir_index) orelse { | |
| 3127 | if (decl.getOwnedStruct(mod)) |struct_type| { | |
| 3128 | struct_type.setZirIndex(ip, inst_map.get(struct_type.zir_index) orelse { | |
| 3356 | 3129 | try file.deleted_decls.append(gpa, decl_index); |
| 3357 | 3130 | continue; |
| 3358 | }; | |
| 3131 | }); | |
| 3359 | 3132 | } |
| 3360 | 3133 | |
| 3361 | 3134 | if (decl.getOwnedUnion(mod)) |union_type| { |
| ... | ... | @@ -3870,36 +3643,16 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { |
| 3870 | 3643 | const new_decl = mod.declPtr(new_decl_index); |
| 3871 | 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 | 3646 | file.root_decl = new_decl_index.toOptional(); |
| 3894 | 3647 | |
| 3895 | 3648 | new_decl.name = try file.fullyQualifiedName(mod); |
| 3649 | new_decl.name_fully_qualified = true; | |
| 3896 | 3650 | new_decl.src_line = 0; |
| 3897 | 3651 | new_decl.is_pub = true; |
| 3898 | 3652 | new_decl.is_exported = false; |
| 3899 | 3653 | new_decl.has_align = false; |
| 3900 | 3654 | new_decl.has_linksection_or_addrspace = false; |
| 3901 | 3655 | new_decl.ty = Type.type; |
| 3902 | new_decl.val = struct_ty.toValue(); | |
| 3903 | 3656 | new_decl.alignment = .none; |
| 3904 | 3657 | new_decl.@"linksection" = .none; |
| 3905 | 3658 | new_decl.has_tv = true; |
| ... | ... | @@ -3907,75 +3660,76 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { |
| 3907 | 3660 | new_decl.alive = true; // This Decl corresponds to a File and is therefore always alive. |
| 3908 | 3661 | new_decl.analysis = .in_progress; |
| 3909 | 3662 | new_decl.generation = mod.generation; |
| 3910 | new_decl.name_fully_qualified = true; | |
| 3911 | 3663 | |
| 3912 | if (file.status == .success_zir) { | |
| 3913 | assert(file.zir_loaded); | |
| 3914 | const main_struct_inst = Zir.main_struct_inst; | |
| 3915 | const struct_obj = mod.structPtr(struct_index); | |
| 3916 | struct_obj.zir_index = main_struct_inst; | |
| 3917 | const extended = file.zir.instructions.items(.data)[main_struct_inst].extended; | |
| 3918 | const small = @as(Zir.Inst.StructDecl.Small, @bitCast(extended.small)); | |
| 3919 | struct_obj.is_tuple = small.is_tuple; | |
| 3920 | ||
| 3921 | var sema_arena = std.heap.ArenaAllocator.init(gpa); | |
| 3922 | defer sema_arena.deinit(); | |
| 3923 | const sema_arena_allocator = sema_arena.allocator(); | |
| 3924 | ||
| 3925 | var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa); | |
| 3926 | defer comptime_mutable_decls.deinit(); | |
| 3927 | ||
| 3928 | var sema: Sema = .{ | |
| 3929 | .mod = mod, | |
| 3930 | .gpa = gpa, | |
| 3931 | .arena = sema_arena_allocator, | |
| 3932 | .code = file.zir, | |
| 3933 | .owner_decl = new_decl, | |
| 3934 | .owner_decl_index = new_decl_index, | |
| 3935 | .func_index = .none, | |
| 3936 | .func_is_naked = false, | |
| 3937 | .fn_ret_ty = Type.void, | |
| 3938 | .fn_ret_ty_ies = null, | |
| 3939 | .owner_func_index = .none, | |
| 3940 | .comptime_mutable_decls = &comptime_mutable_decls, | |
| 3941 | }; | |
| 3942 | defer sema.deinit(); | |
| 3664 | if (file.status != .success_zir) { | |
| 3665 | new_decl.analysis = .file_failure; | |
| 3666 | return; | |
| 3667 | } | |
| 3668 | assert(file.zir_loaded); | |
| 3943 | 3669 | |
| 3944 | if (sema.analyzeStructDecl(new_decl, main_struct_inst, struct_index)) |_| { | |
| 3945 | for (comptime_mutable_decls.items) |decl_index| { | |
| 3946 | const decl = mod.declPtr(decl_index); | |
| 3947 | _ = try decl.internValue(mod); | |
| 3948 | } | |
| 3949 | new_decl.analysis = .complete; | |
| 3950 | } else |err| switch (err) { | |
| 3951 | error.OutOfMemory => return error.OutOfMemory, | |
| 3952 | error.AnalysisFail => {}, | |
| 3953 | } | |
| 3670 | var sema_arena = std.heap.ArenaAllocator.init(gpa); | |
| 3671 | defer sema_arena.deinit(); | |
| 3672 | const sema_arena_allocator = sema_arena.allocator(); | |
| 3954 | 3673 | |
| 3955 | if (mod.comp.whole_cache_manifest) |whole_cache_manifest| { | |
| 3956 | const source = file.getSource(gpa) catch |err| { | |
| 3957 | try reportRetryableFileError(mod, file, "unable to load source: {s}", .{@errorName(err)}); | |
| 3958 | return error.AnalysisFail; | |
| 3959 | }; | |
| 3674 | var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa); | |
| 3675 | defer comptime_mutable_decls.deinit(); | |
| 3960 | 3676 | |
| 3961 | const resolved_path = std.fs.path.resolve( | |
| 3962 | gpa, | |
| 3963 | if (file.pkg.root_src_directory.path) |pkg_path| | |
| 3964 | &[_][]const u8{ pkg_path, file.sub_file_path } | |
| 3965 | else | |
| 3966 | &[_][]const u8{file.sub_file_path}, | |
| 3967 | ) catch |err| { | |
| 3968 | try reportRetryableFileError(mod, file, "unable to resolve path: {s}", .{@errorName(err)}); | |
| 3969 | return error.AnalysisFail; | |
| 3970 | }; | |
| 3971 | errdefer gpa.free(resolved_path); | |
| 3677 | var sema: Sema = .{ | |
| 3678 | .mod = mod, | |
| 3679 | .gpa = gpa, | |
| 3680 | .arena = sema_arena_allocator, | |
| 3681 | .code = file.zir, | |
| 3682 | .owner_decl = new_decl, | |
| 3683 | .owner_decl_index = new_decl_index, | |
| 3684 | .func_index = .none, | |
| 3685 | .func_is_naked = false, | |
| 3686 | .fn_ret_ty = Type.void, | |
| 3687 | .fn_ret_ty_ies = null, | |
| 3688 | .owner_func_index = .none, | |
| 3689 | .comptime_mutable_decls = &comptime_mutable_decls, | |
| 3690 | }; | |
| 3691 | defer sema.deinit(); | |
| 3972 | 3692 | |
| 3973 | mod.comp.whole_cache_manifest_mutex.lock(); | |
| 3974 | defer mod.comp.whole_cache_manifest_mutex.unlock(); | |
| 3975 | try whole_cache_manifest.addFilePostContents(resolved_path, source.bytes, source.stat); | |
| 3976 | } | |
| 3977 | } else { | |
| 3978 | new_decl.analysis = .file_failure; | |
| 3693 | const main_struct_inst = Zir.main_struct_inst; | |
| 3694 | const struct_ty = sema.getStructType( | |
| 3695 | new_decl_index, | |
| 3696 | new_namespace_index, | |
| 3697 | main_struct_inst, | |
| 3698 | ) catch |err| switch (err) { | |
| 3699 | error.OutOfMemory => return error.OutOfMemory, | |
| 3700 | }; | |
| 3701 | // TODO: figure out InternPool removals for incremental compilation | |
| 3702 | //errdefer ip.remove(struct_ty); | |
| 3703 | for (comptime_mutable_decls.items) |decl_index| { | |
| 3704 | const decl = mod.declPtr(decl_index); | |
| 3705 | _ = try decl.internValue(mod); | |
| 3706 | } | |
| 3707 | ||
| 3708 | new_namespace.ty = struct_ty.toType(); | |
| 3709 | new_decl.val = struct_ty.toValue(); | |
| 3710 | new_decl.analysis = .complete; | |
| 3711 | ||
| 3712 | if (mod.comp.whole_cache_manifest) |whole_cache_manifest| { | |
| 3713 | const source = file.getSource(gpa) catch |err| { | |
| 3714 | try reportRetryableFileError(mod, file, "unable to load source: {s}", .{@errorName(err)}); | |
| 3715 | return error.AnalysisFail; | |
| 3716 | }; | |
| 3717 | ||
| 3718 | const resolved_path = std.fs.path.resolve( | |
| 3719 | gpa, | |
| 3720 | if (file.pkg.root_src_directory.path) |pkg_path| | |
| 3721 | &[_][]const u8{ pkg_path, file.sub_file_path } | |
| 3722 | else | |
| 3723 | &[_][]const u8{file.sub_file_path}, | |
| 3724 | ) catch |err| { | |
| 3725 | try reportRetryableFileError(mod, file, "unable to resolve path: {s}", .{@errorName(err)}); | |
| 3726 | return error.AnalysisFail; | |
| 3727 | }; | |
| 3728 | errdefer gpa.free(resolved_path); | |
| 3729 | ||
| 3730 | mod.comp.whole_cache_manifest_mutex.lock(); | |
| 3731 | defer mod.comp.whole_cache_manifest_mutex.unlock(); | |
| 3732 | try whole_cache_manifest.addFilePostContents(resolved_path, source.bytes, source.stat); | |
| 3979 | 3733 | } |
| 3980 | 3734 | } |
| 3981 | 3735 | |
| ... | ... | @@ -4055,18 +3809,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4055 | 3809 | }; |
| 4056 | 3810 | defer sema.deinit(); |
| 4057 | 3811 | |
| 4058 | if (mod.declIsRoot(decl_index)) { | |
| 4059 | const main_struct_inst = Zir.main_struct_inst; | |
| 4060 | const struct_index = decl.getOwnedStructIndex(mod).unwrap().?; | |
| 4061 | const struct_obj = mod.structPtr(struct_index); | |
| 4062 | // This might not have gotten set in `semaFile` if the first time had | |
| 4063 | // a ZIR failure, so we set it here in case. | |
| 4064 | struct_obj.zir_index = main_struct_inst; | |
| 4065 | try sema.analyzeStructDecl(decl, main_struct_inst, struct_index); | |
| 4066 | decl.analysis = .complete; | |
| 4067 | decl.generation = mod.generation; | |
| 4068 | return false; | |
| 4069 | } | |
| 3812 | assert(!mod.declIsRoot(decl_index)); | |
| 4070 | 3813 | |
| 4071 | 3814 | var block_scope: Sema.Block = .{ |
| 4072 | 3815 | .parent = null, |
| ... | ... | @@ -5241,14 +4984,6 @@ pub fn destroyNamespace(mod: *Module, index: Namespace.Index) void { |
| 5241 | 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 | 4987 | pub fn allocateNewDecl( |
| 5253 | 4988 | mod: *Module, |
| 5254 | 4989 | namespace: Namespace.Index, |
| ... | ... | @@ -6202,7 +5937,6 @@ pub fn optionalType(mod: *Module, child_type: InternPool.Index) Allocator.Error! |
| 6202 | 5937 | |
| 6203 | 5938 | pub fn ptrType(mod: *Module, info: InternPool.Key.PtrType) Allocator.Error!Type { |
| 6204 | 5939 | var canon_info = info; |
| 6205 | const have_elem_layout = info.child.toType().layoutIsResolved(mod); | |
| 6206 | 5940 | |
| 6207 | 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 | 5944 | // type, we change it to 0 here. If this causes an assertion trip because the |
| 6211 | 5945 | // pointee type needs to be resolved more, that needs to be done before calling |
| 6212 | 5946 | // this ptr() function. |
| 6213 | if (info.flags.alignment.toByteUnitsOptional()) |info_align| { | |
| 6214 | if (have_elem_layout and info_align == info.child.toType().abiAlignment(mod)) { | |
| 6215 | canon_info.flags.alignment = .none; | |
| 6216 | } | |
| 5947 | if (info.flags.alignment != .none and | |
| 5948 | info.flags.alignment == info.child.toType().abiAlignment(mod)) | |
| 5949 | { | |
| 5950 | canon_info.flags.alignment = .none; | |
| 6217 | 5951 | } |
| 6218 | 5952 | |
| 6219 | 5953 | switch (info.flags.vector_index) { |
| 6220 | 5954 | // Canonicalize host_size. If it matches the bit size of the pointee type, |
| 6221 | 5955 | // we change it to 0 here. If this causes an assertion trip, the pointee type |
| 6222 | 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 | 5958 | const elem_bit_size = info.child.toType().bitSize(mod); |
| 6225 | 5959 | assert(info.packed_offset.bit_offset + elem_bit_size <= info.packed_offset.host_size * 8); |
| 6226 | 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 | 6217 | return @as(u16, @intCast(big.bitCountTwosComp())); |
| 6484 | 6218 | }, |
| 6485 | 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 | 6222 | .lazy_size => |lazy_ty| { |
| 6489 | 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 | 6373 | /// * `@TypeOf(.{})` |
| 6640 | 6374 | /// * A struct which has no fields (`struct {}`). |
| 6641 | 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 | 6377 | if (ty.ip_index == .none) return null; |
| 6644 | const struct_index = mod.intern_pool.indexToStructType(ty.toIntern()).unwrap() orelse return null; | |
| 6645 | return mod.structPtr(struct_index); | |
| 6378 | return switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 6379 | .struct_type => |t| t, | |
| 6380 | else => null, | |
| 6381 | }; | |
| 6382 | } | |
| 6383 | ||
| 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 | 6392 | /// This asserts that the union's enum tag type has been resolved. |
| 6649 | 6393 | pub fn typeToUnion(mod: *Module, ty: Type) ?InternPool.UnionType { |
| 6650 | 6394 | if (ty.ip_index == .none) return null; |
| 6651 | 6395 | const ip = &mod.intern_pool; |
| 6652 | switch (ip.indexToKey(ty.ip_index)) { | |
| 6653 | .union_type => |k| return ip.loadUnionType(k), | |
| 6654 | else => return null, | |
| 6655 | } | |
| 6396 | return switch (ip.indexToKey(ty.ip_index)) { | |
| 6397 | .union_type => |k| ip.loadUnionType(k), | |
| 6398 | else => null, | |
| 6399 | }; | |
| 6656 | 6400 | } |
| 6657 | 6401 | |
| 6658 | 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 | 6485 | |
| 6742 | 6486 | pub const UnionLayout = struct { |
| 6743 | 6487 | abi_size: u64, |
| 6744 | abi_align: u32, | |
| 6488 | abi_align: Alignment, | |
| 6745 | 6489 | most_aligned_field: u32, |
| 6746 | 6490 | most_aligned_field_size: u64, |
| 6747 | 6491 | biggest_field: u32, |
| 6748 | 6492 | payload_size: u64, |
| 6749 | payload_align: u32, | |
| 6750 | tag_align: u32, | |
| 6493 | payload_align: Alignment, | |
| 6494 | tag_align: Alignment, | |
| 6751 | 6495 | tag_size: u64, |
| 6752 | 6496 | padding: u32, |
| 6753 | 6497 | }; |
| ... | ... | @@ -6759,35 +6503,37 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout { |
| 6759 | 6503 | var most_aligned_field_size: u64 = undefined; |
| 6760 | 6504 | var biggest_field: u32 = undefined; |
| 6761 | 6505 | var payload_size: u64 = 0; |
| 6762 | var payload_align: u32 = 0; | |
| 6506 | var payload_align: Alignment = .@"1"; | |
| 6763 | 6507 | for (u.field_types.get(ip), 0..) |field_ty, i| { |
| 6764 | 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 | 6514 | field_ty.toType().abiAlignment(mod); |
| 6768 | 6515 | const field_size = field_ty.toType().abiSize(mod); |
| 6769 | 6516 | if (field_size > payload_size) { |
| 6770 | 6517 | payload_size = field_size; |
| 6771 | 6518 | biggest_field = @intCast(i); |
| 6772 | 6519 | } |
| 6773 | if (field_align > payload_align) { | |
| 6774 | payload_align = @intCast(field_align); | |
| 6520 | if (field_align.compare(.gte, payload_align)) { | |
| 6521 | payload_align = field_align; | |
| 6775 | 6522 | most_aligned_field = @intCast(i); |
| 6776 | 6523 | most_aligned_field_size = field_size; |
| 6777 | 6524 | } |
| 6778 | 6525 | } |
| 6779 | payload_align = @max(payload_align, 1); | |
| 6780 | 6526 | const have_tag = u.flagsPtr(ip).runtime_tag.hasTag(); |
| 6781 | 6527 | if (!have_tag or !u.enum_tag_ty.toType().hasRuntimeBits(mod)) { |
| 6782 | 6528 | return .{ |
| 6783 | .abi_size = std.mem.alignForward(u64, payload_size, payload_align), | |
| 6529 | .abi_size = payload_align.forward(payload_size), | |
| 6784 | 6530 | .abi_align = payload_align, |
| 6785 | 6531 | .most_aligned_field = most_aligned_field, |
| 6786 | 6532 | .most_aligned_field_size = most_aligned_field_size, |
| 6787 | 6533 | .biggest_field = biggest_field, |
| 6788 | 6534 | .payload_size = payload_size, |
| 6789 | 6535 | .payload_align = payload_align, |
| 6790 | .tag_align = 0, | |
| 6536 | .tag_align = .none, | |
| 6791 | 6537 | .tag_size = 0, |
| 6792 | 6538 | .padding = 0, |
| 6793 | 6539 | }; |
| ... | ... | @@ -6795,29 +6541,29 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout { |
| 6795 | 6541 | // Put the tag before or after the payload depending on which one's |
| 6796 | 6542 | // alignment is greater. |
| 6797 | 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 | 6545 | var size: u64 = 0; |
| 6800 | 6546 | var padding: u32 = undefined; |
| 6801 | if (tag_align >= payload_align) { | |
| 6547 | if (tag_align.compare(.gte, payload_align)) { | |
| 6802 | 6548 | // {Tag, Payload} |
| 6803 | 6549 | size += tag_size; |
| 6804 | size = std.mem.alignForward(u64, size, payload_align); | |
| 6550 | size = payload_align.forward(size); | |
| 6805 | 6551 | size += payload_size; |
| 6806 | 6552 | const prev_size = size; |
| 6807 | size = std.mem.alignForward(u64, size, tag_align); | |
| 6808 | padding = @as(u32, @intCast(size - prev_size)); | |
| 6553 | size = tag_align.forward(size); | |
| 6554 | padding = @intCast(size - prev_size); | |
| 6809 | 6555 | } else { |
| 6810 | 6556 | // {Payload, Tag} |
| 6811 | 6557 | size += payload_size; |
| 6812 | size = std.mem.alignForward(u64, size, tag_align); | |
| 6558 | size = tag_align.forward(size); | |
| 6813 | 6559 | size += tag_size; |
| 6814 | 6560 | const prev_size = size; |
| 6815 | size = std.mem.alignForward(u64, size, payload_align); | |
| 6816 | padding = @as(u32, @intCast(size - prev_size)); | |
| 6561 | size = payload_align.forward(size); | |
| 6562 | padding = @intCast(size - prev_size); | |
| 6817 | 6563 | } |
| 6818 | 6564 | return .{ |
| 6819 | 6565 | .abi_size = size, |
| 6820 | .abi_align = @max(tag_align, payload_align), | |
| 6566 | .abi_align = tag_align.max(payload_align), | |
| 6821 | 6567 | .most_aligned_field = most_aligned_field, |
| 6822 | 6568 | .most_aligned_field_size = most_aligned_field_size, |
| 6823 | 6569 | .biggest_field = biggest_field, |
| ... | ... | @@ -6834,17 +6580,16 @@ pub fn unionAbiSize(mod: *Module, u: InternPool.UnionType) u64 { |
| 6834 | 6580 | } |
| 6835 | 6581 | |
| 6836 | 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 | |
| 6838 | pub fn unionAbiAlignment(mod: *Module, u: InternPool.UnionType) u32 { | |
| 6583 | pub fn unionAbiAlignment(mod: *Module, u: InternPool.UnionType) Alignment { | |
| 6839 | 6584 | const ip = &mod.intern_pool; |
| 6840 | 6585 | const have_tag = u.flagsPtr(ip).runtime_tag.hasTag(); |
| 6841 | var max_align: u32 = 0; | |
| 6586 | var max_align: Alignment = .none; | |
| 6842 | 6587 | if (have_tag) max_align = u.enum_tag_ty.toType().abiAlignment(mod); |
| 6843 | 6588 | for (u.field_types.get(ip), 0..) |field_ty, field_index| { |
| 6844 | 6589 | if (!field_ty.toType().hasRuntimeBits(mod)) continue; |
| 6845 | 6590 | |
| 6846 | 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 | 6594 | return max_align; |
| 6850 | 6595 | } |
| ... | ... | @@ -6852,10 +6597,10 @@ pub fn unionAbiAlignment(mod: *Module, u: InternPool.UnionType) u32 { |
| 6852 | 6597 | /// Returns the field alignment, assuming the union is not packed. |
| 6853 | 6598 | /// Keep implementation in sync with `Sema.unionFieldAlignment`. |
| 6854 | 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 | |
| 6856 | pub fn unionFieldNormalAlignment(mod: *Module, u: InternPool.UnionType, field_index: u32) u32 { | |
| 6600 | pub fn unionFieldNormalAlignment(mod: *Module, u: InternPool.UnionType, field_index: u32) Alignment { | |
| 6857 | 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 | 6604 | const field_ty = u.field_types.get(ip)[field_index].toType(); |
| 6860 | 6605 | return field_ty.abiAlignment(mod); |
| 6861 | 6606 | } |
| ... | ... | @@ -6866,3 +6611,64 @@ pub fn unionTagFieldIndex(mod: *Module, u: InternPool.UnionType, enum_tag: Value |
| 6866 | 6611 | const enum_type = ip.indexToKey(u.enum_tag_ty).enum_type; |
| 6867 | 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 | 2221 | const msg = try sema.errMsg(block, init_src, "value stored in comptime field does not match the default value of the field", .{}); |
| 2222 | 2222 | errdefer msg.destroy(sema.gpa); |
| 2223 | 2223 | |
| 2224 | const struct_ty = mod.typeToStruct(container_ty) orelse break :msg msg; | |
| 2225 | const default_value_src = mod.fieldSrcLoc(struct_ty.owner_decl, .{ | |
| 2224 | const struct_type = mod.typeToStruct(container_ty) orelse break :msg msg; | |
| 2225 | const default_value_src = mod.fieldSrcLoc(struct_type.decl.unwrap().?, .{ | |
| 2226 | 2226 | .index = field_index, |
| 2227 | 2227 | .range = .value, |
| 2228 | 2228 | }); |
| ... | ... | @@ -2504,23 +2504,33 @@ fn analyzeAsAlign( |
| 2504 | 2504 | const alignment_big = try sema.analyzeAsInt(block, src, air_ref, align_ty, .{ |
| 2505 | 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. | |
| 2508 | try sema.validateAlign(block, src, alignment); | |
| 2509 | return Alignment.fromNonzeroByteUnits(alignment); | |
| 2507 | return sema.validateAlign(block, src, alignment_big); | |
| 2510 | 2508 | } |
| 2511 | 2509 | |
| 2512 | 2510 | fn validateAlign( |
| 2513 | 2511 | sema: *Sema, |
| 2514 | 2512 | block: *Block, |
| 2515 | 2513 | src: LazySrcLoc, |
| 2516 | alignment: u32, | |
| 2517 | ) !void { | |
| 2518 | if (alignment == 0) return sema.fail(block, src, "alignment must be >= 1", .{}); | |
| 2514 | alignment: u64, | |
| 2515 | ) !Alignment { | |
| 2516 | const result = try validateAlignAllowZero(sema, block, src, alignment); | |
| 2517 | if (result == .none) return sema.fail(block, src, "alignment must be >= 1", .{}); | |
| 2518 | return result; | |
| 2519 | } | |
| 2520 | ||
| 2521 | fn validateAlignAllowZero( | |
| 2522 | sema: *Sema, | |
| 2523 | block: *Block, | |
| 2524 | src: LazySrcLoc, | |
| 2525 | alignment: u64, | |
| 2526 | ) !Alignment { | |
| 2527 | if (alignment == 0) return .none; | |
| 2519 | 2528 | if (!std.math.isPowerOfTwo(alignment)) { |
| 2520 | 2529 | return sema.fail(block, src, "alignment value '{d}' is not a power of two", .{ |
| 2521 | 2530 | alignment, |
| 2522 | 2531 | }); |
| 2523 | 2532 | } |
| 2533 | return Alignment.fromNonzeroByteUnits(alignment); | |
| 2524 | 2534 | } |
| 2525 | 2535 | |
| 2526 | 2536 | pub fn resolveAlign( |
| ... | ... | @@ -2619,7 +2629,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 2619 | 2629 | defer trash_block.instructions.deinit(sema.gpa); |
| 2620 | 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 | 2633 | .child = pointee_ty.toIntern(), |
| 2624 | 2634 | .flags = .{ |
| 2625 | 2635 | .alignment = ia1.alignment, |
| ... | ... | @@ -2650,7 +2660,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 2650 | 2660 | if (alignment != .none) { |
| 2651 | 2661 | try sema.resolveTypeLayout(pointee_ty); |
| 2652 | 2662 | } |
| 2653 | const ptr_ty = try mod.ptrType(.{ | |
| 2663 | const ptr_ty = try sema.ptrType(.{ | |
| 2654 | 2664 | .child = pointee_ty.toIntern(), |
| 2655 | 2665 | .flags = .{ |
| 2656 | 2666 | .alignment = alignment, |
| ... | ... | @@ -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 | 2734 | .child = pointee_ty.toIntern(), |
| 2725 | 2735 | .flags = .{ .address_space = addr_space }, |
| 2726 | 2736 | }); |
| ... | ... | @@ -2749,7 +2759,7 @@ fn coerceResultPtr( |
| 2749 | 2759 | // Array coerced to Vector where element size is not equal but coercible. |
| 2750 | 2760 | .aggregate_init => { |
| 2751 | 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 | 2763 | .child = (try sema.analyzeAsType(block, src, ty_pl.ty)).toIntern(), |
| 2754 | 2764 | .flags = .{ .address_space = addr_space }, |
| 2755 | 2765 | }); |
| ... | ... | @@ -2763,7 +2773,7 @@ fn coerceResultPtr( |
| 2763 | 2773 | .bitcast => { |
| 2764 | 2774 | const ty_op = air_datas[trash_inst].ty_op; |
| 2765 | 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 | 2777 | .child = operand_ty.toIntern(), |
| 2768 | 2778 | .flags = .{ .address_space = addr_space }, |
| 2769 | 2779 | }); |
| ... | ... | @@ -2801,26 +2811,26 @@ fn coerceResultPtr( |
| 2801 | 2811 | } |
| 2802 | 2812 | } |
| 2803 | 2813 | |
| 2804 | pub fn analyzeStructDecl( | |
| 2814 | pub fn getStructType( | |
| 2805 | 2815 | sema: *Sema, |
| 2806 | new_decl: *Decl, | |
| 2807 | inst: Zir.Inst.Index, | |
| 2808 | struct_index: Module.Struct.Index, | |
| 2809 | ) SemaError!void { | |
| 2816 | decl: Module.Decl.Index, | |
| 2817 | namespace: Module.Namespace.Index, | |
| 2818 | zir_index: Zir.Inst.Index, | |
| 2819 | ) !InternPool.Index { | |
| 2810 | 2820 | const mod = sema.mod; |
| 2811 | const struct_obj = mod.structPtr(struct_index); | |
| 2812 | const extended = sema.code.instructions.items(.data)[inst].extended; | |
| 2821 | const gpa = sema.gpa; | |
| 2822 | const ip = &mod.intern_pool; | |
| 2823 | const extended = sema.code.instructions.items(.data)[zir_index].extended; | |
| 2813 | 2824 | assert(extended.opcode == .struct_decl); |
| 2814 | 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 | 2827 | var extra_index: usize = extended.operand; |
| 2822 | 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 | 2834 | const decls_len = if (small.has_decls_len) blk: { |
| 2825 | 2835 | const decls_len = sema.code.extra[extra_index]; |
| 2826 | 2836 | extra_index += 1; |
| ... | ... | @@ -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 | 2869 | fn zirStructDecl( |
| ... | ... | @@ -2847,7 +2873,7 @@ fn zirStructDecl( |
| 2847 | 2873 | inst: Zir.Inst.Index, |
| 2848 | 2874 | ) CompileError!Air.Inst.Ref { |
| 2849 | 2875 | const mod = sema.mod; |
| 2850 | const gpa = sema.gpa; | |
| 2876 | const ip = &mod.intern_pool; | |
| 2851 | 2877 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); |
| 2852 | 2878 | const src: LazySrcLoc = if (small.has_src_node) blk: { |
| 2853 | 2879 | const node_offset: i32 = @bitCast(sema.code.extra[extended.operand]); |
| ... | ... | @@ -2874,37 +2900,21 @@ fn zirStructDecl( |
| 2874 | 2900 | const new_namespace = mod.namespacePtr(new_namespace_index); |
| 2875 | 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 | 2903 | const struct_ty = ty: { |
| 2890 | const ty = try mod.intern_pool.get(gpa, .{ .struct_type = .{ | |
| 2891 | .index = struct_index.toOptional(), | |
| 2892 | .namespace = new_namespace_index.toOptional(), | |
| 2893 | } }); | |
| 2904 | const ty = try sema.getStructType(new_decl_index, new_namespace_index, inst); | |
| 2894 | 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 | 2907 | break :ty sema.builtin_type_target_index; |
| 2897 | 2908 | } |
| 2898 | 2909 | break :ty ty; |
| 2899 | 2910 | }; |
| 2900 | 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 | 2914 | new_decl.ty = Type.type; |
| 2904 | 2915 | new_decl.val = struct_ty.toValue(); |
| 2905 | 2916 | new_namespace.ty = struct_ty.toType(); |
| 2906 | 2917 | |
| 2907 | try sema.analyzeStructDecl(new_decl, inst, struct_index); | |
| 2908 | 2918 | const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); |
| 2909 | 2919 | try mod.finalizeAnonDecl(new_decl_index); |
| 2910 | 2920 | return decl_val; |
| ... | ... | @@ -3196,7 +3206,7 @@ fn zirEnumDecl( |
| 3196 | 3206 | extra_index += 1; |
| 3197 | 3207 | |
| 3198 | 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 | 3210 | const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy; |
| 3201 | 3211 | const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy; |
| 3202 | 3212 | const msg = msg: { |
| ... | ... | @@ -3227,7 +3237,7 @@ fn zirEnumDecl( |
| 3227 | 3237 | }; |
| 3228 | 3238 | if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) break :overflow true; |
| 3229 | 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 | 3241 | const value_src = mod.fieldSrcLoc(new_decl_index, .{ |
| 3232 | 3242 | .index = field_i, |
| 3233 | 3243 | .range = .value, |
| ... | ... | @@ -3249,7 +3259,7 @@ fn zirEnumDecl( |
| 3249 | 3259 | else |
| 3250 | 3260 | try mod.intValue(int_tag_ty, 0); |
| 3251 | 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 | 3263 | const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy; |
| 3254 | 3264 | const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy; |
| 3255 | 3265 | const msg = msg: { |
| ... | ... | @@ -3498,7 +3508,7 @@ fn zirRetPtr(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { |
| 3498 | 3508 | } |
| 3499 | 3509 | |
| 3500 | 3510 | const target = sema.mod.getTarget(); |
| 3501 | const ptr_type = try sema.mod.ptrType(.{ | |
| 3511 | const ptr_type = try sema.ptrType(.{ | |
| 3502 | 3512 | .child = sema.fn_ret_ty.toIntern(), |
| 3503 | 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 | 3517 | // We are inlining a function call; this should be emitted as an alloc, not a ret_ptr. |
| 3508 | 3518 | // TODO when functions gain result location support, the inlining struct in |
| 3509 | 3519 | // Block should contain the return pointer, and we would pass that through here. |
| 3520 | try sema.queueFullTypeResolution(sema.fn_ret_ty); | |
| 3510 | 3521 | return block.addTy(.alloc, ptr_type); |
| 3511 | 3522 | } |
| 3512 | 3523 | |
| ... | ... | @@ -3701,7 +3712,7 @@ fn zirAllocExtended( |
| 3701 | 3712 | } |
| 3702 | 3713 | const target = sema.mod.getTarget(); |
| 3703 | 3714 | try sema.resolveTypeLayout(var_ty); |
| 3704 | const ptr_type = try sema.mod.ptrType(.{ | |
| 3715 | const ptr_type = try sema.ptrType(.{ | |
| 3705 | 3716 | .child = var_ty.toIntern(), |
| 3706 | 3717 | .flags = .{ |
| 3707 | 3718 | .alignment = alignment, |
| ... | ... | @@ -3810,7 +3821,7 @@ fn makePtrConst(sema: *Sema, block: *Block, alloc: Air.Inst.Ref) CompileError!Ai |
| 3810 | 3821 | |
| 3811 | 3822 | var ptr_info = alloc_ty.ptrInfo(mod); |
| 3812 | 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 | 3826 | // Detect if a comptime value simply needs to have its type changed. |
| 3816 | 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 | 3863 | return sema.analyzeComptimeAlloc(block, var_ty, .none); |
| 3853 | 3864 | } |
| 3854 | 3865 | const target = sema.mod.getTarget(); |
| 3855 | const ptr_type = try sema.mod.ptrType(.{ | |
| 3866 | const ptr_type = try sema.ptrType(.{ | |
| 3856 | 3867 | .child = var_ty.toIntern(), |
| 3857 | 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 | 3883 | } |
| 3873 | 3884 | try sema.validateVarType(block, ty_src, var_ty, false); |
| 3874 | 3885 | const target = sema.mod.getTarget(); |
| 3875 | const ptr_type = try sema.mod.ptrType(.{ | |
| 3886 | const ptr_type = try sema.ptrType(.{ | |
| 3876 | 3887 | .child = var_ty.toIntern(), |
| 3877 | 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 | 3949 | const decl = mod.declPtr(decl_index); |
| 3939 | 3950 | if (iac.is_const) _ = try decl.internValue(mod); |
| 3940 | 3951 | const final_elem_ty = decl.ty; |
| 3941 | const final_ptr_ty = try mod.ptrType(.{ | |
| 3952 | const final_ptr_ty = try sema.ptrType(.{ | |
| 3942 | 3953 | .child = final_elem_ty.toIntern(), |
| 3943 | 3954 | .flags = .{ |
| 3944 | 3955 | .is_const = false, |
| ... | ... | @@ -3971,7 +3982,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 3971 | 3982 | const peer_inst_list = ia2.prongs.items(.stored_inst); |
| 3972 | 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 | 3986 | .child = final_elem_ty.toIntern(), |
| 3976 | 3987 | .flags = .{ |
| 3977 | 3988 | .alignment = ia1.alignment, |
| ... | ... | @@ -4093,7 +4104,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 4093 | 4104 | trash_block.is_comptime = false; |
| 4094 | 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 | 4108 | .child = final_elem_ty.toIntern(), |
| 4098 | 4109 | .flags = .{ |
| 4099 | 4110 | .alignment = ia1.alignment, |
| ... | ... | @@ -4688,12 +4699,13 @@ fn validateStructInit( |
| 4688 | 4699 | // In this case the only thing we need to do is evaluate the implicit |
| 4689 | 4700 | // store instructions for default field values, and report any missing fields. |
| 4690 | 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 | 4704 | if (field_ptr != 0) continue; |
| 4693 | 4705 | |
| 4694 | 4706 | const default_val = struct_ty.structFieldDefaultValue(i, mod); |
| 4695 | 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 | 4709 | const template = "missing tuple field with index {d}"; |
| 4698 | 4710 | if (root_msg) |msg| { |
| 4699 | 4711 | try sema.errNote(block, init_src, msg, template, .{i}); |
| ... | ... | @@ -4701,8 +4713,7 @@ fn validateStructInit( |
| 4701 | 4713 | root_msg = try sema.errMsg(block, init_src, template, .{i}); |
| 4702 | 4714 | } |
| 4703 | 4715 | continue; |
| 4704 | } | |
| 4705 | const field_name = struct_ty.structFieldName(i, mod); | |
| 4716 | }; | |
| 4706 | 4717 | const template = "missing struct field: {}"; |
| 4707 | 4718 | const args = .{field_name.fmt(ip)}; |
| 4708 | 4719 | if (root_msg) |msg| { |
| ... | ... | @@ -4723,10 +4734,11 @@ fn validateStructInit( |
| 4723 | 4734 | } |
| 4724 | 4735 | |
| 4725 | 4736 | if (root_msg) |msg| { |
| 4726 | if (mod.typeToStruct(struct_ty)) |struct_obj| { | |
| 4727 | const fqn = try struct_obj.getFullyQualifiedName(mod); | |
| 4737 | if (mod.typeToStruct(struct_ty)) |struct_type| { | |
| 4738 | const decl = mod.declPtr(struct_type.decl.unwrap().?); | |
| 4739 | const fqn = try decl.getFullyQualifiedName(mod); | |
| 4728 | 4740 | try mod.errNoteNonLazy( |
| 4729 | struct_obj.srcLoc(mod), | |
| 4741 | decl.srcLoc(mod), | |
| 4730 | 4742 | msg, |
| 4731 | 4743 | "struct '{}' declared here", |
| 4732 | 4744 | .{fqn.fmt(ip)}, |
| ... | ... | @@ -4751,7 +4763,8 @@ fn validateStructInit( |
| 4751 | 4763 | // ends up being comptime-known. |
| 4752 | 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 | 4768 | if (field_ptr != 0) { |
| 4756 | 4769 | // Determine whether the value stored to this pointer is comptime-known. |
| 4757 | 4770 | const field_ty = struct_ty.structFieldType(i, mod); |
| ... | ... | @@ -4830,7 +4843,7 @@ fn validateStructInit( |
| 4830 | 4843 | |
| 4831 | 4844 | const default_val = struct_ty.structFieldDefaultValue(i, mod); |
| 4832 | 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 | 4847 | const template = "missing tuple field with index {d}"; |
| 4835 | 4848 | if (root_msg) |msg| { |
| 4836 | 4849 | try sema.errNote(block, init_src, msg, template, .{i}); |
| ... | ... | @@ -4838,8 +4851,7 @@ fn validateStructInit( |
| 4838 | 4851 | root_msg = try sema.errMsg(block, init_src, template, .{i}); |
| 4839 | 4852 | } |
| 4840 | 4853 | continue; |
| 4841 | } | |
| 4842 | const field_name = struct_ty.structFieldName(i, mod); | |
| 4854 | }; | |
| 4843 | 4855 | const template = "missing struct field: {}"; |
| 4844 | 4856 | const args = .{field_name.fmt(ip)}; |
| 4845 | 4857 | if (root_msg) |msg| { |
| ... | ... | @@ -4853,10 +4865,11 @@ fn validateStructInit( |
| 4853 | 4865 | } |
| 4854 | 4866 | |
| 4855 | 4867 | if (root_msg) |msg| { |
| 4856 | if (mod.typeToStruct(struct_ty)) |struct_obj| { | |
| 4857 | const fqn = try struct_obj.getFullyQualifiedName(mod); | |
| 4868 | if (mod.typeToStruct(struct_ty)) |struct_type| { | |
| 4869 | const decl = mod.declPtr(struct_type.decl.unwrap().?); | |
| 4870 | const fqn = try decl.getFullyQualifiedName(mod); | |
| 4858 | 4871 | try mod.errNoteNonLazy( |
| 4859 | struct_obj.srcLoc(mod), | |
| 4872 | decl.srcLoc(mod), | |
| 4860 | 4873 | msg, |
| 4861 | 4874 | "struct '{}' declared here", |
| 4862 | 4875 | .{fqn.fmt(ip)}, |
| ... | ... | @@ -5255,14 +5268,14 @@ fn failWithBadMemberAccess( |
| 5255 | 5268 | fn failWithBadStructFieldAccess( |
| 5256 | 5269 | sema: *Sema, |
| 5257 | 5270 | block: *Block, |
| 5258 | struct_obj: *Module.Struct, | |
| 5271 | struct_type: InternPool.Key.StructType, | |
| 5259 | 5272 | field_src: LazySrcLoc, |
| 5260 | 5273 | field_name: InternPool.NullTerminatedString, |
| 5261 | 5274 | ) CompileError { |
| 5262 | 5275 | const mod = sema.mod; |
| 5263 | 5276 | const gpa = sema.gpa; |
| 5264 | ||
| 5265 | const fqn = try struct_obj.getFullyQualifiedName(mod); | |
| 5277 | const decl = mod.declPtr(struct_type.decl.unwrap().?); | |
| 5278 | const fqn = try decl.getFullyQualifiedName(mod); | |
| 5266 | 5279 | |
| 5267 | 5280 | const msg = msg: { |
| 5268 | 5281 | const msg = try sema.errMsg( |
| ... | ... | @@ -5272,7 +5285,7 @@ fn failWithBadStructFieldAccess( |
| 5272 | 5285 | .{ field_name.fmt(&mod.intern_pool), fqn.fmt(&mod.intern_pool) }, |
| 5273 | 5286 | ); |
| 5274 | 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 | 5289 | break :msg msg; |
| 5277 | 5290 | }; |
| 5278 | 5291 | return sema.failWithOwnedErrorMsg(block, msg); |
| ... | ... | @@ -5787,9 +5800,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr |
| 5787 | 5800 | |
| 5788 | 5801 | try mod.semaFile(result.file); |
| 5789 | 5802 | const file_root_decl_index = result.file.root_decl.unwrap().?; |
| 5790 | const file_root_decl = mod.declPtr(file_root_decl_index); | |
| 5791 | try mod.declareDeclDependency(sema.owner_decl_index, file_root_decl_index); | |
| 5792 | return Air.internedToRef(file_root_decl.val.toIntern()); | |
| 5803 | return sema.analyzeDeclVal(parent_block, src, file_root_decl_index); | |
| 5793 | 5804 | } |
| 5794 | 5805 | |
| 5795 | 5806 | fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -8638,7 +8649,7 @@ fn analyzeOptionalPayloadPtr( |
| 8638 | 8649 | } |
| 8639 | 8650 | |
| 8640 | 8651 | const child_type = opt_type.optionalChild(mod); |
| 8641 | const child_pointer = try mod.ptrType(.{ | |
| 8652 | const child_pointer = try sema.ptrType(.{ | |
| 8642 | 8653 | .child = child_type.toIntern(), |
| 8643 | 8654 | .flags = .{ |
| 8644 | 8655 | .is_const = optional_ptr_ty.isConstPtr(mod), |
| ... | ... | @@ -8707,7 +8718,7 @@ fn zirOptionalPayload( |
| 8707 | 8718 | // TODO https://github.com/ziglang/zig/issues/6597 |
| 8708 | 8719 | if (true) break :t operand_ty; |
| 8709 | 8720 | const ptr_info = operand_ty.ptrInfo(mod); |
| 8710 | break :t try mod.ptrType(.{ | |
| 8721 | break :t try sema.ptrType(.{ | |
| 8711 | 8722 | .child = ptr_info.child, |
| 8712 | 8723 | .flags = .{ |
| 8713 | 8724 | .alignment = ptr_info.flags.alignment, |
| ... | ... | @@ -8825,7 +8836,7 @@ fn analyzeErrUnionPayloadPtr( |
| 8825 | 8836 | |
| 8826 | 8837 | const err_union_ty = operand_ty.childType(mod); |
| 8827 | 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 | 8840 | .child = payload_ty.toIntern(), |
| 8830 | 8841 | .flags = .{ |
| 8831 | 8842 | .is_const = operand_ty.isConstPtr(mod), |
| ... | ... | @@ -10680,7 +10691,7 @@ const SwitchProngAnalysis = struct { |
| 10680 | 10691 | const union_obj = mod.typeToUnion(operand_ty).?; |
| 10681 | 10692 | const field_ty = union_obj.field_types.get(ip)[field_index].toType(); |
| 10682 | 10693 | if (capture_byref) { |
| 10683 | const ptr_field_ty = try mod.ptrType(.{ | |
| 10694 | const ptr_field_ty = try sema.ptrType(.{ | |
| 10684 | 10695 | .child = field_ty.toIntern(), |
| 10685 | 10696 | .flags = .{ |
| 10686 | 10697 | .is_const = !operand_ptr_ty.ptrIsMutable(mod), |
| ... | ... | @@ -10786,7 +10797,7 @@ const SwitchProngAnalysis = struct { |
| 10786 | 10797 | // By-reference captures have some further restrictions which make them easier to emit |
| 10787 | 10798 | if (capture_byref) { |
| 10788 | 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 | 10801 | .child = capture_ty.toIntern(), |
| 10791 | 10802 | .flags = .{ |
| 10792 | 10803 | // TODO: alignment! |
| ... | ... | @@ -10800,7 +10811,7 @@ const SwitchProngAnalysis = struct { |
| 10800 | 10811 | // pointer type is in-memory coercible to the capture pointer type. |
| 10801 | 10812 | if (!same_types) { |
| 10802 | 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 | 10815 | .child = field_ty.toIntern(), |
| 10805 | 10816 | .flags = .{ |
| 10806 | 10817 | // TODO: alignment! |
| ... | ... | @@ -12953,9 +12964,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 12953 | 12964 | } |
| 12954 | 12965 | }, |
| 12955 | 12966 | .struct_type => |struct_type| { |
| 12956 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :hf false; | |
| 12957 | assert(struct_obj.haveFieldTypes()); | |
| 12958 | break :hf struct_obj.fields.contains(field_name); | |
| 12967 | break :hf struct_type.nameIndex(ip, field_name) != null; | |
| 12959 | 12968 | }, |
| 12960 | 12969 | .union_type => |union_type| { |
| 12961 | 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 | 13034 | }; |
| 13026 | 13035 | try mod.semaFile(result.file); |
| 13027 | 13036 | const file_root_decl_index = result.file.root_decl.unwrap().?; |
| 13028 | const file_root_decl = mod.declPtr(file_root_decl_index); | |
| 13029 | try mod.declareDeclDependency(sema.owner_decl_index, file_root_decl_index); | |
| 13030 | return Air.internedToRef(file_root_decl.val.toIntern()); | |
| 13037 | return sema.analyzeDeclVal(block, operand_src, file_root_decl_index); | |
| 13031 | 13038 | } |
| 13032 | 13039 | |
| 13033 | 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 | 13773 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 13767 | 13774 | |
| 13768 | 13775 | if (ptr_addrspace) |ptr_as| { |
| 13769 | const alloc_ty = try mod.ptrType(.{ | |
| 13776 | const alloc_ty = try sema.ptrType(.{ | |
| 13770 | 13777 | .child = result_ty.toIntern(), |
| 13771 | 13778 | .flags = .{ .address_space = ptr_as }, |
| 13772 | 13779 | }); |
| 13773 | 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 | 13782 | .child = resolved_elem_ty.toIntern(), |
| 13776 | 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 | 14038 | try sema.requireRuntimeBlock(block, src, lhs_src); |
| 14032 | 14039 | |
| 14033 | 14040 | if (ptr_addrspace) |ptr_as| { |
| 14034 | const alloc_ty = try mod.ptrType(.{ | |
| 14041 | const alloc_ty = try sema.ptrType(.{ | |
| 14035 | 14042 | .child = result_ty.toIntern(), |
| 14036 | 14043 | .flags = .{ .address_space = ptr_as }, |
| 14037 | 14044 | }); |
| 14038 | 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 | 14047 | .child = lhs_info.elem_type.toIntern(), |
| 14041 | 14048 | .flags = .{ .address_space = ptr_as }, |
| 14042 | 14049 | }); |
| ... | ... | @@ -15978,7 +15985,7 @@ fn analyzePtrArithmetic( |
| 15978 | 15985 | )); |
| 15979 | 15986 | assert(new_align != .none); |
| 15980 | 15987 | |
| 15981 | break :t try mod.ptrType(.{ | |
| 15988 | break :t try sema.ptrType(.{ | |
| 15982 | 15989 | .child = ptr_info.child, |
| 15983 | 15990 | .sentinel = ptr_info.sentinel, |
| 15984 | 15991 | .flags = .{ |
| ... | ... | @@ -16881,7 +16888,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16881 | 16888 | .none, // default alignment |
| 16882 | 16889 | ); |
| 16883 | 16890 | break :v try mod.intern(.{ .ptr = .{ |
| 16884 | .ty = (try mod.ptrType(.{ | |
| 16891 | .ty = (try sema.ptrType(.{ | |
| 16885 | 16892 | .child = param_info_ty.toIntern(), |
| 16886 | 16893 | .flags = .{ |
| 16887 | 16894 | .size = .Slice, |
| ... | ... | @@ -16907,7 +16914,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16907 | 16914 | // calling_convention: CallingConvention, |
| 16908 | 16915 | (try mod.enumValueFieldIndex(callconv_ty, @intFromEnum(func_ty_info.cc))).toIntern(), |
| 16909 | 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 | 16918 | // is_generic: bool, |
| 16912 | 16919 | Value.makeBool(func_ty_info.is_generic).toIntern(), |
| 16913 | 16920 | // is_var_args: bool, |
| ... | ... | @@ -17200,7 +17207,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17200 | 17207 | }; |
| 17201 | 17208 | |
| 17202 | 17209 | // Build our ?[]const Error value |
| 17203 | const slice_errors_ty = try mod.ptrType(.{ | |
| 17210 | const slice_errors_ty = try sema.ptrType(.{ | |
| 17204 | 17211 | .child = error_field_ty.toIntern(), |
| 17205 | 17212 | .flags = .{ |
| 17206 | 17213 | .size = .Slice, |
| ... | ... | @@ -17349,7 +17356,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17349 | 17356 | .none, // default alignment |
| 17350 | 17357 | ); |
| 17351 | 17358 | break :v try mod.intern(.{ .ptr = .{ |
| 17352 | .ty = (try mod.ptrType(.{ | |
| 17359 | .ty = (try sema.ptrType(.{ | |
| 17353 | 17360 | .child = enum_field_ty.toIntern(), |
| 17354 | 17361 | .flags = .{ |
| 17355 | 17362 | .size = .Slice, |
| ... | ... | @@ -17461,7 +17468,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17461 | 17468 | |
| 17462 | 17469 | const alignment = switch (layout) { |
| 17463 | 17470 | .Auto, .Extern => try sema.unionFieldAlignment(union_obj, @intCast(i)), |
| 17464 | .Packed => 0, | |
| 17471 | .Packed => .none, | |
| 17465 | 17472 | }; |
| 17466 | 17473 | |
| 17467 | 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 | 17478 | // type: type, |
| 17472 | 17479 | field_ty, |
| 17473 | 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 | 17483 | field_val.* = try mod.intern(.{ .aggregate = .{ |
| 17477 | 17484 | .ty = union_field_ty.toIntern(), |
| ... | ... | @@ -17493,7 +17500,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17493 | 17500 | .none, // default alignment |
| 17494 | 17501 | ); |
| 17495 | 17502 | break :v try mod.intern(.{ .ptr = .{ |
| 17496 | .ty = (try mod.ptrType(.{ | |
| 17503 | .ty = (try sema.ptrType(.{ | |
| 17497 | 17504 | .child = union_field_ty.toIntern(), |
| 17498 | 17505 | .flags = .{ |
| 17499 | 17506 | .size = .Slice, |
| ... | ... | @@ -17578,7 +17585,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17578 | 17585 | }; |
| 17579 | 17586 | |
| 17580 | 17587 | try sema.resolveTypeLayout(ty); // Getting alignment requires type layout |
| 17581 | const layout = ty.containerLayout(mod); | |
| 17582 | 17588 | |
| 17583 | 17589 | var struct_field_vals: []InternPool.Index = &.{}; |
| 17584 | 17590 | defer gpa.free(struct_field_vals); |
| ... | ... | @@ -17633,7 +17639,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17633 | 17639 | // is_comptime: bool, |
| 17634 | 17640 | Value.makeBool(is_comptime).toIntern(), |
| 17635 | 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 | 17644 | struct_field_val.* = try mod.intern(.{ .aggregate = .{ |
| 17639 | 17645 | .ty = struct_field_ty.toIntern(), |
| ... | ... | @@ -17645,16 +17651,17 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17645 | 17651 | .struct_type => |s| s, |
| 17646 | 17652 | else => unreachable, |
| 17647 | 17653 | }; |
| 17648 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :fv; | |
| 17649 | struct_field_vals = try gpa.alloc(InternPool.Index, struct_obj.fields.count()); | |
| 17650 | ||
| 17651 | for ( | |
| 17652 | struct_field_vals, | |
| 17653 | struct_obj.fields.keys(), | |
| 17654 | struct_obj.fields.values(), | |
| 17655 | ) |*field_val, name_nts, field| { | |
| 17654 | struct_field_vals = try gpa.alloc(InternPool.Index, struct_type.field_types.len); | |
| 17655 | ||
| 17656 | for (struct_field_vals, 0..) |*field_val, i| { | |
| 17656 | 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 | 17665 | const name_val = v: { |
| 17659 | 17666 | var anon_decl = try block.startAnonDecl(); |
| 17660 | 17667 | defer anon_decl.deinit(); |
| ... | ... | @@ -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) | |
| 17681 | null | |
| 17682 | else | |
| 17683 | field.default_val.toValue(); | |
| 17684 | const default_val_ptr = try sema.optRefValue(block, field.ty, opt_default_val); | |
| 17685 | const alignment = field.alignment(mod, layout); | |
| 17687 | const opt_default_val = if (field_init == .none) null else field_init.toValue(); | |
| 17688 | const default_val_ptr = try sema.optRefValue(block, field_ty, opt_default_val); | |
| 17689 | const alignment = switch (struct_type.layout) { | |
| 17690 | .Packed => .none, | |
| 17691 | else => try sema.structFieldAlignment( | |
| 17692 | struct_type.fieldAlign(ip, i), | |
| 17693 | field_ty, | |
| 17694 | struct_type.layout, | |
| 17695 | ), | |
| 17696 | }; | |
| 17686 | 17697 | |
| 17687 | 17698 | const struct_field_fields = .{ |
| 17688 | 17699 | // name: []const u8, |
| 17689 | 17700 | name_val, |
| 17690 | 17701 | // type: type, |
| 17691 | field.ty.toIntern(), | |
| 17702 | field_ty.toIntern(), | |
| 17692 | 17703 | // default_value: ?*const anyopaque, |
| 17693 | 17704 | default_val_ptr.toIntern(), |
| 17694 | 17705 | // is_comptime: bool, |
| 17695 | Value.makeBool(field.is_comptime).toIntern(), | |
| 17706 | Value.makeBool(field_is_comptime).toIntern(), | |
| 17696 | 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 | 17710 | field_val.* = try mod.intern(.{ .aggregate = .{ |
| 17700 | 17711 | .ty = struct_field_ty.toIntern(), |
| ... | ... | @@ -17717,7 +17728,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17717 | 17728 | .none, // default alignment |
| 17718 | 17729 | ); |
| 17719 | 17730 | break :v try mod.intern(.{ .ptr = .{ |
| 17720 | .ty = (try mod.ptrType(.{ | |
| 17731 | .ty = (try sema.ptrType(.{ | |
| 17721 | 17732 | .child = struct_field_ty.toIntern(), |
| 17722 | 17733 | .flags = .{ |
| 17723 | 17734 | .size = .Slice, |
| ... | ... | @@ -17733,11 +17744,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17733 | 17744 | |
| 17734 | 17745 | const backing_integer_val = try mod.intern(.{ .opt = .{ |
| 17735 | 17746 | .ty = (try mod.optionalType(.type_type)).toIntern(), |
| 17736 | .val = if (layout == .Packed) val: { | |
| 17737 | const struct_obj = mod.typeToStruct(ty).?; | |
| 17738 | assert(struct_obj.haveLayout()); | |
| 17739 | assert(struct_obj.backing_int_ty.isInt(mod)); | |
| 17740 | break :val struct_obj.backing_int_ty.toIntern(); | |
| 17747 | .val = if (mod.typeToPackedStruct(ty)) |packed_struct| val: { | |
| 17748 | assert(packed_struct.backingIntType(ip).toType().isInt(mod)); | |
| 17749 | break :val packed_struct.backingIntType(ip).*; | |
| 17741 | 17750 | } else .none, |
| 17742 | 17751 | } }); |
| 17743 | 17752 | |
| ... | ... | @@ -17754,6 +17763,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17754 | 17763 | break :t decl.val.toType(); |
| 17755 | 17764 | }; |
| 17756 | 17765 | |
| 17766 | const layout = ty.containerLayout(mod); | |
| 17767 | ||
| 17757 | 17768 | const field_values = [_]InternPool.Index{ |
| 17758 | 17769 | // layout: ContainerLayout, |
| 17759 | 17770 | (try mod.enumValueFieldIndex(container_layout_ty, @intFromEnum(layout))).toIntern(), |
| ... | ... | @@ -17863,7 +17874,7 @@ fn typeInfoDecls( |
| 17863 | 17874 | .none, // default alignment |
| 17864 | 17875 | ); |
| 17865 | 17876 | return try mod.intern(.{ .ptr = .{ |
| 17866 | .ty = (try mod.ptrType(.{ | |
| 17877 | .ty = (try sema.ptrType(.{ | |
| 17867 | 17878 | .child = declaration_ty.toIntern(), |
| 17868 | 17879 | .flags = .{ |
| 17869 | 17880 | .size = .Slice, |
| ... | ... | @@ -18433,7 +18444,7 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr |
| 18433 | 18444 | |
| 18434 | 18445 | const operand_ty = sema.typeOf(operand); |
| 18435 | 18446 | const ptr_info = operand_ty.ptrInfo(mod); |
| 18436 | const res_ty = try mod.ptrType(.{ | |
| 18447 | const res_ty = try sema.ptrType(.{ | |
| 18437 | 18448 | .child = err_union_ty.errorUnionPayload(mod).toIntern(), |
| 18438 | 18449 | .flags = .{ |
| 18439 | 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 | 18935 | }, |
| 18925 | 18936 | else => {}, |
| 18926 | 18937 | } |
| 18927 | const abi_align: u32 = @intCast((try val.getUnsignedIntAdvanced(mod, sema)).?); | |
| 18928 | try sema.validateAlign(block, align_src, abi_align); | |
| 18929 | break :blk Alignment.fromByteUnits(abi_align); | |
| 18938 | const align_bytes = (try val.getUnsignedIntAdvanced(mod, sema)).?; | |
| 18939 | break :blk try sema.validateAlignAllowZero(block, align_src, align_bytes); | |
| 18930 | 18940 | } else .none; |
| 18931 | 18941 | |
| 18932 | 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 | 18998 | } |
| 18989 | 18999 | } |
| 18990 | 19000 | |
| 18991 | const ty = try mod.ptrType(.{ | |
| 19001 | const ty = try sema.ptrType(.{ | |
| 18992 | 19002 | .child = elem_ty.toIntern(), |
| 18993 | 19003 | .sentinel = sentinel, |
| 18994 | 19004 | .flags = .{ |
| ... | ... | @@ -19226,7 +19236,7 @@ fn zirStructInit( |
| 19226 | 19236 | |
| 19227 | 19237 | if (is_ref) { |
| 19228 | 19238 | const target = mod.getTarget(); |
| 19229 | const alloc_ty = try mod.ptrType(.{ | |
| 19239 | const alloc_ty = try sema.ptrType(.{ | |
| 19230 | 19240 | .child = resolved_ty.toIntern(), |
| 19231 | 19241 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 19232 | 19242 | }); |
| ... | ... | @@ -19291,12 +19301,12 @@ fn finishStructInit( |
| 19291 | 19301 | } |
| 19292 | 19302 | }, |
| 19293 | 19303 | .struct_type => |struct_type| { |
| 19294 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 19295 | for (struct_obj.fields.values(), 0..) |field, i| { | |
| 19304 | for (0..struct_type.field_types.len) |i| { | |
| 19296 | 19305 | if (field_inits[i] != .none) continue; |
| 19297 | 19306 | |
| 19298 | if (field.default_val == .none) { | |
| 19299 | const field_name = struct_obj.fields.keys()[i]; | |
| 19307 | const field_init = struct_type.fieldInit(ip, i); | |
| 19308 | if (field_init == .none) { | |
| 19309 | const field_name = struct_type.field_names.get(ip)[i]; | |
| 19300 | 19310 | const template = "missing struct field: {}"; |
| 19301 | 19311 | const args = .{field_name.fmt(ip)}; |
| 19302 | 19312 | if (root_msg) |msg| { |
| ... | ... | @@ -19305,7 +19315,7 @@ fn finishStructInit( |
| 19305 | 19315 | root_msg = try sema.errMsg(block, init_src, template, args); |
| 19306 | 19316 | } |
| 19307 | 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 | 19323 | } |
| 19314 | 19324 | |
| 19315 | 19325 | if (root_msg) |msg| { |
| 19316 | if (mod.typeToStruct(struct_ty)) |struct_obj| { | |
| 19317 | const fqn = try struct_obj.getFullyQualifiedName(mod); | |
| 19326 | if (mod.typeToStruct(struct_ty)) |struct_type| { | |
| 19327 | const decl = mod.declPtr(struct_type.decl.unwrap().?); | |
| 19328 | const fqn = try decl.getFullyQualifiedName(mod); | |
| 19318 | 19329 | try mod.errNoteNonLazy( |
| 19319 | struct_obj.srcLoc(mod), | |
| 19330 | decl.srcLoc(mod), | |
| 19320 | 19331 | msg, |
| 19321 | 19332 | "struct '{}' declared here", |
| 19322 | 19333 | .{fqn.fmt(ip)}, |
| ... | ... | @@ -19349,7 +19360,7 @@ fn finishStructInit( |
| 19349 | 19360 | if (is_ref) { |
| 19350 | 19361 | try sema.resolveStructLayout(struct_ty); |
| 19351 | 19362 | const target = sema.mod.getTarget(); |
| 19352 | const alloc_ty = try mod.ptrType(.{ | |
| 19363 | const alloc_ty = try sema.ptrType(.{ | |
| 19353 | 19364 | .child = struct_ty.toIntern(), |
| 19354 | 19365 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 19355 | 19366 | }); |
| ... | ... | @@ -19502,7 +19513,7 @@ fn structInitAnon( |
| 19502 | 19513 | |
| 19503 | 19514 | if (is_ref) { |
| 19504 | 19515 | const target = mod.getTarget(); |
| 19505 | const alloc_ty = try mod.ptrType(.{ | |
| 19516 | const alloc_ty = try sema.ptrType(.{ | |
| 19506 | 19517 | .child = tuple_ty, |
| 19507 | 19518 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 19508 | 19519 | }); |
| ... | ... | @@ -19516,7 +19527,7 @@ fn structInitAnon( |
| 19516 | 19527 | }; |
| 19517 | 19528 | extra_index = item.end; |
| 19518 | 19529 | |
| 19519 | const field_ptr_ty = try mod.ptrType(.{ | |
| 19530 | const field_ptr_ty = try sema.ptrType(.{ | |
| 19520 | 19531 | .child = field_ty, |
| 19521 | 19532 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 19522 | 19533 | }); |
| ... | ... | @@ -19640,7 +19651,7 @@ fn zirArrayInit( |
| 19640 | 19651 | |
| 19641 | 19652 | if (is_ref) { |
| 19642 | 19653 | const target = mod.getTarget(); |
| 19643 | const alloc_ty = try mod.ptrType(.{ | |
| 19654 | const alloc_ty = try sema.ptrType(.{ | |
| 19644 | 19655 | .child = array_ty.toIntern(), |
| 19645 | 19656 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 19646 | 19657 | }); |
| ... | ... | @@ -19648,7 +19659,7 @@ fn zirArrayInit( |
| 19648 | 19659 | |
| 19649 | 19660 | if (array_ty.isTuple(mod)) { |
| 19650 | 19661 | for (resolved_args, 0..) |arg, i| { |
| 19651 | const elem_ptr_ty = try mod.ptrType(.{ | |
| 19662 | const elem_ptr_ty = try sema.ptrType(.{ | |
| 19652 | 19663 | .child = array_ty.structFieldType(i, mod).toIntern(), |
| 19653 | 19664 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 19654 | 19665 | }); |
| ... | ... | @@ -19661,7 +19672,7 @@ fn zirArrayInit( |
| 19661 | 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 | 19676 | .child = array_ty.elemType2(mod).toIntern(), |
| 19666 | 19677 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 19667 | 19678 | }); |
| ... | ... | @@ -19749,14 +19760,14 @@ fn arrayInitAnon( |
| 19749 | 19760 | |
| 19750 | 19761 | if (is_ref) { |
| 19751 | 19762 | const target = sema.mod.getTarget(); |
| 19752 | const alloc_ty = try mod.ptrType(.{ | |
| 19763 | const alloc_ty = try sema.ptrType(.{ | |
| 19753 | 19764 | .child = tuple_ty, |
| 19754 | 19765 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 19755 | 19766 | }); |
| 19756 | 19767 | const alloc = try block.addTy(.alloc, alloc_ty); |
| 19757 | 19768 | for (operands, 0..) |operand, i_usize| { |
| 19758 | 19769 | const i: u32 = @intCast(i_usize); |
| 19759 | const field_ptr_ty = try mod.ptrType(.{ | |
| 19770 | const field_ptr_ty = try sema.ptrType(.{ | |
| 19760 | 19771 | .child = types[i], |
| 19761 | 19772 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 19762 | 19773 | }); |
| ... | ... | @@ -19848,10 +19859,10 @@ fn fieldType( |
| 19848 | 19859 | return Air.internedToRef(anon_struct.types.get(ip)[field_index]); |
| 19849 | 19860 | }, |
| 19850 | 19861 | .struct_type => |struct_type| { |
| 19851 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 19852 | const field = struct_obj.fields.get(field_name) orelse | |
| 19853 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name); | |
| 19854 | return Air.internedToRef(field.ty.toIntern()); | |
| 19862 | const field_index = struct_type.nameIndex(ip, field_name) orelse | |
| 19863 | return sema.failWithBadStructFieldAccess(block, struct_type, field_src, field_name); | |
| 19864 | const field_ty = struct_type.field_types.get(ip)[field_index]; | |
| 19865 | return Air.internedToRef(field_ty); | |
| 19855 | 19866 | }, |
| 19856 | 19867 | else => unreachable, |
| 19857 | 19868 | }, |
| ... | ... | @@ -20167,14 +20178,14 @@ fn zirReify( |
| 20167 | 20178 | .AnyFrame => return sema.failWithUseOfAsync(block, src), |
| 20168 | 20179 | .EnumLiteral => return .enum_literal_type, |
| 20169 | 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 | 20182 | const signedness_val = try union_val.val.toValue().fieldValue( |
| 20172 | 20183 | mod, |
| 20173 | fields.getIndex(try ip.getOrPutString(gpa, "signedness")).?, | |
| 20184 | struct_type.nameIndex(ip, try ip.getOrPutString(gpa, "signedness")).?, | |
| 20174 | 20185 | ); |
| 20175 | 20186 | const bits_val = try union_val.val.toValue().fieldValue( |
| 20176 | 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 | 20191 | const signedness = mod.toEnum(std.builtin.Signedness, signedness_val); |
| ... | ... | @@ -20183,11 +20194,13 @@ fn zirReify( |
| 20183 | 20194 | return Air.internedToRef(ty.toIntern()); |
| 20184 | 20195 | }, |
| 20185 | 20196 | .Vector => { |
| 20186 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | |
| 20187 | const len_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 20197 | const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type; | |
| 20198 | const len_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( | |
| 20199 | ip, | |
| 20188 | 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 | 20204 | try ip.getOrPutString(gpa, "child"), |
| 20192 | 20205 | ).?); |
| 20193 | 20206 | |
| ... | ... | @@ -20203,8 +20216,9 @@ fn zirReify( |
| 20203 | 20216 | return Air.internedToRef(ty.toIntern()); |
| 20204 | 20217 | }, |
| 20205 | 20218 | .Float => { |
| 20206 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | |
| 20207 | const bits_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 20219 | const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type; | |
| 20220 | const bits_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( | |
| 20221 | ip, | |
| 20208 | 20222 | try ip.getOrPutString(gpa, "bits"), |
| 20209 | 20223 | ).?); |
| 20210 | 20224 | |
| ... | ... | @@ -20220,29 +20234,37 @@ fn zirReify( |
| 20220 | 20234 | return Air.internedToRef(ty.toIntern()); |
| 20221 | 20235 | }, |
| 20222 | 20236 | .Pointer => { |
| 20223 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | |
| 20224 | const size_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 20237 | const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type; | |
| 20238 | const size_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( | |
| 20239 | ip, | |
| 20225 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 20268 | try ip.getOrPutString(gpa, "sentinel"), |
| 20247 | 20269 | ).?); |
| 20248 | 20270 | |
| ... | ... | @@ -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 | 20333 | .child = elem_ty.toIntern(), |
| 20312 | 20334 | .sentinel = actual_sentinel, |
| 20313 | 20335 | .flags = .{ |
| ... | ... | @@ -20322,14 +20344,17 @@ fn zirReify( |
| 20322 | 20344 | return Air.internedToRef(ty.toIntern()); |
| 20323 | 20345 | }, |
| 20324 | 20346 | .Array => { |
| 20325 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | |
| 20326 | const len_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 20347 | const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type; | |
| 20348 | const len_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( | |
| 20349 | ip, | |
| 20327 | 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 | 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 | 20358 | try ip.getOrPutString(gpa, "sentinel"), |
| 20334 | 20359 | ).?); |
| 20335 | 20360 | |
| ... | ... | @@ -20348,8 +20373,9 @@ fn zirReify( |
| 20348 | 20373 | return Air.internedToRef(ty.toIntern()); |
| 20349 | 20374 | }, |
| 20350 | 20375 | .Optional => { |
| 20351 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | |
| 20352 | const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 20376 | const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type; | |
| 20377 | const child_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( | |
| 20378 | ip, | |
| 20353 | 20379 | try ip.getOrPutString(gpa, "child"), |
| 20354 | 20380 | ).?); |
| 20355 | 20381 | |
| ... | ... | @@ -20359,11 +20385,13 @@ fn zirReify( |
| 20359 | 20385 | return Air.internedToRef(ty.toIntern()); |
| 20360 | 20386 | }, |
| 20361 | 20387 | .ErrorUnion => { |
| 20362 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | |
| 20363 | const error_set_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 20388 | const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type; | |
| 20389 | const error_set_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( | |
| 20390 | ip, | |
| 20364 | 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 | 20395 | try ip.getOrPutString(gpa, "payload"), |
| 20368 | 20396 | ).?); |
| 20369 | 20397 | |
| ... | ... | @@ -20386,8 +20414,9 @@ fn zirReify( |
| 20386 | 20414 | try names.ensureUnusedCapacity(sema.arena, len); |
| 20387 | 20415 | for (0..len) |i| { |
| 20388 | 20416 | const elem_val = try payload_val.elemValue(mod, i); |
| 20389 | const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); | |
| 20390 | const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | |
| 20417 | const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type; | |
| 20418 | const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( | |
| 20419 | ip, | |
| 20391 | 20420 | try ip.getOrPutString(gpa, "name"), |
| 20392 | 20421 | ).?); |
| 20393 | 20422 | |
| ... | ... | @@ -20405,20 +20434,25 @@ fn zirReify( |
| 20405 | 20434 | return Air.internedToRef(ty.toIntern()); |
| 20406 | 20435 | }, |
| 20407 | 20436 | .Struct => { |
| 20408 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | |
| 20409 | const layout_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 20437 | const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type; | |
| 20438 | const layout_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( | |
| 20439 | ip, | |
| 20410 | 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 | 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 | 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 | 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 | 20456 | try ip.getOrPutString(gpa, "is_tuple"), |
| 20423 | 20457 | ).?); |
| 20424 | 20458 | |
| ... | ... | @@ -20436,17 +20470,21 @@ fn zirReify( |
| 20436 | 20470 | return try sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_val, name_strategy, is_tuple_val.toBool()); |
| 20437 | 20471 | }, |
| 20438 | 20472 | .Enum => { |
| 20439 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | |
| 20440 | const tag_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 20473 | const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type; | |
| 20474 | const tag_type_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( | |
| 20475 | ip, | |
| 20441 | 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 | 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 | 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 | 20488 | try ip.getOrPutString(gpa, "is_exhaustive"), |
| 20451 | 20489 | ).?); |
| 20452 | 20490 | |
| ... | ... | @@ -20496,11 +20534,13 @@ fn zirReify( |
| 20496 | 20534 | |
| 20497 | 20535 | for (0..fields_len) |field_i| { |
| 20498 | 20536 | const elem_val = try fields_val.elemValue(mod, field_i); |
| 20499 | const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); | |
| 20500 | const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | |
| 20537 | const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type; | |
| 20538 | const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( | |
| 20539 | ip, | |
| 20501 | 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 | 20544 | try ip.getOrPutString(gpa, "value"), |
| 20505 | 20545 | ).?); |
| 20506 | 20546 | |
| ... | ... | @@ -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 | 20559 | const msg = msg: { |
| 20520 | 20560 | const msg = try sema.errMsg(block, src, "duplicate enum field '{}'", .{ |
| 20521 | 20561 | field_name.fmt(ip), |
| ... | ... | @@ -20528,7 +20568,7 @@ fn zirReify( |
| 20528 | 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 | 20572 | const msg = msg: { |
| 20533 | 20573 | const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{value_val.fmtValue(Type.comptime_int, mod)}); |
| 20534 | 20574 | errdefer msg.destroy(gpa); |
| ... | ... | @@ -20545,8 +20585,9 @@ fn zirReify( |
| 20545 | 20585 | return decl_val; |
| 20546 | 20586 | }, |
| 20547 | 20587 | .Opaque => { |
| 20548 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | |
| 20549 | const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 20588 | const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type; | |
| 20589 | const decls_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( | |
| 20590 | ip, | |
| 20550 | 20591 | try ip.getOrPutString(gpa, "decls"), |
| 20551 | 20592 | ).?); |
| 20552 | 20593 | |
| ... | ... | @@ -20594,17 +20635,21 @@ fn zirReify( |
| 20594 | 20635 | return decl_val; |
| 20595 | 20636 | }, |
| 20596 | 20637 | .Union => { |
| 20597 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | |
| 20598 | const layout_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 20638 | const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type; | |
| 20639 | const layout_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( | |
| 20640 | ip, | |
| 20599 | 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 | 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 | 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 | 20653 | try ip.getOrPutString(gpa, "decls"), |
| 20609 | 20654 | ).?); |
| 20610 | 20655 | |
| ... | ... | @@ -20644,14 +20689,17 @@ fn zirReify( |
| 20644 | 20689 | |
| 20645 | 20690 | for (0..fields_len) |i| { |
| 20646 | 20691 | const elem_val = try fields_val.elemValue(mod, i); |
| 20647 | const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); | |
| 20648 | const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | |
| 20692 | const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type; | |
| 20693 | const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( | |
| 20694 | ip, | |
| 20649 | 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 | 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 | 20703 | try ip.getOrPutString(gpa, "alignment"), |
| 20656 | 20704 | ).?); |
| 20657 | 20705 | |
| ... | ... | @@ -20812,23 +20860,29 @@ fn zirReify( |
| 20812 | 20860 | return decl_val; |
| 20813 | 20861 | }, |
| 20814 | 20862 | .Fn => { |
| 20815 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); | |
| 20816 | const calling_convention_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 20863 | const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type; | |
| 20864 | const calling_convention_val = try union_val.val.toValue().fieldValue(mod, struct_type.nameIndex( | |
| 20865 | ip, | |
| 20817 | 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 | 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 | 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 | 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 | 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 | 20886 | try ip.getOrPutString(gpa, "params"), |
| 20833 | 20887 | ).?); |
| 20834 | 20888 | |
| ... | ... | @@ -20844,15 +20898,9 @@ fn zirReify( |
| 20844 | 20898 | } |
| 20845 | 20899 | |
| 20846 | 20900 | const alignment = alignment: { |
| 20847 | if (!try sema.intFitsInType(alignment_val, Type.u32, null)) { | |
| 20848 | return sema.fail(block, src, "alignment must fit in 'u32'", .{}); | |
| 20849 | } | |
| 20850 | const alignment: u29 = @intCast(alignment_val.toUnsignedInt(mod)); | |
| 20851 | if (alignment == target_util.defaultFunctionAlignment(target)) { | |
| 20852 | break :alignment .none; | |
| 20853 | } else { | |
| 20854 | break :alignment Alignment.fromByteUnits(alignment); | |
| 20855 | } | |
| 20901 | const alignment = try sema.validateAlignAllowZero(block, src, alignment_val.toUnsignedInt(mod)); | |
| 20902 | const default = target_util.defaultFunctionAlignment(target); | |
| 20903 | break :alignment if (alignment == default) .none else alignment; | |
| 20856 | 20904 | }; |
| 20857 | 20905 | const return_type = return_type_val.optionalValue(mod) orelse |
| 20858 | 20906 | return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{}); |
| ... | ... | @@ -20863,14 +20911,17 @@ fn zirReify( |
| 20863 | 20911 | var noalias_bits: u32 = 0; |
| 20864 | 20912 | for (param_types, 0..) |*param_type, i| { |
| 20865 | 20913 | const elem_val = try params_val.elemValue(mod, i); |
| 20866 | const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); | |
| 20867 | const param_is_generic_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | |
| 20914 | const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type; | |
| 20915 | const param_is_generic_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( | |
| 20916 | ip, | |
| 20868 | 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 | 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 | 20925 | try ip.getOrPutString(gpa, "type"), |
| 20875 | 20926 | ).?); |
| 20876 | 20927 | |
| ... | ... | @@ -20931,6 +20982,8 @@ fn reifyStruct( |
| 20931 | 20982 | .Auto => {}, |
| 20932 | 20983 | }; |
| 20933 | 20984 | |
| 20985 | const fields_len: u32 = @intCast(try sema.usizeCast(block, src, fields_val.sliceLen(mod))); | |
| 20986 | ||
| 20934 | 20987 | // Because these three things each reference each other, `undefined` |
| 20935 | 20988 | // placeholders are used before being set after the struct type gains an |
| 20936 | 20989 | // InternPool index. |
| ... | ... | @@ -20946,58 +20999,52 @@ fn reifyStruct( |
| 20946 | 20999 | mod.abortAnonDecl(new_decl_index); |
| 20947 | 21000 | } |
| 20948 | 21001 | |
| 20949 | const new_namespace_index = try mod.createNamespace(.{ | |
| 20950 | .parent = block.namespace.toOptional(), | |
| 20951 | .ty = undefined, | |
| 20952 | .file_scope = block.getFileScope(mod), | |
| 20953 | }); | |
| 20954 | const new_namespace = mod.namespacePtr(new_namespace_index); | |
| 20955 | errdefer mod.destroyNamespace(new_namespace_index); | |
| 20956 | ||
| 20957 | const struct_index = try mod.createStruct(.{ | |
| 20958 | .owner_decl = new_decl_index, | |
| 20959 | .fields = .{}, | |
| 21002 | const ty = try ip.getStructType(gpa, .{ | |
| 21003 | .decl = new_decl_index, | |
| 21004 | .namespace = .none, | |
| 20960 | 21005 | .zir_index = inst, |
| 20961 | 21006 | .layout = layout, |
| 20962 | .status = .have_field_types, | |
| 20963 | 21007 | .known_non_opv = false, |
| 21008 | .fields_len = fields_len, | |
| 21009 | .requires_comptime = .unknown, | |
| 20964 | 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 | 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 | 21023 | new_decl.ty = Type.type; |
| 20978 | new_decl.val = struct_ty.toValue(); | |
| 20979 | new_namespace.ty = struct_ty.toType(); | |
| 21024 | new_decl.val = ty.toValue(); | |
| 20980 | 21025 | |
| 20981 | 21026 | // Fields |
| 20982 | const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod)); | |
| 20983 | try struct_obj.fields.ensureTotalCapacity(mod.tmp_hack_arena.allocator(), fields_len); | |
| 20984 | var i: usize = 0; | |
| 20985 | while (i < fields_len) : (i += 1) { | |
| 21027 | for (0..fields_len) |i| { | |
| 20986 | 21028 | const elem_val = try fields_val.elemValue(mod, i); |
| 20987 | const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); | |
| 20988 | const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | |
| 21029 | const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type; | |
| 21030 | const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( | |
| 21031 | ip, | |
| 20989 | 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 | 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 | 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 | 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 | 21048 | try ip.getOrPutString(gpa, "alignment"), |
| 21002 | 21049 | ).?); |
| 21003 | 21050 | |
| ... | ... | @@ -21009,6 +21056,8 @@ fn reifyStruct( |
| 21009 | 21056 | if (layout == .Packed) { |
| 21010 | 21057 | if (abi_align != 0) return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{}); |
| 21011 | 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 | 21062 | if (layout == .Extern and is_comptime_val.toBool()) { |
| 21014 | 21063 | return sema.fail(block, src, "extern struct fields cannot be marked comptime", .{}); |
| ... | ... | @@ -21032,10 +21081,8 @@ fn reifyStruct( |
| 21032 | 21081 | .{field_index}, |
| 21033 | 21082 | ); |
| 21034 | 21083 | } |
| 21035 | } | |
| 21036 | const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name); | |
| 21037 | if (gop.found_existing) { | |
| 21038 | // TODO: better source location | |
| 21084 | } else if (struct_type.addFieldName(ip, field_name)) |prev_index| { | |
| 21085 | _ = prev_index; // TODO: better source location | |
| 21039 | 21086 | return sema.fail(block, src, "duplicate struct field {}", .{field_name.fmt(ip)}); |
| 21040 | 21087 | } |
| 21041 | 21088 | |
| ... | ... | @@ -21051,13 +21098,10 @@ fn reifyStruct( |
| 21051 | 21098 | return sema.fail(block, src, "comptime field without default initialization value", .{}); |
| 21052 | 21099 | } |
| 21053 | 21100 | |
| 21054 | gop.value_ptr.* = .{ | |
| 21055 | .ty = field_ty, | |
| 21056 | .abi_align = Alignment.fromByteUnits(abi_align), | |
| 21057 | .default_val = default_val, | |
| 21058 | .is_comptime = is_comptime_val.toBool(), | |
| 21059 | .offset = undefined, | |
| 21060 | }; | |
| 21101 | struct_type.field_types.get(ip)[i] = field_ty.toIntern(); | |
| 21102 | struct_type.field_inits.get(ip)[i] = default_val; | |
| 21103 | if (is_comptime_val.toBool()) | |
| 21104 | struct_type.setFieldComptime(ip, i); | |
| 21061 | 21105 | |
| 21062 | 21106 | if (field_ty.zigTypeTag(mod) == .Opaque) { |
| 21063 | 21107 | const msg = msg: { |
| ... | ... | @@ -21079,7 +21123,7 @@ fn reifyStruct( |
| 21079 | 21123 | }; |
| 21080 | 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 | 21127 | const msg = msg: { |
| 21084 | 21128 | const msg = try sema.errMsg(block, src, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); |
| 21085 | 21129 | errdefer msg.destroy(gpa); |
| ... | ... | @@ -21091,7 +21135,7 @@ fn reifyStruct( |
| 21091 | 21135 | break :msg msg; |
| 21092 | 21136 | }; |
| 21093 | 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 | 21139 | const msg = msg: { |
| 21096 | 21140 | const msg = try sema.errMsg(block, src, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); |
| 21097 | 21141 | errdefer msg.destroy(gpa); |
| ... | ... | @@ -21107,13 +21151,12 @@ fn reifyStruct( |
| 21107 | 21151 | } |
| 21108 | 21152 | |
| 21109 | 21153 | if (layout == .Packed) { |
| 21110 | struct_obj.status = .layout_wip; | |
| 21111 | ||
| 21112 | for (struct_obj.fields.values(), 0..) |field, index| { | |
| 21113 | sema.resolveTypeLayout(field.ty) catch |err| switch (err) { | |
| 21154 | for (0..struct_type.field_types.len) |index| { | |
| 21155 | const field_ty = struct_type.field_types.get(ip)[index].toType(); | |
| 21156 | sema.resolveTypeLayout(field_ty) catch |err| switch (err) { | |
| 21114 | 21157 | error.AnalysisFail => { |
| 21115 | 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 | 21160 | return err; |
| 21118 | 21161 | }, |
| 21119 | 21162 | else => return err, |
| ... | ... | @@ -21121,19 +21164,18 @@ fn reifyStruct( |
| 21121 | 21164 | } |
| 21122 | 21165 | |
| 21123 | 21166 | var fields_bit_sum: u64 = 0; |
| 21124 | for (struct_obj.fields.values()) |field| { | |
| 21125 | fields_bit_sum += field.ty.bitSize(mod); | |
| 21167 | for (struct_type.field_types.get(ip)) |field_ty| { | |
| 21168 | fields_bit_sum += field_ty.toType().bitSize(mod); | |
| 21126 | 21169 | } |
| 21127 | 21170 | |
| 21128 | if (backing_int_val.optionalValue(mod)) |payload| { | |
| 21129 | const backing_int_ty = payload.toType(); | |
| 21171 | if (backing_int_val.optionalValue(mod)) |backing_int_ty_val| { | |
| 21172 | const backing_int_ty = backing_int_ty_val.toType(); | |
| 21130 | 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 | 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 | 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 | 21481 | const is_non_zero = try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize); |
| 21440 | 21482 | try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null); |
| 21441 | 21483 | } |
| 21442 | if (ptr_align > 1) { | |
| 21443 | const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, ptr_align - 1)).toIntern()); | |
| 21484 | if (ptr_align.compare(.gt, .@"1")) { | |
| 21485 | const align_bytes_minus_1 = ptr_align.toByteUnitsOptional().? - 1; | |
| 21486 | const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, align_bytes_minus_1)).toIntern()); | |
| 21444 | 21487 | const remainder = try block.addBinOp(.bit_and, operand_coerced, align_minus_1); |
| 21445 | 21488 | const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize); |
| 21446 | 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 | 21501 | const is_non_zero = try block.addBinOp(.cmp_neq, elem_coerced, .zero_usize); |
| 21459 | 21502 | try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null); |
| 21460 | 21503 | } |
| 21461 | if (ptr_align > 1) { | |
| 21462 | const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, ptr_align - 1)).toIntern()); | |
| 21504 | if (ptr_align.compare(.gt, .@"1")) { | |
| 21505 | const align_bytes_minus_1 = ptr_align.toByteUnitsOptional().? - 1; | |
| 21506 | const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, align_bytes_minus_1)).toIntern()); | |
| 21463 | 21507 | const remainder = try block.addBinOp(.bit_and, elem_coerced, align_minus_1); |
| 21464 | 21508 | const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize); |
| 21465 | 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 | 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 | 21531 | const mod = sema.mod; |
| 21481 | 21532 | const addr = operand_val.toUnsignedInt(mod); |
| 21482 | 21533 | if (!ptr_ty.isAllowzeroPtr(mod) and addr == 0) |
| 21483 | 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 | 21536 | return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{ptr_ty.fmt(sema.mod)}); |
| 21486 | 21537 | |
| 21487 | 21538 | return switch (ptr_ty.zigTypeTag(mod)) { |
| ... | ... | @@ -21795,18 +21846,26 @@ fn ptrCastFull( |
| 21795 | 21846 | // TODO: vector index? |
| 21796 | 21847 | } |
| 21797 | 21848 | |
| 21798 | const src_align = src_info.flags.alignment.toByteUnitsOptional() orelse src_info.child.toType().abiAlignment(mod); | |
| 21799 | const dest_align = dest_info.flags.alignment.toByteUnitsOptional() orelse dest_info.child.toType().abiAlignment(mod); | |
| 21849 | const src_align = if (src_info.flags.alignment != .none) | |
| 21850 | src_info.flags.alignment | |
| 21851 | else | |
| 21852 | src_info.child.toType().abiAlignment(mod); | |
| 21853 | ||
| 21854 | const dest_align = if (dest_info.flags.alignment != .none) | |
| 21855 | dest_info.flags.alignment | |
| 21856 | else | |
| 21857 | dest_info.child.toType().abiAlignment(mod); | |
| 21858 | ||
| 21800 | 21859 | if (!flags.align_cast) { |
| 21801 | if (dest_align > src_align) { | |
| 21860 | if (dest_align.compare(.gt, src_align)) { | |
| 21802 | 21861 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 21803 | 21862 | const msg = try sema.errMsg(block, src, "cast increases pointer alignment", .{}); |
| 21804 | 21863 | errdefer msg.destroy(sema.gpa); |
| 21805 | 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 | 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 | 21870 | try sema.errNote(block, src, msg, "use @alignCast to assert pointer alignment", .{}); |
| 21812 | 21871 | break :msg msg; |
| ... | ... | @@ -21874,7 +21933,7 @@ fn ptrCastFull( |
| 21874 | 21933 | // Only convert to a many-pointer at first |
| 21875 | 21934 | var info = dest_info; |
| 21876 | 21935 | info.flags.size = .Many; |
| 21877 | const ty = try mod.ptrType(info); | |
| 21936 | const ty = try sema.ptrType(info); | |
| 21878 | 21937 | if (dest_ty.zigTypeTag(mod) == .Optional) { |
| 21879 | 21938 | break :blk try mod.optionalType(ty.toIntern()); |
| 21880 | 21939 | } else { |
| ... | ... | @@ -21891,10 +21950,13 @@ fn ptrCastFull( |
| 21891 | 21950 | if (!dest_ty.ptrAllowsZero(mod) and ptr_val.isNull(mod)) { |
| 21892 | 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 | 21954 | if (try ptr_val.getUnsignedIntAdvanced(mod, null)) |addr| { |
| 21896 | if (addr % dest_align != 0) { | |
| 21897 | return sema.fail(block, operand_src, "pointer address 0x{X} is not aligned to {d} bytes", .{ addr, dest_align }); | |
| 21955 | if (!dest_align.check(addr)) { | |
| 21956 | return sema.fail(block, operand_src, "pointer address 0x{X} is not aligned to {d} bytes", .{ | |
| 21957 | addr, | |
| 21958 | dest_align.toByteUnitsOptional().?, | |
| 21959 | }); | |
| 21898 | 21960 | } |
| 21899 | 21961 | } |
| 21900 | 21962 | } |
| ... | ... | @@ -21928,8 +21990,12 @@ fn ptrCastFull( |
| 21928 | 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())) { | |
| 21932 | const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, dest_align - 1)).toIntern()); | |
| 21993 | if (block.wantSafety() and | |
| 21994 | dest_align.compare(.gt, src_align) and | |
| 21995 | try sema.typeHasRuntimeBits(dest_info.child.toType())) | |
| 21996 | { | |
| 21997 | const align_bytes_minus_1 = dest_align.toByteUnitsOptional().? - 1; | |
| 21998 | const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, align_bytes_minus_1)).toIntern()); | |
| 21933 | 21999 | const ptr_int = try block.addUnOp(.int_from_ptr, ptr); |
| 21934 | 22000 | const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1); |
| 21935 | 22001 | const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize); |
| ... | ... | @@ -21946,7 +22012,7 @@ fn ptrCastFull( |
| 21946 | 22012 | // We can't change address spaces with a bitcast, so this requires two instructions |
| 21947 | 22013 | var intermediate_info = src_info; |
| 21948 | 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 | 22016 | const intermediate_ty = if (dest_ptr_ty.zigTypeTag(mod) == .Optional) blk: { |
| 21951 | 22017 | break :blk try mod.optionalType(intermediate_ptr_ty.toIntern()); |
| 21952 | 22018 | } else intermediate_ptr_ty; |
| ... | ... | @@ -22002,7 +22068,7 @@ fn zirPtrCastNoDest(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst |
| 22002 | 22068 | var ptr_info = operand_ty.ptrInfo(mod); |
| 22003 | 22069 | if (flags.const_cast) ptr_info.flags.is_const = false; |
| 22004 | 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 | 22073 | if (try sema.resolveMaybeUndefVal(operand)) |operand_val| { |
| 22008 | 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 | 22351 | }); |
| 22286 | 22352 | |
| 22287 | 22353 | const mod = sema.mod; |
| 22354 | const ip = &mod.intern_pool; | |
| 22288 | 22355 | try sema.resolveTypeLayout(ty); |
| 22289 | 22356 | switch (ty.zigTypeTag(mod)) { |
| 22290 | 22357 | .Struct => {}, |
| ... | ... | @@ -22300,7 +22367,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6 |
| 22300 | 22367 | } |
| 22301 | 22368 | |
| 22302 | 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 | 22371 | return sema.fail(block, src, "no offset available for 'len' field of tuple", .{}); |
| 22305 | 22372 | } |
| 22306 | 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 | 22380 | switch (ty.containerLayout(mod)) { |
| 22314 | 22381 | .Packed => { |
| 22315 | 22382 | var bit_sum: u64 = 0; |
| 22316 | const fields = ty.structFields(mod); | |
| 22317 | for (fields.values(), 0..) |field, i| { | |
| 22383 | const struct_type = ip.indexToKey(ty.toIntern()).struct_type; | |
| 22384 | for (0..struct_type.field_types.len) |i| { | |
| 22318 | 22385 | if (i == field_index) { |
| 22319 | 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 | 22390 | } else unreachable; |
| 22323 | 22391 | }, |
| 22324 | 22392 | else => return ty.structFieldOffset(field_index, mod) * 8, |
| ... | ... | @@ -22535,7 +22603,7 @@ fn checkAtomicPtrOperand( |
| 22535 | 22603 | const ptr_data = switch (try ptr_ty.zigTypeTagOrPoison(mod)) { |
| 22536 | 22604 | .Pointer => ptr_ty.ptrInfo(mod), |
| 22537 | 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 | 22607 | _ = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src); |
| 22540 | 22608 | unreachable; |
| 22541 | 22609 | }, |
| ... | ... | @@ -22545,7 +22613,7 @@ fn checkAtomicPtrOperand( |
| 22545 | 22613 | wanted_ptr_data.flags.is_allowzero = ptr_data.flags.is_allowzero; |
| 22546 | 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 | 22617 | const casted_ptr = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src); |
| 22550 | 22618 | |
| 22551 | 22619 | return casted_ptr; |
| ... | ... | @@ -23717,8 +23785,8 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr |
| 23717 | 23785 | return sema.fail(block, src, "TODO handle packed structs/unions with @fieldParentPtr", .{}); |
| 23718 | 23786 | } else { |
| 23719 | 23787 | ptr_ty_data.flags.alignment = blk: { |
| 23720 | if (mod.typeToStruct(parent_ty)) |struct_obj| { | |
| 23721 | break :blk struct_obj.fields.values()[field_index].abi_align; | |
| 23788 | if (mod.typeToStruct(parent_ty)) |struct_type| { | |
| 23789 | break :blk struct_type.fieldAlign(ip, field_index); | |
| 23722 | 23790 | } else if (mod.typeToUnion(parent_ty)) |union_obj| { |
| 23723 | 23791 | break :blk union_obj.fieldAlign(ip, field_index); |
| 23724 | 23792 | } else { |
| ... | ... | @@ -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 | 23799 | const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, ptr_src); |
| 23732 | 23800 | |
| 23733 | 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 | 23804 | if (try sema.resolveDefinedValue(block, src, casted_field_ptr)) |field_ptr_val| { |
| 23737 | 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 | 24130 | // Already an array pointer. |
| 24063 | 24131 | return ptr; |
| 24064 | 24132 | } |
| 24065 | const new_ty = try mod.ptrType(.{ | |
| 24133 | const new_ty = try sema.ptrType(.{ | |
| 24066 | 24134 | .child = (try mod.arrayType(.{ |
| 24067 | 24135 | .len = len, |
| 24068 | 24136 | .sentinel = info.sentinel, |
| ... | ... | @@ -24266,7 +24334,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 24266 | 24334 | assert(dest_manyptr_ty_key.flags.size == .One); |
| 24267 | 24335 | dest_manyptr_ty_key.child = dest_elem_ty.toIntern(); |
| 24268 | 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 | 24338 | } else new_dest_ptr; |
| 24271 | 24339 | |
| 24272 | 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 | 24345 | assert(src_manyptr_ty_key.flags.size == .One); |
| 24278 | 24346 | src_manyptr_ty_key.child = src_elem_ty.toIntern(); |
| 24279 | 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 | 24349 | } else new_src_ptr; |
| 24282 | 24350 | |
| 24283 | 24351 | // ok1: dest >= src + len |
| ... | ... | @@ -24528,13 +24596,9 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 24528 | 24596 | if (val.isGenericPoison()) { |
| 24529 | 24597 | break :blk null; |
| 24530 | 24598 | } |
| 24531 | const alignment: u32 = @intCast(val.toUnsignedInt(mod)); | |
| 24532 | try sema.validateAlign(block, align_src, alignment); | |
| 24533 | if (alignment == target_util.defaultFunctionAlignment(target)) { | |
| 24534 | break :blk .none; | |
| 24535 | } else { | |
| 24536 | break :blk Alignment.fromNonzeroByteUnits(alignment); | |
| 24537 | } | |
| 24599 | const alignment = try sema.validateAlignAllowZero(block, align_src, val.toUnsignedInt(mod)); | |
| 24600 | const default = target_util.defaultFunctionAlignment(target); | |
| 24601 | break :blk if (alignment == default) .none else alignment; | |
| 24538 | 24602 | } else if (extra.data.bits.has_align_ref) blk: { |
| 24539 | 24603 | const align_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]); |
| 24540 | 24604 | extra_index += 1; |
| ... | ... | @@ -24546,13 +24610,9 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 24546 | 24610 | }, |
| 24547 | 24611 | else => |e| return e, |
| 24548 | 24612 | }; |
| 24549 | const alignment: u32 = @intCast(align_tv.val.toUnsignedInt(mod)); | |
| 24550 | try sema.validateAlign(block, align_src, alignment); | |
| 24551 | if (alignment == target_util.defaultFunctionAlignment(target)) { | |
| 24552 | break :blk .none; | |
| 24553 | } else { | |
| 24554 | break :blk Alignment.fromNonzeroByteUnits(alignment); | |
| 24555 | } | |
| 24613 | const alignment = try sema.validateAlignAllowZero(block, align_src, align_tv.val.toUnsignedInt(mod)); | |
| 24614 | const default = target_util.defaultFunctionAlignment(target); | |
| 24615 | break :blk if (alignment == default) .none else alignment; | |
| 24556 | 24616 | } else .none; |
| 24557 | 24617 | |
| 24558 | 24618 | const @"addrspace": ?std.builtin.AddressSpace = if (extra.data.bits.has_addrspace_body) blk: { |
| ... | ... | @@ -25237,16 +25297,17 @@ fn explainWhyTypeIsComptimeInner( |
| 25237 | 25297 | .Struct => { |
| 25238 | 25298 | if ((try type_set.getOrPut(sema.gpa, ty.toIntern())).found_existing) return; |
| 25239 | 25299 | |
| 25240 | if (mod.typeToStruct(ty)) |struct_obj| { | |
| 25241 | for (struct_obj.fields.values(), 0..) |field, i| { | |
| 25242 | const field_src_loc = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | |
| 25300 | if (mod.typeToStruct(ty)) |struct_type| { | |
| 25301 | for (0..struct_type.field_types.len) |i| { | |
| 25302 | const field_ty = struct_type.field_types.get(ip)[i].toType(); | |
| 25303 | const field_src_loc = mod.fieldSrcLoc(struct_type.decl.unwrap().?, .{ | |
| 25243 | 25304 | .index = i, |
| 25244 | 25305 | .range = .type, |
| 25245 | 25306 | }); |
| 25246 | 25307 | |
| 25247 | if (try sema.typeRequiresComptime(field.ty)) { | |
| 25308 | if (try sema.typeRequiresComptime(field_ty)) { | |
| 25248 | 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 | 25576 | const stack_trace_ty = try sema.getBuiltinType("StackTrace"); |
| 25516 | 25577 | try sema.resolveTypeFields(stack_trace_ty); |
| 25517 | 25578 | const target = mod.getTarget(); |
| 25518 | const ptr_stack_trace_ty = try mod.ptrType(.{ | |
| 25579 | const ptr_stack_trace_ty = try sema.ptrType(.{ | |
| 25519 | 25580 | .child = stack_trace_ty.toIntern(), |
| 25520 | 25581 | .flags = .{ |
| 25521 | 25582 | .address_space = target_util.defaultAddressSpace(target, .global_constant), |
| ... | ... | @@ -25867,7 +25928,7 @@ fn fieldVal( |
| 25867 | 25928 | return Air.internedToRef((try mod.intValue(Type.usize, inner_ty.arrayLen(mod))).toIntern()); |
| 25868 | 25929 | } else if (ip.stringEqlSlice(field_name, "ptr") and is_pointer_to) { |
| 25869 | 25930 | const ptr_info = object_ty.ptrInfo(mod); |
| 25870 | const result_ty = try mod.ptrType(.{ | |
| 25931 | const result_ty = try sema.ptrType(.{ | |
| 25871 | 25932 | .child = ptr_info.child.toType().childType(mod).toIntern(), |
| 25872 | 25933 | .sentinel = ptr_info.sentinel, |
| 25873 | 25934 | .flags = .{ |
| ... | ... | @@ -26086,7 +26147,7 @@ fn fieldPtr( |
| 26086 | 26147 | if (ip.stringEqlSlice(field_name, "ptr")) { |
| 26087 | 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 | 26151 | .child = slice_ptr_ty.toIntern(), |
| 26091 | 26152 | .flags = .{ |
| 26092 | 26153 | .is_const = !attr_ptr_ty.ptrIsMutable(mod), |
| ... | ... | @@ -26108,7 +26169,7 @@ fn fieldPtr( |
| 26108 | 26169 | |
| 26109 | 26170 | return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr); |
| 26110 | 26171 | } else if (ip.stringEqlSlice(field_name, "len")) { |
| 26111 | const result_ty = try mod.ptrType(.{ | |
| 26172 | const result_ty = try sema.ptrType(.{ | |
| 26112 | 26173 | .child = .usize_type, |
| 26113 | 26174 | .flags = .{ |
| 26114 | 26175 | .is_const = !attr_ptr_ty.ptrIsMutable(mod), |
| ... | ... | @@ -26297,13 +26358,12 @@ fn fieldCallBind( |
| 26297 | 26358 | switch (concrete_ty.zigTypeTag(mod)) { |
| 26298 | 26359 | .Struct => { |
| 26299 | 26360 | try sema.resolveTypeFields(concrete_ty); |
| 26300 | if (mod.typeToStruct(concrete_ty)) |struct_obj| { | |
| 26301 | const field_index_usize = struct_obj.fields.getIndex(field_name) orelse | |
| 26361 | if (mod.typeToStruct(concrete_ty)) |struct_type| { | |
| 26362 | const field_index = struct_type.nameIndex(ip, field_name) orelse | |
| 26302 | 26363 | break :find_field; |
| 26303 | const field_index: u32 = @intCast(field_index_usize); | |
| 26304 | const field = struct_obj.fields.values()[field_index]; | |
| 26364 | const field_ty = struct_type.field_types.get(ip)[field_index].toType(); | |
| 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 | 26367 | } else if (concrete_ty.isTuple(mod)) { |
| 26308 | 26368 | if (ip.stringEqlSlice(field_name, "len")) { |
| 26309 | 26369 | return .{ .direct = try mod.intRef(Type.usize, concrete_ty.structFieldCount(mod)) }; |
| ... | ... | @@ -26316,7 +26376,7 @@ fn fieldCallBind( |
| 26316 | 26376 | const max = concrete_ty.structFieldCount(mod); |
| 26317 | 26377 | for (0..max) |i_usize| { |
| 26318 | 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 | 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 | 26494 | object_ptr: Air.Inst.Ref, |
| 26435 | 26495 | ) CompileError!ResolvedFieldCallee { |
| 26436 | 26496 | const mod = sema.mod; |
| 26437 | const ptr_field_ty = try mod.ptrType(.{ | |
| 26497 | const ptr_field_ty = try sema.ptrType(.{ | |
| 26438 | 26498 | .child = field_ty.toIntern(), |
| 26439 | 26499 | .flags = .{ |
| 26440 | 26500 | .is_const = !ptr_ty.ptrIsMutable(mod), |
| ... | ... | @@ -26526,13 +26586,14 @@ fn structFieldPtr( |
| 26526 | 26586 | initializing: bool, |
| 26527 | 26587 | ) CompileError!Air.Inst.Ref { |
| 26528 | 26588 | const mod = sema.mod; |
| 26589 | const ip = &mod.intern_pool; | |
| 26529 | 26590 | assert(struct_ty.zigTypeTag(mod) == .Struct); |
| 26530 | 26591 | |
| 26531 | 26592 | try sema.resolveTypeFields(struct_ty); |
| 26532 | 26593 | try sema.resolveStructLayout(struct_ty); |
| 26533 | 26594 | |
| 26534 | 26595 | if (struct_ty.isTuple(mod)) { |
| 26535 | if (mod.intern_pool.stringEqlSlice(field_name, "len")) { | |
| 26596 | if (ip.stringEqlSlice(field_name, "len")) { | |
| 26536 | 26597 | const len_inst = try mod.intRef(Type.usize, struct_ty.structFieldCount(mod)); |
| 26537 | 26598 | return sema.analyzeRef(block, src, len_inst); |
| 26538 | 26599 | } |
| ... | ... | @@ -26543,11 +26604,10 @@ fn structFieldPtr( |
| 26543 | 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 | |
| 26549 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name); | |
| 26550 | const field_index: u32 = @intCast(field_index_big); | |
| 26609 | const field_index = struct_type.nameIndex(ip, field_name) orelse | |
| 26610 | return sema.failWithBadStructFieldAccess(block, struct_type, field_name_src, field_name); | |
| 26551 | 26611 | |
| 26552 | 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 | 26623 | initializing: bool, |
| 26564 | 26624 | ) CompileError!Air.Inst.Ref { |
| 26565 | 26625 | const mod = sema.mod; |
| 26626 | const ip = &mod.intern_pool; | |
| 26566 | 26627 | if (struct_ty.isAnonStruct(mod)) { |
| 26567 | 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).?; | |
| 26571 | const field = struct_obj.fields.values()[field_index]; | |
| 26631 | const struct_type = mod.typeToStruct(struct_ty).?; | |
| 26632 | const field_ty = struct_type.field_types.get(ip)[field_index]; | |
| 26572 | 26633 | const struct_ptr_ty = sema.typeOf(struct_ptr); |
| 26573 | 26634 | const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(mod); |
| 26574 | 26635 | |
| 26575 | 26636 | var ptr_ty_data: InternPool.Key.PtrType = .{ |
| 26576 | .child = field.ty.toIntern(), | |
| 26637 | .child = field_ty, | |
| 26577 | 26638 | .flags = .{ |
| 26578 | 26639 | .is_const = struct_ptr_ty_info.flags.is_const, |
| 26579 | 26640 | .is_volatile = struct_ptr_ty_info.flags.is_volatile, |
| ... | ... | @@ -26583,20 +26644,23 @@ fn structFieldPtrByIndex( |
| 26583 | 26644 | |
| 26584 | 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 | 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 | 26653 | comptime assert(Type.packed_struct_layout_version == 2); |
| 26591 | 26654 | |
| 26592 | 26655 | var running_bits: u16 = 0; |
| 26593 | for (struct_obj.fields.values(), 0..) |f, i| { | |
| 26594 | if (!(try sema.typeHasRuntimeBits(f.ty))) continue; | |
| 26656 | for (0..struct_type.field_types.len) |i| { | |
| 26657 | const f_ty = struct_type.field_types.get(ip)[i].toType(); | |
| 26658 | if (!(try sema.typeHasRuntimeBits(f_ty))) continue; | |
| 26595 | 26659 | |
| 26596 | 26660 | if (i == field_index) { |
| 26597 | 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 | 26665 | ptr_ty_data.packed_offset.host_size = (running_bits + 7) / 8; |
| 26602 | 26666 | |
| ... | ... | @@ -26607,7 +26671,7 @@ fn structFieldPtrByIndex( |
| 26607 | 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 | 26676 | // If the field happens to be byte-aligned, simplify the pointer type. |
| 26613 | 26677 | // The pointee type bit size must match its ABI byte size so that loads and stores |
| ... | ... | @@ -26617,38 +26681,47 @@ fn structFieldPtrByIndex( |
| 26617 | 26681 | // targets before adding the necessary complications to this code. This will not |
| 26618 | 26682 | // cause miscompilations; it only means the field pointer uses bit masking when it |
| 26619 | 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 | 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 | 26688 | const elem_size_bits = ptr_ty_data.child.toType().bitSize(mod); |
| 26625 | 26689 | if (elem_size_bytes * 8 == elem_size_bits) { |
| 26626 | 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 | 26692 | assert(new_align != .none); |
| 26629 | 26693 | ptr_ty_data.flags.alignment = new_align; |
| 26630 | 26694 | ptr_ty_data.packed_offset = .{ .host_size = 0, .bit_offset = 0 }; |
| 26631 | 26695 | } |
| 26632 | 26696 | } |
| 26633 | } else if (struct_obj.layout == .Extern) { | |
| 26634 | // For extern structs, field aligment might be bigger than type's natural alignment. Eg, in | |
| 26635 | // `extern struct { x: u32, y: u16 }` the second field is aligned as u32. | |
| 26697 | } else if (struct_type.layout == .Extern) { | |
| 26698 | // For extern structs, field alignment might be bigger than type's | |
| 26699 | // natural alignment. Eg, in `extern struct { x: u32, y: u16 }` the | |
| 26700 | // second field is aligned as u32. | |
| 26636 | 26701 | const field_offset = struct_ty.structFieldOffset(field_index, mod); |
| 26637 | ptr_ty_data.flags.alignment = Alignment.fromByteUnits( | |
| 26638 | if (parent_align == 0) 0 else std.math.gcd(field_offset, parent_align), | |
| 26639 | ); | |
| 26702 | ptr_ty_data.flags.alignment = if (parent_align == .none) | |
| 26703 | .none | |
| 26704 | else | |
| 26705 | @enumFromInt(@min(@intFromEnum(parent_align), @ctz(field_offset))); | |
| 26640 | 26706 | } else { |
| 26641 | // Our alignment is capped at the field alignment | |
| 26642 | const field_align = try sema.structFieldAlignment(field, struct_obj.layout); | |
| 26643 | ptr_ty_data.flags.alignment = Alignment.fromByteUnits(@min(field_align, parent_align)); | |
| 26707 | // Our alignment is capped at the field alignment. | |
| 26708 | const field_align = try sema.structFieldAlignment( | |
| 26709 | struct_type.fieldAlign(ip, field_index), | |
| 26710 | field_ty.toType(), | |
| 26711 | struct_type.layout, | |
| 26712 | ); | |
| 26713 | ptr_ty_data.flags.alignment = if (struct_ptr_ty_info.flags.alignment == .none) | |
| 26714 | field_align | |
| 26715 | else | |
| 26716 | field_align.min(parent_align); | |
| 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 | 26722 | const val = try mod.intern(.{ .ptr = .{ |
| 26650 | 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 | 26726 | return Air.internedToRef(val); |
| 26654 | 26727 | } |
| ... | ... | @@ -26678,33 +26751,34 @@ fn structFieldVal( |
| 26678 | 26751 | struct_ty: Type, |
| 26679 | 26752 | ) CompileError!Air.Inst.Ref { |
| 26680 | 26753 | const mod = sema.mod; |
| 26754 | const ip = &mod.intern_pool; | |
| 26681 | 26755 | assert(struct_ty.zigTypeTag(mod) == .Struct); |
| 26682 | 26756 | |
| 26683 | 26757 | try sema.resolveTypeFields(struct_ty); |
| 26684 | switch (mod.intern_pool.indexToKey(struct_ty.toIntern())) { | |
| 26758 | switch (ip.indexToKey(struct_ty.toIntern())) { | |
| 26685 | 26759 | .struct_type => |struct_type| { |
| 26686 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 26687 | if (struct_obj.is_tuple) return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty); | |
| 26688 | ||
| 26689 | const field_index_usize = struct_obj.fields.getIndex(field_name) orelse | |
| 26690 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name); | |
| 26691 | const field_index: u32 = @intCast(field_index_usize); | |
| 26692 | const field = struct_obj.fields.values()[field_index]; | |
| 26760 | if (struct_type.isTuple(ip)) | |
| 26761 | return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty); | |
| 26693 | 26762 | |
| 26694 | if (field.is_comptime) { | |
| 26695 | return Air.internedToRef(field.default_val); | |
| 26763 | const field_index = struct_type.nameIndex(ip, field_name) orelse | |
| 26764 | return sema.failWithBadStructFieldAccess(block, struct_type, field_name_src, field_name); | |
| 26765 | if (struct_type.fieldIsComptime(ip, field_index)) { | |
| 26766 | return Air.internedToRef(struct_type.field_inits.get(ip)[field_index]); | |
| 26696 | 26767 | } |
| 26697 | 26768 | |
| 26769 | const field_ty = struct_type.field_types.get(ip)[field_index].toType(); | |
| 26770 | ||
| 26698 | 26771 | if (try sema.resolveMaybeUndefVal(struct_byval)) |struct_val| { |
| 26699 | if (struct_val.isUndef(mod)) return mod.undefRef(field.ty); | |
| 26700 | if ((try sema.typeHasOnePossibleValue(field.ty))) |opv| { | |
| 26772 | if (struct_val.isUndef(mod)) return mod.undefRef(field_ty); | |
| 26773 | if ((try sema.typeHasOnePossibleValue(field_ty))) |opv| { | |
| 26701 | 26774 | return Air.internedToRef(opv.toIntern()); |
| 26702 | 26775 | } |
| 26703 | 26776 | return Air.internedToRef((try struct_val.fieldValue(mod, field_index)).toIntern()); |
| 26704 | 26777 | } |
| 26705 | 26778 | |
| 26706 | 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 | 26783 | .anon_struct_type => |anon_struct| { |
| 26710 | 26784 | if (anon_struct.names.len == 0) { |
| ... | ... | @@ -26792,6 +26866,7 @@ fn tupleFieldValByIndex( |
| 26792 | 26866 | } |
| 26793 | 26867 | |
| 26794 | 26868 | try sema.requireRuntimeBlock(block, src, null); |
| 26869 | try sema.resolveTypeLayout(field_ty); | |
| 26795 | 26870 | return block.addStructFieldVal(tuple_byval, field_index, field_ty); |
| 26796 | 26871 | } |
| 26797 | 26872 | |
| ... | ... | @@ -26816,16 +26891,19 @@ fn unionFieldPtr( |
| 26816 | 26891 | const union_obj = mod.typeToUnion(union_ty).?; |
| 26817 | 26892 | const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); |
| 26818 | 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 | 26895 | .child = field_ty.toIntern(), |
| 26821 | 26896 | .flags = .{ |
| 26822 | 26897 | .is_const = union_ptr_info.flags.is_const, |
| 26823 | 26898 | .is_volatile = union_ptr_info.flags.is_volatile, |
| 26824 | 26899 | .address_space = union_ptr_info.flags.address_space, |
| 26825 | 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 | 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 | 26907 | } else union_ptr_info.flags.alignment, |
| 26830 | 26908 | }, |
| 26831 | 26909 | .packed_offset = union_ptr_info.packed_offset, |
| ... | ... | @@ -26970,6 +27048,7 @@ fn unionFieldVal( |
| 26970 | 27048 | _ = try block.addNoOp(.unreach); |
| 26971 | 27049 | return .unreachable_value; |
| 26972 | 27050 | } |
| 27051 | try sema.resolveTypeLayout(field_ty); | |
| 26973 | 27052 | return block.addStructFieldVal(union_byval, field_index, field_ty); |
| 26974 | 27053 | } |
| 26975 | 27054 | |
| ... | ... | @@ -27194,7 +27273,7 @@ fn tupleFieldPtr( |
| 27194 | 27273 | } |
| 27195 | 27274 | |
| 27196 | 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 | 27277 | .child = field_ty.toIntern(), |
| 27199 | 27278 | .flags = .{ |
| 27200 | 27279 | .is_const = !tuple_ptr_ty.ptrIsMutable(mod), |
| ... | ... | @@ -27265,6 +27344,7 @@ fn tupleField( |
| 27265 | 27344 | try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src); |
| 27266 | 27345 | |
| 27267 | 27346 | try sema.requireRuntimeBlock(block, tuple_src, null); |
| 27347 | try sema.resolveTypeLayout(field_ty); | |
| 27268 | 27348 | return block.addStructFieldVal(tuple, field_index, field_ty); |
| 27269 | 27349 | } |
| 27270 | 27350 | |
| ... | ... | @@ -28266,7 +28346,7 @@ const InMemoryCoercionResult = union(enum) { |
| 28266 | 28346 | ptr_qualifiers: Qualifiers, |
| 28267 | 28347 | ptr_allowzero: Pair, |
| 28268 | 28348 | ptr_bit_range: BitRange, |
| 28269 | ptr_alignment: IntPair, | |
| 28349 | ptr_alignment: AlignPair, | |
| 28270 | 28350 | double_ptr_to_anyopaque: Pair, |
| 28271 | 28351 | slice_to_anyopaque: Pair, |
| 28272 | 28352 | |
| ... | ... | @@ -28312,6 +28392,11 @@ const InMemoryCoercionResult = union(enum) { |
| 28312 | 28392 | wanted: u64, |
| 28313 | 28393 | }; |
| 28314 | 28394 | |
| 28395 | const AlignPair = struct { | |
| 28396 | actual: Alignment, | |
| 28397 | wanted: Alignment, | |
| 28398 | }; | |
| 28399 | ||
| 28315 | 28400 | const Size = struct { |
| 28316 | 28401 | actual: std.builtin.Type.Pointer.Size, |
| 28317 | 28402 | wanted: std.builtin.Type.Pointer.Size, |
| ... | ... | @@ -28555,8 +28640,8 @@ const InMemoryCoercionResult = union(enum) { |
| 28555 | 28640 | break; |
| 28556 | 28641 | }, |
| 28557 | 28642 | .ptr_alignment => |pair| { |
| 28558 | try sema.errNote(block, src, msg, "pointer alignment '{}' cannot cast into pointer alignment '{}'", .{ | |
| 28559 | pair.actual, pair.wanted, | |
| 28643 | try sema.errNote(block, src, msg, "pointer alignment '{d}' cannot cast into pointer alignment '{d}'", .{ | |
| 28644 | pair.actual.toByteUnits(0), pair.wanted.toByteUnits(0), | |
| 28560 | 28645 | }); |
| 28561 | 28646 | break; |
| 28562 | 28647 | }, |
| ... | ... | @@ -29133,13 +29218,17 @@ fn coerceInMemoryAllowedPtrs( |
| 29133 | 29218 | if (src_info.flags.alignment != .none or dest_info.flags.alignment != .none or |
| 29134 | 29219 | dest_info.child != src_info.child) |
| 29135 | 29220 | { |
| 29136 | const src_align = src_info.flags.alignment.toByteUnitsOptional() orelse | |
| 29137 | src_info.child.toType().abiAlignment(mod); | |
| 29221 | const src_align = if (src_info.flags.alignment != .none) | |
| 29222 | src_info.flags.alignment | |
| 29223 | else | |
| 29224 | try sema.typeAbiAlignment(src_info.child.toType()); | |
| 29138 | 29225 | |
| 29139 | const dest_align = dest_info.flags.alignment.toByteUnitsOptional() orelse | |
| 29140 | dest_info.child.toType().abiAlignment(mod); | |
| 29226 | const dest_align = if (dest_info.flags.alignment != .none) | |
| 29227 | dest_info.flags.alignment | |
| 29228 | else | |
| 29229 | try sema.typeAbiAlignment(dest_info.child.toType()); | |
| 29141 | 29230 | |
| 29142 | if (dest_align > src_align) { | |
| 29231 | if (dest_align.compare(.gt, src_align)) { | |
| 29143 | 29232 | return InMemoryCoercionResult{ .ptr_alignment = .{ |
| 29144 | 29233 | .actual = src_align, |
| 29145 | 29234 | .wanted = dest_align, |
| ... | ... | @@ -30378,13 +30467,17 @@ fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_resul |
| 30378 | 30467 | if (inst_info.flags.alignment == .none and dest_info.flags.alignment == .none) return true; |
| 30379 | 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 | 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 | 30478 | dest_info.child.toType().abiAlignment(mod); |
| 30386 | 30479 | |
| 30387 | if (dest_align > inst_align) { | |
| 30480 | if (dest_align.compare(.gt, inst_align)) { | |
| 30388 | 30481 | in_memory_result.* = .{ .ptr_alignment = .{ |
| 30389 | 30482 | .actual = inst_align, |
| 30390 | 30483 | .wanted = dest_align, |
| ... | ... | @@ -30598,7 +30691,7 @@ fn coerceAnonStructToUnion( |
| 30598 | 30691 | else |
| 30599 | 30692 | .{ .count = anon_struct_type.names.len }, |
| 30600 | 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 | 30695 | break :name if (field_names.len == 1) |
| 30603 | 30696 | .{ .name = field_names[0] } |
| 30604 | 30697 | else |
| ... | ... | @@ -30869,8 +30962,8 @@ fn coerceTupleToStruct( |
| 30869 | 30962 | return sema.coerceTupleToTuple(block, struct_ty, inst, inst_src); |
| 30870 | 30963 | } |
| 30871 | 30964 | |
| 30872 | const fields = struct_ty.structFields(mod); | |
| 30873 | const field_vals = try sema.arena.alloc(InternPool.Index, fields.count()); | |
| 30965 | const struct_type = mod.typeToStruct(struct_ty).?; | |
| 30966 | const field_vals = try sema.arena.alloc(InternPool.Index, struct_type.field_types.len); | |
| 30874 | 30967 | const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len); |
| 30875 | 30968 | @memset(field_refs, .none); |
| 30876 | 30969 | |
| ... | ... | @@ -30878,10 +30971,7 @@ fn coerceTupleToStruct( |
| 30878 | 30971 | var runtime_src: ?LazySrcLoc = null; |
| 30879 | 30972 | const field_count = switch (ip.indexToKey(inst_ty.toIntern())) { |
| 30880 | 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| | |
| 30882 | struct_obj.fields.count() | |
| 30883 | else | |
| 30884 | 0, | |
| 30974 | .struct_type => |s| s.field_types.len, | |
| 30885 | 30975 | else => unreachable, |
| 30886 | 30976 | }; |
| 30887 | 30977 | for (0..field_count) |field_index_usize| { |
| ... | ... | @@ -30893,22 +30983,23 @@ fn coerceTupleToStruct( |
| 30893 | 30983 | anon_struct_type.names.get(ip)[field_i] |
| 30894 | 30984 | else |
| 30895 | 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 | 30987 | else => unreachable, |
| 30898 | 30988 | }; |
| 30899 | 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 | 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 | 30993 | field_refs[field_index] = coerced; |
| 30904 | if (field.is_comptime) { | |
| 30994 | if (struct_type.fieldIsComptime(ip, field_index)) { | |
| 30905 | 30995 | const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse { |
| 30906 | 30996 | return sema.failWithNeededComptime(block, field_src, .{ |
| 30907 | 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 | 31003 | return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i); |
| 30913 | 31004 | } |
| 30914 | 31005 | } |
| ... | ... | @@ -30928,10 +31019,10 @@ fn coerceTupleToStruct( |
| 30928 | 31019 | for (field_refs, 0..) |*field_ref, i| { |
| 30929 | 31020 | if (field_ref.* != .none) continue; |
| 30930 | 31021 | |
| 30931 | const field_name = fields.keys()[i]; | |
| 30932 | const field = fields.values()[i]; | |
| 31022 | const field_name = struct_type.field_names.get(ip)[i]; | |
| 31023 | const field_default_val = struct_type.fieldInit(ip, i); | |
| 30933 | 31024 | const field_src = inst_src; // TODO better source location |
| 30934 | if (field.default_val == .none) { | |
| 31025 | if (field_default_val == .none) { | |
| 30935 | 31026 | const template = "missing struct field: {}"; |
| 30936 | 31027 | const args = .{field_name.fmt(ip)}; |
| 30937 | 31028 | if (root_msg) |msg| { |
| ... | ... | @@ -30942,9 +31033,9 @@ fn coerceTupleToStruct( |
| 30942 | 31033 | continue; |
| 30943 | 31034 | } |
| 30944 | 31035 | if (runtime_src == null) { |
| 30945 | field_vals[i] = field.default_val; | |
| 31036 | field_vals[i] = field_default_val; | |
| 30946 | 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 | 31071 | const ip = &mod.intern_pool; |
| 30981 | 31072 | const dest_field_count = switch (ip.indexToKey(tuple_ty.toIntern())) { |
| 30982 | 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| | |
| 30984 | struct_obj.fields.count() | |
| 30985 | else | |
| 30986 | 0, | |
| 31074 | .struct_type => |struct_type| struct_type.field_types.len, | |
| 30987 | 31075 | else => unreachable, |
| 30988 | 31076 | }; |
| 30989 | 31077 | const field_vals = try sema.arena.alloc(InternPool.Index, dest_field_count); |
| ... | ... | @@ -30993,10 +31081,7 @@ fn coerceTupleToTuple( |
| 30993 | 31081 | const inst_ty = sema.typeOf(inst); |
| 30994 | 31082 | const src_field_count = switch (ip.indexToKey(inst_ty.toIntern())) { |
| 30995 | 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| | |
| 30997 | struct_obj.fields.count() | |
| 30998 | else | |
| 30999 | 0, | |
| 31084 | .struct_type => |struct_type| struct_type.field_types.len, | |
| 31000 | 31085 | else => unreachable, |
| 31001 | 31086 | }; |
| 31002 | 31087 | if (src_field_count > dest_field_count) return error.NotCoercible; |
| ... | ... | @@ -31011,7 +31096,7 @@ fn coerceTupleToTuple( |
| 31011 | 31096 | anon_struct_type.names.get(ip)[field_i] |
| 31012 | 31097 | else |
| 31013 | 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 | 31100 | else => unreachable, |
| 31016 | 31101 | }; |
| 31017 | 31102 | |
| ... | ... | @@ -31019,20 +31104,20 @@ fn coerceTupleToTuple( |
| 31019 | 31104 | return sema.fail(block, field_src, "cannot assign to 'len' field of tuple", .{}); |
| 31020 | 31105 | |
| 31021 | 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(), | |
| 31023 | .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.values()[field_index_usize].ty, | |
| 31107 | .anon_struct_type => |anon_struct_type| anon_struct_type.types.get(ip)[field_index_usize], | |
| 31108 | .struct_type => |struct_type| struct_type.field_types.get(ip)[field_index_usize], | |
| 31024 | 31109 | else => unreachable, |
| 31025 | 31110 | }; |
| 31026 | 31111 | const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) { |
| 31027 | 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 | 31114 | else => unreachable, |
| 31030 | 31115 | }; |
| 31031 | 31116 | |
| 31032 | 31117 | const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_src); |
| 31033 | 31118 | |
| 31034 | 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 | 31121 | field_refs[field_index] = coerced; |
| 31037 | 31122 | if (default_val != .none) { |
| 31038 | 31123 | const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse { |
| ... | ... | @@ -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 | 31130 | return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i); |
| 31046 | 31131 | } |
| 31047 | 31132 | } |
| ... | ... | @@ -31058,18 +31143,19 @@ fn coerceTupleToTuple( |
| 31058 | 31143 | var root_msg: ?*Module.ErrorMsg = null; |
| 31059 | 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 | 31148 | if (field_ref.* != .none) continue; |
| 31063 | 31149 | |
| 31064 | 31150 | const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) { |
| 31065 | 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 | 31153 | else => unreachable, |
| 31068 | 31154 | }; |
| 31069 | 31155 | |
| 31070 | 31156 | const field_src = inst_src; // TODO better source location |
| 31071 | 31157 | if (default_val == .none) { |
| 31072 | if (tuple_ty.isTuple(mod)) { | |
| 31158 | const field_name = tuple_ty.structFieldName(i, mod).unwrap() orelse { | |
| 31073 | 31159 | const template = "missing tuple field: {d}"; |
| 31074 | 31160 | if (root_msg) |msg| { |
| 31075 | 31161 | try sema.errNote(block, field_src, msg, template, .{i}); |
| ... | ... | @@ -31077,9 +31163,9 @@ fn coerceTupleToTuple( |
| 31077 | 31163 | root_msg = try sema.errMsg(block, field_src, template, .{i}); |
| 31078 | 31164 | } |
| 31079 | 31165 | continue; |
| 31080 | } | |
| 31166 | }; | |
| 31081 | 31167 | const template = "missing struct field: {}"; |
| 31082 | const args = .{tuple_ty.structFieldName(i, mod).fmt(ip)}; | |
| 31168 | const args = .{field_name.fmt(ip)}; | |
| 31083 | 31169 | if (root_msg) |msg| { |
| 31084 | 31170 | try sema.errNote(block, field_src, msg, template, args); |
| 31085 | 31171 | } else { |
| ... | ... | @@ -31229,7 +31315,7 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: Decl.Index, analyze_fn_body: boo |
| 31229 | 31315 | |
| 31230 | 31316 | const decl = mod.declPtr(decl_index); |
| 31231 | 31317 | const decl_tv = try decl.typedValue(); |
| 31232 | const ptr_ty = try mod.ptrType(.{ | |
| 31318 | const ptr_ty = try sema.ptrType(.{ | |
| 31233 | 31319 | .child = decl_tv.ty.toIntern(), |
| 31234 | 31320 | .flags = .{ |
| 31235 | 31321 | .alignment = decl.alignment, |
| ... | ... | @@ -31283,14 +31369,14 @@ fn analyzeRef( |
| 31283 | 31369 | |
| 31284 | 31370 | try sema.requireRuntimeBlock(block, src, null); |
| 31285 | 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 | 31373 | .child = operand_ty.toIntern(), |
| 31288 | 31374 | .flags = .{ |
| 31289 | 31375 | .is_const = true, |
| 31290 | 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 | 31380 | .child = operand_ty.toIntern(), |
| 31295 | 31381 | .flags = .{ .address_space = address_space }, |
| 31296 | 31382 | }); |
| ... | ... | @@ -31662,7 +31748,7 @@ fn analyzeSlice( |
| 31662 | 31748 | assert(manyptr_ty_key.flags.size == .One); |
| 31663 | 31749 | manyptr_ty_key.child = elem_ty.toIntern(); |
| 31664 | 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 | 31752 | } else ptr_or_slice; |
| 31667 | 31753 | |
| 31668 | 31754 | const start = try sema.coerce(block, Type.usize, uncasted_start, start_src); |
| ... | ... | @@ -31885,7 +31971,7 @@ fn analyzeSlice( |
| 31885 | 31971 | if (opt_new_len_val) |new_len_val| { |
| 31886 | 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 | 31975 | .child = (try mod.arrayType(.{ |
| 31890 | 31976 | .len = new_len_int, |
| 31891 | 31977 | .sentinel = if (sentinel) |s| s.toIntern() else .none, |
| ... | ... | @@ -31946,7 +32032,7 @@ fn analyzeSlice( |
| 31946 | 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 | 32036 | .child = elem_ty.toIntern(), |
| 31951 | 32037 | .sentinel = if (sentinel) |s| s.toIntern() else .none, |
| 31952 | 32038 | .flags = .{ |
| ... | ... | @@ -33181,12 +33267,17 @@ fn resolvePeerTypesInner( |
| 33181 | 33267 | } |
| 33182 | 33268 | |
| 33183 | 33269 | // Note that the align can be always non-zero; Module.ptrType will canonicalize it |
| 33184 | ptr_info.flags.alignment = Alignment.fromByteUnits(@min( | |
| 33185 | ptr_info.flags.alignment.toByteUnitsOptional() orelse | |
| 33270 | ptr_info.flags.alignment = InternPool.Alignment.min( | |
| 33271 | if (ptr_info.flags.alignment != .none) | |
| 33272 | ptr_info.flags.alignment | |
| 33273 | else | |
| 33186 | 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 | 33279 | peer_info.child.toType().abiAlignment(mod), |
| 33189 | )); | |
| 33280 | ); | |
| 33190 | 33281 | if (ptr_info.flags.address_space != peer_info.flags.address_space) { |
| 33191 | 33282 | return .{ .conflict = .{ |
| 33192 | 33283 | .peer_idx_a = first_idx, |
| ... | ... | @@ -33208,7 +33299,7 @@ fn resolvePeerTypesInner( |
| 33208 | 33299 | |
| 33209 | 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 | 33305 | .ptr => { |
| ... | ... | @@ -33260,12 +33351,17 @@ fn resolvePeerTypesInner( |
| 33260 | 33351 | } }; |
| 33261 | 33352 | |
| 33262 | 33353 | // Note that the align can be always non-zero; Type.ptr will canonicalize it |
| 33263 | ptr_info.flags.alignment = Alignment.fromByteUnits(@min( | |
| 33264 | ptr_info.flags.alignment.toByteUnitsOptional() orelse | |
| 33265 | ptr_info.child.toType().abiAlignment(mod), | |
| 33266 | peer_info.flags.alignment.toByteUnitsOptional() orelse | |
| 33267 | peer_info.child.toType().abiAlignment(mod), | |
| 33268 | )); | |
| 33354 | ptr_info.flags.alignment = Alignment.min( | |
| 33355 | if (ptr_info.flags.alignment != .none) | |
| 33356 | ptr_info.flags.alignment | |
| 33357 | else | |
| 33358 | try sema.typeAbiAlignment(ptr_info.child.toType()), | |
| 33359 | ||
| 33360 | if (peer_info.flags.alignment != .none) | |
| 33361 | peer_info.flags.alignment | |
| 33362 | else | |
| 33363 | try sema.typeAbiAlignment(peer_info.child.toType()), | |
| 33364 | ); | |
| 33269 | 33365 | |
| 33270 | 33366 | if (ptr_info.flags.address_space != peer_info.flags.address_space) { |
| 33271 | 33367 | return generic_err; |
| ... | ... | @@ -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 | 33615 | .func => { |
| ... | ... | @@ -33802,8 +33898,9 @@ fn resolvePeerTypesInner( |
| 33802 | 33898 | } |
| 33803 | 33899 | |
| 33804 | 33900 | if (!is_tuple) { |
| 33805 | for (field_names, 0..) |expected, field_idx| { | |
| 33806 | const actual = ty.structFieldName(field_idx, mod); | |
| 33901 | for (field_names, 0..) |expected, field_index_usize| { | |
| 33902 | const field_index: u32 = @intCast(field_index_usize); | |
| 33903 | const actual = ty.structFieldName(field_index, mod).unwrap().?; | |
| 33807 | 33904 | if (actual == expected) continue; |
| 33808 | 33905 | return .{ .conflict = .{ |
| 33809 | 33906 | .peer_idx_a = first_idx, |
| ... | ... | @@ -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 | 34347 | fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { |
| 34194 | 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 | 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; | |
| 34216 | for (struct_obj.fields.values(), 0..) |field, i| { | |
| 34217 | sema.resolveTypeLayout(field.ty) catch |err| switch (err) { | |
| 34218 | error.AnalysisFail => { | |
| 34219 | const msg = sema.err orelse return err; | |
| 34220 | try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{}); | |
| 34221 | return err; | |
| 34222 | }, | |
| 34223 | else => return err, | |
| 34224 | }; | |
| 34225 | } | |
| 34357 | if (struct_type.layout == .Packed) { | |
| 34358 | try semaBackingIntType(mod, struct_type); | |
| 34359 | return; | |
| 34360 | } | |
| 34226 | 34361 | |
| 34227 | if (struct_obj.layout == .Packed) { | |
| 34228 | try semaBackingIntType(mod, struct_obj); | |
| 34229 | } | |
| 34362 | if (struct_type.setLayoutWip(ip)) { | |
| 34363 | const msg = try Module.ErrorMsg.create( | |
| 34364 | sema.gpa, | |
| 34365 | mod.declPtr(struct_type.decl.unwrap().?).srcLoc(mod), | |
| 34366 | "struct '{}' depends on itself", | |
| 34367 | .{ty.fmt(mod)}, | |
| 34368 | ); | |
| 34369 | return sema.failWithOwnedErrorMsg(null, msg); | |
| 34370 | } | |
| 34371 | defer struct_type.clearLayoutWip(ip); | |
| 34230 | 34372 | |
| 34231 | struct_obj.status = .have_layout; | |
| 34232 | _ = try sema.typeRequiresComptime(ty); | |
| 34373 | const aligns = try sema.arena.alloc(Alignment, struct_type.field_types.len); | |
| 34374 | const sizes = try sema.arena.alloc(u64, struct_type.field_types.len); | |
| 34233 | 34375 | |
| 34234 | if (struct_obj.assumed_runtime_bits and !(try sema.typeHasRuntimeBits(ty))) { | |
| 34235 | const msg = try Module.ErrorMsg.create( | |
| 34236 | sema.gpa, | |
| 34237 | struct_obj.srcLoc(mod), | |
| 34238 | "struct layout depends on it having runtime bits", | |
| 34239 | .{}, | |
| 34240 | ); | |
| 34241 | return sema.failWithOwnedErrorMsg(null, msg); | |
| 34376 | var big_align: Alignment = .@"1"; | |
| 34377 | ||
| 34378 | for (aligns, sizes, 0..) |*field_align, *field_size, i| { | |
| 34379 | const field_ty = struct_type.field_types.get(ip)[i].toType(); | |
| 34380 | if (struct_type.fieldIsComptime(ip, i) or try sema.typeRequiresComptime(field_ty)) { | |
| 34381 | struct_type.offsets.get(ip)[i] = 0; | |
| 34382 | field_size.* = 0; | |
| 34383 | field_align.* = .none; | |
| 34384 | continue; | |
| 34242 | 34385 | } |
| 34243 | 34386 | |
| 34244 | if (struct_obj.layout == .Auto and !struct_obj.is_tuple and | |
| 34245 | mod.backendSupportsFeature(.field_reordering)) | |
| 34246 | { | |
| 34247 | const optimized_order = try mod.tmp_hack_arena.allocator().alloc(u32, struct_obj.fields.count()); | |
| 34387 | field_size.* = sema.typeAbiSize(field_ty) catch |err| switch (err) { | |
| 34388 | error.AnalysisFail => { | |
| 34389 | const msg = sema.err orelse return err; | |
| 34390 | try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{}); | |
| 34391 | return err; | |
| 34392 | }, | |
| 34393 | else => return err, | |
| 34394 | }; | |
| 34395 | field_align.* = try sema.structFieldAlignment( | |
| 34396 | struct_type.fieldAlign(ip, i), | |
| 34397 | field_ty, | |
| 34398 | struct_type.layout, | |
| 34399 | ); | |
| 34400 | big_align = big_align.maxStrict(field_align.*); | |
| 34401 | } | |
| 34248 | 34402 | |
| 34249 | for (struct_obj.fields.values(), 0..) |field, i| { | |
| 34250 | optimized_order[i] = if (try sema.typeHasRuntimeBits(field.ty)) | |
| 34251 | @intCast(i) | |
| 34252 | else | |
| 34253 | Module.Struct.omitted_field; | |
| 34403 | if (struct_type.flagsPtr(ip).assumed_runtime_bits and !(try sema.typeHasRuntimeBits(ty))) { | |
| 34404 | const msg = try Module.ErrorMsg.create( | |
| 34405 | sema.gpa, | |
| 34406 | mod.declPtr(struct_type.decl.unwrap().?).srcLoc(mod), | |
| 34407 | "struct layout depends on it having runtime bits", | |
| 34408 | .{}, | |
| 34409 | ); | |
| 34410 | return sema.failWithOwnedErrorMsg(null, msg); | |
| 34411 | } | |
| 34412 | ||
| 34413 | if (struct_type.hasReorderedFields()) { | |
| 34414 | const runtime_order = struct_type.runtime_order.get(ip); | |
| 34415 | ||
| 34416 | for (runtime_order, 0..) |*ro, i| { | |
| 34417 | const field_ty = struct_type.field_types.get(ip)[i].toType(); | |
| 34418 | if (struct_type.fieldIsComptime(ip, i) or try sema.typeRequiresComptime(field_ty)) { | |
| 34419 | ro.* = .omitted; | |
| 34420 | } else { | |
| 34421 | ro.* = @enumFromInt(i); | |
| 34254 | 34422 | } |
| 34423 | } | |
| 34424 | ||
| 34425 | const RuntimeOrder = InternPool.Key.StructType.RuntimeOrder; | |
| 34255 | 34426 | |
| 34256 | const AlignSortContext = struct { | |
| 34257 | struct_obj: *Module.Struct, | |
| 34258 | sema: *Sema, | |
| 34427 | const AlignSortContext = struct { | |
| 34428 | aligns: []const Alignment, | |
| 34259 | 34429 | |
| 34260 | fn lessThan(ctx: @This(), a: u32, b: u32) bool { | |
| 34261 | const m = ctx.sema.mod; | |
| 34262 | if (a == Module.Struct.omitted_field) return false; | |
| 34263 | if (b == Module.Struct.omitted_field) return true; | |
| 34264 | return ctx.struct_obj.fields.values()[a].ty.abiAlignment(m) > | |
| 34265 | ctx.struct_obj.fields.values()[b].ty.abiAlignment(m); | |
| 34430 | fn lessThan(ctx: @This(), a: RuntimeOrder, b: RuntimeOrder) bool { | |
| 34431 | if (a == .omitted) return false; | |
| 34432 | if (b == .omitted) return true; | |
| 34433 | const a_align = ctx.aligns[@intFromEnum(a)]; | |
| 34434 | const b_align = ctx.aligns[@intFromEnum(b)]; | |
| 34435 | return a_align.compare(.gt, b_align); | |
| 34436 | } | |
| 34437 | }; | |
| 34438 | if (struct_type.isTuple(ip) or !mod.backendSupportsFeature(.field_reordering)) { | |
| 34439 | // TODO: don't handle tuples differently. This logic exists only because it | |
| 34440 | // uncovers latent bugs if removed. Fix the latent bugs and remove this logic! | |
| 34441 | // Likewise, implement field reordering support in all the backends! | |
| 34442 | // This logic does not reorder fields; it only moves the omitted ones to the end | |
| 34443 | // so that logic elsewhere does not need to special-case tuples. | |
| 34444 | var i: usize = 0; | |
| 34445 | var off: usize = 0; | |
| 34446 | while (i + off < runtime_order.len) { | |
| 34447 | if (runtime_order[i + off] == .omitted) { | |
| 34448 | off += 1; | |
| 34449 | continue; | |
| 34266 | 34450 | } |
| 34267 | }; | |
| 34268 | mem.sort(u32, optimized_order, AlignSortContext{ | |
| 34269 | .struct_obj = struct_obj, | |
| 34270 | .sema = sema, | |
| 34451 | runtime_order[i] = runtime_order[i + off]; | |
| 34452 | i += 1; | |
| 34453 | } | |
| 34454 | @memset(runtime_order[i..], .omitted); | |
| 34455 | } else { | |
| 34456 | mem.sortUnstable(RuntimeOrder, runtime_order, AlignSortContext{ | |
| 34457 | .aligns = aligns, | |
| 34271 | 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 | 34478 | const gpa = mod.gpa; |
| 34479 | const ip = &mod.intern_pool; | |
| 34280 | 34480 | |
| 34281 | var fields_bit_sum: u64 = 0; | |
| 34282 | for (struct_obj.fields.values()) |field| { | |
| 34283 | fields_bit_sum += field.ty.bitSize(mod); | |
| 34284 | } | |
| 34285 | ||
| 34286 | const decl_index = struct_obj.owner_decl; | |
| 34481 | const decl_index = struct_type.decl.unwrap().?; | |
| 34287 | 34482 | const decl = mod.declPtr(decl_index); |
| 34288 | 34483 | |
| 34289 | const zir = mod.namespacePtr(struct_obj.namespace).file_scope.zir; | |
| 34290 | const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended; | |
| 34484 | const zir = mod.namespacePtr(struct_type.namespace.unwrap().?).file_scope.zir; | |
| 34485 | ||
| 34486 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); | |
| 34487 | defer analysis_arena.deinit(); | |
| 34488 | ||
| 34489 | var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa); | |
| 34490 | defer comptime_mutable_decls.deinit(); | |
| 34491 | ||
| 34492 | var sema: Sema = .{ | |
| 34493 | .mod = mod, | |
| 34494 | .gpa = gpa, | |
| 34495 | .arena = analysis_arena.allocator(), | |
| 34496 | .code = zir, | |
| 34497 | .owner_decl = decl, | |
| 34498 | .owner_decl_index = decl_index, | |
| 34499 | .func_index = .none, | |
| 34500 | .func_is_naked = false, | |
| 34501 | .fn_ret_ty = Type.void, | |
| 34502 | .fn_ret_ty_ies = null, | |
| 34503 | .owner_func_index = .none, | |
| 34504 | .comptime_mutable_decls = &comptime_mutable_decls, | |
| 34505 | }; | |
| 34506 | defer sema.deinit(); | |
| 34507 | ||
| 34508 | var block: Block = .{ | |
| 34509 | .parent = null, | |
| 34510 | .sema = &sema, | |
| 34511 | .src_decl = decl_index, | |
| 34512 | .namespace = struct_type.namespace.unwrap() orelse decl.src_namespace, | |
| 34513 | .wip_capture_scope = try mod.createCaptureScope(decl.src_scope), | |
| 34514 | .instructions = .{}, | |
| 34515 | .inlining = null, | |
| 34516 | .is_comptime = true, | |
| 34517 | }; | |
| 34518 | defer assert(block.instructions.items.len == 0); | |
| 34519 | ||
| 34520 | const fields_bit_sum = blk: { | |
| 34521 | var accumulator: u64 = 0; | |
| 34522 | for (0..struct_type.field_types.len) |i| { | |
| 34523 | const field_ty = struct_type.field_types.get(ip)[i].toType(); | |
| 34524 | accumulator += try field_ty.bitSizeAdvanced(mod, &sema); | |
| 34525 | } | |
| 34526 | break :blk accumulator; | |
| 34527 | }; | |
| 34528 | ||
| 34529 | const extended = zir.instructions.items(.data)[struct_type.zir_index].extended; | |
| 34291 | 34530 | assert(extended.opcode == .struct_decl); |
| 34292 | 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 | 34539 | const backing_int_body_len = zir.extra[extra_index]; |
| 34301 | 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 | 34542 | const backing_int_src: LazySrcLoc = .{ .node_offset_container_tag = 0 }; |
| 34338 | 34543 | const backing_int_ty = blk: { |
| 34339 | 34544 | if (backing_int_body_len == 0) { |
| ... | ... | @@ -34341,48 +34546,24 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi |
| 34341 | 34546 | break :blk try sema.resolveType(&block, backing_int_src, backing_int_ref); |
| 34342 | 34547 | } else { |
| 34343 | 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 | 34550 | break :blk try sema.analyzeAsType(&block, backing_int_src, ty_ref); |
| 34346 | 34551 | } |
| 34347 | 34552 | }; |
| 34348 | 34553 | |
| 34349 | 34554 | try sema.checkBackingIntType(&block, backing_int_src, backing_int_ty, fields_bit_sum); |
| 34350 | struct_obj.backing_int_ty = backing_int_ty; | |
| 34351 | for (comptime_mutable_decls.items) |ct_decl_index| { | |
| 34352 | const ct_decl = mod.declPtr(ct_decl_index); | |
| 34353 | _ = try ct_decl.internValue(mod); | |
| 34354 | } | |
| 34555 | struct_type.backingIntType(ip).* = backing_int_ty.toIntern(); | |
| 34355 | 34556 | } else { |
| 34356 | 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 | 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 | 34713 | try sema.resolveStructLayout(ty); |
| 34533 | 34714 | |
| 34534 | 34715 | const mod = sema.mod; |
| 34535 | try sema.resolveTypeFields(ty); | |
| 34536 | const struct_obj = mod.typeToStruct(ty).?; | |
| 34716 | const ip = &mod.intern_pool; | |
| 34717 | const struct_type = mod.typeToStruct(ty).?; | |
| 34537 | 34718 | |
| 34538 | switch (struct_obj.status) { | |
| 34539 | .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, | |
| 34540 | .fully_resolved_wip, .fully_resolved => return, | |
| 34541 | } | |
| 34719 | if (struct_type.setFullyResolved(ip)) return; | |
| 34720 | errdefer struct_type.clearFullyResolved(ip); | |
| 34542 | 34721 | |
| 34543 | { | |
| 34544 | // After we have resolve struct layout we have to go over the fields again to | |
| 34545 | // make sure pointer fields get their child types resolved as well. | |
| 34546 | // See also similar code for unions. | |
| 34547 | const prev_status = struct_obj.status; | |
| 34548 | errdefer struct_obj.status = prev_status; | |
| 34722 | // After we have resolve struct layout we have to go over the fields again to | |
| 34723 | // make sure pointer fields get their child types resolved as well. | |
| 34724 | // See also similar code for unions. | |
| 34549 | 34725 | |
| 34550 | struct_obj.status = .fully_resolved_wip; | |
| 34551 | for (struct_obj.fields.values()) |field| { | |
| 34552 | try sema.resolveTypeFully(field.ty); | |
| 34553 | } | |
| 34554 | struct_obj.status = .fully_resolved; | |
| 34726 | for (0..struct_type.field_types.len) |i| { | |
| 34727 | const field_ty = struct_type.field_types.get(ip)[i].toType(); | |
| 34728 | try sema.resolveTypeFully(field_ty); | |
| 34555 | 34729 | } |
| 34556 | ||
| 34557 | // And let's not forget comptime-only status. | |
| 34558 | _ = try sema.typeRequiresComptime(ty); | |
| 34559 | 34730 | } |
| 34560 | 34731 | |
| 34561 | 34732 | fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void { |
| ... | ... | @@ -34591,8 +34762,10 @@ fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void { |
| 34591 | 34762 | |
| 34592 | 34763 | pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void { |
| 34593 | 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 | 34769 | .var_args_param_type => unreachable, |
| 34597 | 34770 | |
| 34598 | 34771 | .none => unreachable, |
| ... | ... | @@ -34673,20 +34846,15 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void { |
| 34673 | 34846 | .empty_struct => unreachable, |
| 34674 | 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 | 34850 | .type_struct, |
| 34678 | 34851 | .type_struct_ns, |
| 34679 | .type_union, | |
| 34680 | .simple_type, | |
| 34681 | => switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 34682 | .struct_type => |struct_type| { | |
| 34683 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return; | |
| 34684 | try sema.resolveTypeFieldsStruct(ty, struct_obj); | |
| 34685 | }, | |
| 34686 | .union_type => |union_type| try sema.resolveTypeFieldsUnion(ty, union_type), | |
| 34687 | .simple_type => |simple_type| try sema.resolveSimpleType(simple_type), | |
| 34688 | else => unreachable, | |
| 34689 | }, | |
| 34852 | .type_struct_packed, | |
| 34853 | .type_struct_packed_inits, | |
| 34854 | => try sema.resolveTypeFieldsStruct(ty_ip, ip.indexToKey(ty_ip).struct_type), | |
| 34855 | ||
| 34856 | .type_union => try sema.resolveTypeFieldsUnion(ty_ip.toType(), ip.indexToKey(ty_ip).union_type), | |
| 34857 | .simple_type => try sema.resolveSimpleType(ip.indexToKey(ty_ip).simple_type), | |
| 34690 | 34858 | else => {}, |
| 34691 | 34859 | }, |
| 34692 | 34860 | } |
| ... | ... | @@ -34716,43 +34884,41 @@ fn resolveSimpleType(sema: *Sema, simple_type: InternPool.SimpleType) CompileErr |
| 34716 | 34884 | |
| 34717 | 34885 | fn resolveTypeFieldsStruct( |
| 34718 | 34886 | sema: *Sema, |
| 34719 | ty: Type, | |
| 34720 | struct_obj: *Module.Struct, | |
| 34887 | ty: InternPool.Index, | |
| 34888 | struct_type: InternPool.Key.StructType, | |
| 34721 | 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 | 34896 | .file_failure, |
| 34724 | 34897 | .dependency_failure, |
| 34725 | 34898 | .sema_failure, |
| 34726 | 34899 | .sema_failure_retryable, |
| 34727 | 34900 | => { |
| 34728 | 34901 | sema.owner_decl.analysis = .dependency_failure; |
| 34729 | sema.owner_decl.generation = sema.mod.generation; | |
| 34902 | sema.owner_decl.generation = mod.generation; | |
| 34730 | 34903 | return error.AnalysisFail; |
| 34731 | 34904 | }, |
| 34732 | 34905 | else => {}, |
| 34733 | 34906 | } |
| 34734 | switch (struct_obj.status) { | |
| 34735 | .none => {}, | |
| 34736 | .field_types_wip => { | |
| 34737 | const msg = try Module.ErrorMsg.create( | |
| 34738 | sema.gpa, | |
| 34739 | struct_obj.srcLoc(sema.mod), | |
| 34740 | "struct '{}' depends on itself", | |
| 34741 | .{ty.fmt(sema.mod)}, | |
| 34742 | ); | |
| 34743 | return sema.failWithOwnedErrorMsg(null, msg); | |
| 34744 | }, | |
| 34745 | .have_field_types, | |
| 34746 | .have_layout, | |
| 34747 | .layout_wip, | |
| 34748 | .fully_resolved_wip, | |
| 34749 | .fully_resolved, | |
| 34750 | => return, | |
| 34907 | ||
| 34908 | if (struct_type.haveFieldTypes(ip)) return; | |
| 34909 | ||
| 34910 | if (struct_type.setTypesWip(ip)) { | |
| 34911 | const msg = try Module.ErrorMsg.create( | |
| 34912 | sema.gpa, | |
| 34913 | mod.declPtr(owner_decl).srcLoc(mod), | |
| 34914 | "struct '{}' depends on itself", | |
| 34915 | .{ty.toType().fmt(mod)}, | |
| 34916 | ); | |
| 34917 | return sema.failWithOwnedErrorMsg(null, msg); | |
| 34751 | 34918 | } |
| 34919 | defer struct_type.clearTypesWip(ip); | |
| 34752 | 34920 | |
| 34753 | struct_obj.status = .field_types_wip; | |
| 34754 | errdefer struct_obj.status = .none; | |
| 34755 | try semaStructFields(sema.mod, struct_obj); | |
| 34921 | try semaStructFields(mod, sema.arena, struct_type); | |
| 34756 | 34922 | } |
| 34757 | 34923 | |
| 34758 | 34924 | fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Key.UnionType) CompileError!void { |
| ... | ... | @@ -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 | 35110 | const gpa = mod.gpa; |
| 34941 | 35111 | const ip = &mod.intern_pool; |
| 34942 | const decl_index = struct_obj.owner_decl; | |
| 34943 | const zir = mod.namespacePtr(struct_obj.namespace).file_scope.zir; | |
| 34944 | const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended; | |
| 35112 | const decl_index = struct_type.decl.unwrap() orelse return; | |
| 35113 | const decl = mod.declPtr(decl_index); | |
| 35114 | const namespace_index = struct_type.namespace.unwrap() orelse decl.src_namespace; | |
| 35115 | const zir = mod.namespacePtr(namespace_index).file_scope.zir; | |
| 35116 | const zir_index = struct_type.zir_index; | |
| 35117 | const extended = zir.instructions.items(.data)[zir_index].extended; | |
| 34945 | 35118 | assert(extended.opcode == .struct_decl); |
| 34946 | 35119 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); |
| 34947 | 35120 | var extra_index: usize = extended.operand; |
| ... | ... | @@ -34977,18 +35150,16 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 34977 | 35150 | while (decls_it.next()) |_| {} |
| 34978 | 35151 | extra_index = decls_it.extra_index; |
| 34979 | 35152 | |
| 34980 | if (fields_len == 0) { | |
| 34981 | if (struct_obj.layout == .Packed) { | |
| 34982 | try semaBackingIntType(mod, struct_obj); | |
| 34983 | } | |
| 34984 | struct_obj.status = .have_layout; | |
| 34985 | return; | |
| 34986 | } | |
| 34987 | ||
| 34988 | const decl = mod.declPtr(decl_index); | |
| 34989 | ||
| 34990 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); | |
| 34991 | defer analysis_arena.deinit(); | |
| 35153 | if (fields_len == 0) switch (struct_type.layout) { | |
| 35154 | .Packed => { | |
| 35155 | try semaBackingIntType(mod, struct_type); | |
| 35156 | return; | |
| 35157 | }, | |
| 35158 | .Auto, .Extern => { | |
| 35159 | struct_type.flagsPtr(ip).layout_resolved = true; | |
| 35160 | return; | |
| 35161 | }, | |
| 35162 | }; | |
| 34992 | 35163 | |
| 34993 | 35164 | var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa); |
| 34994 | 35165 | defer comptime_mutable_decls.deinit(); |
| ... | ... | @@ -34996,7 +35167,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 34996 | 35167 | var sema: Sema = .{ |
| 34997 | 35168 | .mod = mod, |
| 34998 | 35169 | .gpa = gpa, |
| 34999 | .arena = analysis_arena.allocator(), | |
| 35170 | .arena = arena, | |
| 35000 | 35171 | .code = zir, |
| 35001 | 35172 | .owner_decl = decl, |
| 35002 | 35173 | .owner_decl_index = decl_index, |
| ... | ... | @@ -35013,7 +35184,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 35013 | 35184 | .parent = null, |
| 35014 | 35185 | .sema = &sema, |
| 35015 | 35186 | .src_decl = decl_index, |
| 35016 | .namespace = struct_obj.namespace, | |
| 35187 | .namespace = namespace_index, | |
| 35017 | 35188 | .wip_capture_scope = try mod.createCaptureScope(decl.src_scope), |
| 35018 | 35189 | .instructions = .{}, |
| 35019 | 35190 | .inlining = null, |
| ... | ... | @@ -35021,9 +35192,6 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 35021 | 35192 | }; |
| 35022 | 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 | 35195 | const Field = struct { |
| 35028 | 35196 | type_body_len: u32 = 0, |
| 35029 | 35197 | align_body_len: u32 = 0, |
| ... | ... | @@ -35031,7 +35199,9 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 35031 | 35199 | type_ref: Zir.Inst.Ref = .none, |
| 35032 | 35200 | }; |
| 35033 | 35201 | const fields = try sema.arena.alloc(Field, fields_len); |
| 35202 | ||
| 35034 | 35203 | var any_inits = false; |
| 35204 | var any_aligned = false; | |
| 35035 | 35205 | |
| 35036 | 35206 | { |
| 35037 | 35207 | const bits_per_field = 4; |
| ... | ... | @@ -35056,9 +35226,11 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 35056 | 35226 | const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0; |
| 35057 | 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 | 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 | 35234 | extra_index += 1; |
| 35063 | 35235 | } |
| 35064 | 35236 | extra_index += 1; // doc_comment |
| ... | ... | @@ -35073,37 +35245,27 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 35073 | 35245 | extra_index += 1; |
| 35074 | 35246 | |
| 35075 | 35247 | // This string needs to outlive the ZIR code. |
| 35076 | const field_name = try ip.getOrPutString(gpa, if (field_name_zir) |s| | |
| 35077 | s | |
| 35078 | else | |
| 35079 | try std.fmt.allocPrint(sema.arena, "{d}", .{field_i})); | |
| 35080 | ||
| 35081 | const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name); | |
| 35082 | if (gop.found_existing) { | |
| 35083 | const msg = msg: { | |
| 35084 | const field_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ .index = field_i }).lazy; | |
| 35085 | const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{}'", .{field_name.fmt(ip)}); | |
| 35086 | errdefer msg.destroy(gpa); | |
| 35248 | if (opt_field_name_zir) |field_name_zir| { | |
| 35249 | const field_name = try ip.getOrPutString(gpa, field_name_zir); | |
| 35250 | if (struct_type.addFieldName(ip, field_name)) |other_index| { | |
| 35251 | const msg = msg: { | |
| 35252 | const field_src = mod.fieldSrcLoc(decl_index, .{ .index = field_i }).lazy; | |
| 35253 | const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{}'", .{field_name.fmt(ip)}); | |
| 35254 | errdefer msg.destroy(gpa); | |
| 35087 | 35255 | |
| 35088 | const prev_field_index = struct_obj.fields.getIndex(field_name).?; | |
| 35089 | const prev_field_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ .index = prev_field_index }); | |
| 35090 | try mod.errNoteNonLazy(prev_field_src, msg, "other field here", .{}); | |
| 35091 | try sema.errNote(&block_scope, src, msg, "struct declared here", .{}); | |
| 35092 | break :msg msg; | |
| 35093 | }; | |
| 35094 | return sema.failWithOwnedErrorMsg(&block_scope, msg); | |
| 35256 | const prev_field_src = mod.fieldSrcLoc(decl_index, .{ .index = other_index }); | |
| 35257 | try mod.errNoteNonLazy(prev_field_src, msg, "other field here", .{}); | |
| 35258 | try sema.errNote(&block_scope, src, msg, "struct declared here", .{}); | |
| 35259 | break :msg msg; | |
| 35260 | }; | |
| 35261 | return sema.failWithOwnedErrorMsg(&block_scope, msg); | |
| 35262 | } | |
| 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 | 35265 | if (has_align) { |
| 35105 | 35266 | fields[field_i].align_body_len = zir.extra[extra_index]; |
| 35106 | 35267 | extra_index += 1; |
| 35268 | any_aligned = true; | |
| 35107 | 35269 | } |
| 35108 | 35270 | if (has_init) { |
| 35109 | 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 | 35284 | if (zir_field.type_ref != .none) { |
| 35123 | 35285 | break :ty sema.resolveType(&block_scope, .unneeded, zir_field.type_ref) catch |err| switch (err) { |
| 35124 | 35286 | error.NeededSourceLocation => { |
| 35125 | const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | |
| 35287 | const ty_src = mod.fieldSrcLoc(decl_index, .{ | |
| 35126 | 35288 | .index = field_i, |
| 35127 | 35289 | .range = .type, |
| 35128 | 35290 | }).lazy; |
| ... | ... | @@ -35135,10 +35297,10 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 35135 | 35297 | assert(zir_field.type_body_len != 0); |
| 35136 | 35298 | const body = zir.extra[extra_index..][0..zir_field.type_body_len]; |
| 35137 | 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 | 35301 | break :ty sema.analyzeAsType(&block_scope, .unneeded, ty_ref) catch |err| switch (err) { |
| 35140 | 35302 | error.NeededSourceLocation => { |
| 35141 | const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | |
| 35303 | const ty_src = mod.fieldSrcLoc(decl_index, .{ | |
| 35142 | 35304 | .index = field_i, |
| 35143 | 35305 | .range = .type, |
| 35144 | 35306 | }).lazy; |
| ... | ... | @@ -35152,12 +35314,11 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 35152 | 35314 | return error.GenericPoison; |
| 35153 | 35315 | } |
| 35154 | 35316 | |
| 35155 | const field = &struct_obj.fields.values()[field_i]; | |
| 35156 | field.ty = field_ty; | |
| 35317 | struct_type.field_types.get(ip)[field_i] = field_ty.toIntern(); | |
| 35157 | 35318 | |
| 35158 | 35319 | if (field_ty.zigTypeTag(mod) == .Opaque) { |
| 35159 | 35320 | const msg = msg: { |
| 35160 | const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | |
| 35321 | const ty_src = mod.fieldSrcLoc(decl_index, .{ | |
| 35161 | 35322 | .index = field_i, |
| 35162 | 35323 | .range = .type, |
| 35163 | 35324 | }).lazy; |
| ... | ... | @@ -35171,7 +35332,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 35171 | 35332 | } |
| 35172 | 35333 | if (field_ty.zigTypeTag(mod) == .NoReturn) { |
| 35173 | 35334 | const msg = msg: { |
| 35174 | const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | |
| 35335 | const ty_src = mod.fieldSrcLoc(decl_index, .{ | |
| 35175 | 35336 | .index = field_i, |
| 35176 | 35337 | .range = .type, |
| 35177 | 35338 | }).lazy; |
| ... | ... | @@ -35183,45 +35344,49 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 35183 | 35344 | }; |
| 35184 | 35345 | return sema.failWithOwnedErrorMsg(&block_scope, msg); |
| 35185 | 35346 | } |
| 35186 | if (struct_obj.layout == .Extern and !try sema.validateExternType(field.ty, .struct_field)) { | |
| 35187 | const msg = msg: { | |
| 35188 | const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | |
| 35189 | .index = field_i, | |
| 35190 | .range = .type, | |
| 35191 | }); | |
| 35192 | const msg = try sema.errMsg(&block_scope, ty_src.lazy, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(mod)}); | |
| 35193 | errdefer msg.destroy(sema.gpa); | |
| 35347 | switch (struct_type.layout) { | |
| 35348 | .Extern => if (!try sema.validateExternType(field_ty, .struct_field)) { | |
| 35349 | const msg = msg: { | |
| 35350 | const ty_src = mod.fieldSrcLoc(decl_index, .{ | |
| 35351 | .index = field_i, | |
| 35352 | .range = .type, | |
| 35353 | }); | |
| 35354 | const msg = try sema.errMsg(&block_scope, ty_src.lazy, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(mod)}); | |
| 35355 | errdefer msg.destroy(sema.gpa); | |
| 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); | |
| 35198 | break :msg msg; | |
| 35199 | }; | |
| 35200 | return sema.failWithOwnedErrorMsg(&block_scope, msg); | |
| 35201 | } else if (struct_obj.layout == .Packed and !(validatePackedType(field.ty, mod))) { | |
| 35202 | const msg = msg: { | |
| 35203 | const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | |
| 35204 | .index = field_i, | |
| 35205 | .range = .type, | |
| 35206 | }); | |
| 35207 | const msg = try sema.errMsg(&block_scope, ty_src.lazy, "packed structs cannot contain fields of type '{}'", .{field.ty.fmt(mod)}); | |
| 35208 | errdefer msg.destroy(sema.gpa); | |
| 35359 | try sema.addDeclaredHereNote(msg, field_ty); | |
| 35360 | break :msg msg; | |
| 35361 | }; | |
| 35362 | return sema.failWithOwnedErrorMsg(&block_scope, msg); | |
| 35363 | }, | |
| 35364 | .Packed => if (!validatePackedType(field_ty, mod)) { | |
| 35365 | const msg = msg: { | |
| 35366 | const ty_src = mod.fieldSrcLoc(decl_index, .{ | |
| 35367 | .index = field_i, | |
| 35368 | .range = .type, | |
| 35369 | }); | |
| 35370 | const msg = try sema.errMsg(&block_scope, ty_src.lazy, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(mod)}); | |
| 35371 | errdefer msg.destroy(sema.gpa); | |
| 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); | |
| 35213 | break :msg msg; | |
| 35214 | }; | |
| 35215 | return sema.failWithOwnedErrorMsg(&block_scope, msg); | |
| 35375 | try sema.addDeclaredHereNote(msg, field_ty); | |
| 35376 | break :msg msg; | |
| 35377 | }; | |
| 35378 | return sema.failWithOwnedErrorMsg(&block_scope, msg); | |
| 35379 | }, | |
| 35380 | else => {}, | |
| 35216 | 35381 | } |
| 35217 | 35382 | |
| 35218 | 35383 | if (zir_field.align_body_len > 0) { |
| 35219 | 35384 | const body = zir.extra[extra_index..][0..zir_field.align_body_len]; |
| 35220 | 35385 | extra_index += body.len; |
| 35221 | const align_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index); | |
| 35222 | field.abi_align = sema.analyzeAsAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) { | |
| 35386 | const align_ref = try sema.resolveBody(&block_scope, body, zir_index); | |
| 35387 | const field_align = sema.analyzeAsAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) { | |
| 35223 | 35388 | error.NeededSourceLocation => { |
| 35224 | const align_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | |
| 35389 | const align_src = mod.fieldSrcLoc(decl_index, .{ | |
| 35225 | 35390 | .index = field_i, |
| 35226 | 35391 | .range = .alignment, |
| 35227 | 35392 | }).lazy; |
| ... | ... | @@ -35230,36 +35395,38 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 35230 | 35395 | }, |
| 35231 | 35396 | else => |e| return e, |
| 35232 | 35397 | }; |
| 35398 | struct_type.field_aligns.get(ip)[field_i] = field_align; | |
| 35233 | 35399 | } |
| 35234 | 35400 | |
| 35235 | 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 | 35407 | if (any_inits) { |
| 35241 | 35408 | extra_index = bodies_index; |
| 35242 | 35409 | for (fields, 0..) |zir_field, field_i| { |
| 35410 | const field_ty = struct_type.field_types.get(ip)[field_i].toType(); | |
| 35243 | 35411 | extra_index += zir_field.type_body_len; |
| 35244 | 35412 | extra_index += zir_field.align_body_len; |
| 35245 | 35413 | if (zir_field.init_body_len > 0) { |
| 35246 | 35414 | const body = zir.extra[extra_index..][0..zir_field.init_body_len]; |
| 35247 | 35415 | extra_index += body.len; |
| 35248 | const init = try sema.resolveBody(&block_scope, body, struct_obj.zir_index); | |
| 35249 | const field = &struct_obj.fields.values()[field_i]; | |
| 35250 | const coerced = sema.coerce(&block_scope, field.ty, init, .unneeded) catch |err| switch (err) { | |
| 35416 | const init = try sema.resolveBody(&block_scope, body, zir_index); | |
| 35417 | const coerced = sema.coerce(&block_scope, field_ty, init, .unneeded) catch |err| switch (err) { | |
| 35251 | 35418 | error.NeededSourceLocation => { |
| 35252 | const init_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ | |
| 35419 | const init_src = mod.fieldSrcLoc(decl_index, .{ | |
| 35253 | 35420 | .index = field_i, |
| 35254 | 35421 | .range = .value, |
| 35255 | 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 | 35424 | unreachable; |
| 35258 | 35425 | }, |
| 35259 | 35426 | else => |e| return e, |
| 35260 | 35427 | }; |
| 35261 | 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 | 35430 | .index = field_i, |
| 35264 | 35431 | .range = .value, |
| 35265 | 35432 | }).lazy; |
| ... | ... | @@ -35267,7 +35434,8 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 35267 | 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 | 35443 | const ct_decl = mod.declPtr(ct_decl_index); |
| 35276 | 35444 | _ = try ct_decl.internValue(mod); |
| 35277 | 35445 | } |
| 35278 | ||
| 35279 | struct_obj.have_field_inits = true; | |
| 35280 | 35446 | } |
| 35281 | 35447 | |
| 35282 | 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 | 36226 | .type_struct, |
| 36061 | 36227 | .type_struct_ns, |
| 36062 | 36228 | .type_struct_anon, |
| 36229 | .type_struct_packed, | |
| 36230 | .type_struct_packed_inits, | |
| 36063 | 36231 | .type_tuple_anon, |
| 36064 | 36232 | .type_union, |
| 36065 | 36233 | => switch (ip.indexToKey(ty.toIntern())) { |
| ... | ... | @@ -36081,41 +36249,46 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { |
| 36081 | 36249 | |
| 36082 | 36250 | .struct_type => |struct_type| { |
| 36083 | 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 | 36255 | // therefore has one possible value. |
| 36108 | 36256 | return (try mod.intern(.{ .aggregate = .{ |
| 36109 | 36257 | .ty = ty.toIntern(), |
| 36110 | .storage = .{ .elems = field_vals }, | |
| 36258 | .storage = .{ .elems = &.{} }, | |
| 36111 | 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 | 36288 | // therefore has one possible value. |
| 36116 | 36289 | return (try mod.intern(.{ .aggregate = .{ |
| 36117 | 36290 | .ty = ty.toIntern(), |
| 36118 | .storage = .{ .elems = &.{} }, | |
| 36291 | .storage = .{ .elems = field_vals }, | |
| 36119 | 36292 | } })).toValue(); |
| 36120 | 36293 | }, |
| 36121 | 36294 | |
| ... | ... | @@ -36266,7 +36439,7 @@ fn analyzeComptimeAlloc( |
| 36266 | 36439 | // Needed to make an anon decl with type `var_type` (the `finish()` call below). |
| 36267 | 36440 | _ = try sema.typeHasOnePossibleValue(var_type); |
| 36268 | 36441 | |
| 36269 | const ptr_type = try mod.ptrType(.{ | |
| 36442 | const ptr_type = try sema.ptrType(.{ | |
| 36270 | 36443 | .child = var_type.toIntern(), |
| 36271 | 36444 | .flags = .{ |
| 36272 | 36445 | .alignment = alignment, |
| ... | ... | @@ -36574,25 +36747,36 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { |
| 36574 | 36747 | => true, |
| 36575 | 36748 | }, |
| 36576 | 36749 | .struct_type => |struct_type| { |
| 36577 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false; | |
| 36578 | switch (struct_obj.requires_comptime) { | |
| 36750 | if (struct_type.layout == .Packed) { | |
| 36751 | // packed structs cannot be comptime-only because they have a well-defined | |
| 36752 | // memory layout and every field has a well-defined bit pattern. | |
| 36753 | return false; | |
| 36754 | } | |
| 36755 | switch (struct_type.flagsPtr(ip).requires_comptime) { | |
| 36579 | 36756 | .no, .wip => return false, |
| 36580 | 36757 | .yes => return true, |
| 36581 | 36758 | .unknown => { |
| 36582 | if (struct_obj.status == .field_types_wip) | |
| 36759 | if (struct_type.flagsPtr(ip).field_types_wip) | |
| 36583 | 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; | |
| 36588 | for (struct_obj.fields.values()) |field| { | |
| 36589 | if (field.is_comptime) continue; | |
| 36590 | if (try sema.typeRequiresComptime(field.ty)) { | |
| 36591 | struct_obj.requires_comptime = .yes; | |
| 36766 | for (0..struct_type.field_types.len) |i_usize| { | |
| 36767 | const i: u32 = @intCast(i_usize); | |
| 36768 | if (struct_type.fieldIsComptime(ip, i)) continue; | |
| 36769 | const field_ty = struct_type.field_types.get(ip)[i]; | |
| 36770 | if (try sema.typeRequiresComptime(field_ty.toType())) { | |
| 36771 | // Note that this does not cause the layout to | |
| 36772 | // be considered resolved. Comptime-only types | |
| 36773 | // still maintain a layout of their | |
| 36774 | // runtime-known fields. | |
| 36775 | struct_type.flagsPtr(ip).requires_comptime = .yes; | |
| 36592 | 36776 | return true; |
| 36593 | 36777 | } |
| 36594 | 36778 | } |
| 36595 | struct_obj.requires_comptime = .no; | |
| 36779 | struct_type.flagsPtr(ip).requires_comptime = .no; | |
| 36596 | 36780 | return false; |
| 36597 | 36781 | }, |
| 36598 | 36782 | } |
| ... | ... | @@ -36673,40 +36857,41 @@ fn typeAbiSize(sema: *Sema, ty: Type) !u64 { |
| 36673 | 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 | 36861 | return (try ty.abiAlignmentAdvanced(sema.mod, .{ .sema = sema })).scalar; |
| 36678 | 36862 | } |
| 36679 | 36863 | |
| 36680 | 36864 | /// Not valid to call for packed unions. |
| 36681 | 36865 | /// Keep implementation in sync with `Module.unionFieldNormalAlignment`. |
| 36682 | /// TODO: this returns alignment in byte units should should be a u64 | |
| 36683 | fn unionFieldAlignment(sema: *Sema, u: InternPool.UnionType, field_index: u32) !u32 { | |
| 36866 | fn unionFieldAlignment(sema: *Sema, u: InternPool.UnionType, field_index: u32) !Alignment { | |
| 36684 | 36867 | const mod = sema.mod; |
| 36685 | 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 | 36871 | const field_ty = u.field_types.get(ip)[field_index].toType(); |
| 36688 | if (field_ty.isNoReturn(sema.mod)) return 0; | |
| 36689 | return @intCast(try sema.typeAbiAlignment(field_ty)); | |
| 36872 | if (field_ty.isNoReturn(sema.mod)) return .none; | |
| 36873 | return sema.typeAbiAlignment(field_ty); | |
| 36690 | 36874 | } |
| 36691 | 36875 | |
| 36692 | /// Keep implementation in sync with `Module.Struct.Field.alignment`. | |
| 36693 | fn structFieldAlignment(sema: *Sema, field: Module.Struct.Field, layout: std.builtin.Type.ContainerLayout) !u32 { | |
| 36876 | /// Keep implementation in sync with `Module.structFieldAlignment`. | |
| 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 | 36885 | const mod = sema.mod; |
| 36695 | if (field.abi_align.toByteUnitsOptional()) |a| { | |
| 36696 | assert(layout != .Packed); | |
| 36697 | return @intCast(a); | |
| 36698 | } | |
| 36699 | 36886 | switch (layout) { |
| 36700 | .Packed => return 0, | |
| 36701 | .Auto => if (mod.getTarget().ofmt != .c) { | |
| 36702 | return sema.typeAbiAlignment(field.ty); | |
| 36703 | }, | |
| 36887 | .Packed => return .none, | |
| 36888 | .Auto => if (mod.getTarget().ofmt != .c) return sema.typeAbiAlignment(field_ty), | |
| 36704 | 36889 | .Extern => {}, |
| 36705 | 36890 | } |
| 36706 | 36891 | // extern |
| 36707 | const ty_abi_align = try sema.typeAbiAlignment(field.ty); | |
| 36708 | if (field.ty.isAbiInt(mod) and field.ty.intInfo(mod).bits >= 128) { | |
| 36709 | return @max(ty_abi_align, 16); | |
| 36892 | const ty_abi_align = try sema.typeAbiAlignment(field_ty); | |
| 36893 | if (field_ty.isAbiInt(mod) and field_ty.intInfo(mod).bits >= 128) { | |
| 36894 | return ty_abi_align.maxStrict(.@"16"); | |
| 36710 | 36895 | } |
| 36711 | 36896 | return ty_abi_align; |
| 36712 | 36897 | } |
| ... | ... | @@ -36752,14 +36937,14 @@ fn structFieldIndex( |
| 36752 | 36937 | field_src: LazySrcLoc, |
| 36753 | 36938 | ) !u32 { |
| 36754 | 36939 | const mod = sema.mod; |
| 36940 | const ip = &mod.intern_pool; | |
| 36755 | 36941 | try sema.resolveTypeFields(struct_ty); |
| 36756 | 36942 | if (struct_ty.isAnonStruct(mod)) { |
| 36757 | 36943 | return sema.anonStructFieldIndex(block, struct_ty, field_name, field_src); |
| 36758 | 36944 | } else { |
| 36759 | const struct_obj = mod.typeToStruct(struct_ty).?; | |
| 36760 | const field_index_usize = struct_obj.fields.getIndex(field_name) orelse | |
| 36761 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name); | |
| 36762 | return @intCast(field_index_usize); | |
| 36945 | const struct_type = mod.typeToStruct(struct_ty).?; | |
| 36946 | return struct_type.nameIndex(ip, field_name) orelse | |
| 36947 | return sema.failWithBadStructFieldAccess(block, struct_type, field_src, field_name); | |
| 36763 | 36948 | } |
| 36764 | 36949 | } |
| 36765 | 36950 | |
| ... | ... | @@ -36776,13 +36961,7 @@ fn anonStructFieldIndex( |
| 36776 | 36961 | .anon_struct_type => |anon_struct_type| for (anon_struct_type.names.get(ip), 0..) |name, i| { |
| 36777 | 36962 | if (name == field_name) return @intCast(i); |
| 36778 | 36963 | }, |
| 36779 | .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| { | |
| 36780 | for (struct_obj.fields.keys(), 0..) |name, i| { | |
| 36781 | if (name == field_name) { | |
| 36782 | return @intCast(i); | |
| 36783 | } | |
| 36784 | } | |
| 36785 | }, | |
| 36964 | .struct_type => |struct_type| if (struct_type.nameIndex(ip, field_name)) |i| return i, | |
| 36786 | 36965 | else => unreachable, |
| 36787 | 36966 | } |
| 36788 | 36967 | return sema.fail(block, field_src, "no field named '{}' in anonymous struct '{}'", .{ |
| ... | ... | @@ -37167,8 +37346,8 @@ fn intFitsInType( |
| 37167 | 37346 | // If it is u16 or bigger we know the alignment fits without resolving it. |
| 37168 | 37347 | if (info.bits >= max_needed_bits) return true; |
| 37169 | 37348 | const x = try sema.typeAbiAlignment(lazy_ty.toType()); |
| 37170 | if (x == 0) return true; | |
| 37171 | const actual_needed_bits = std.math.log2(x) + 1 + @intFromBool(info.signedness == .signed); | |
| 37349 | if (x == .none) return true; | |
| 37350 | const actual_needed_bits = @as(usize, x.toLog2Units()) + 1 + @intFromBool(info.signedness == .signed); | |
| 37172 | 37351 | return info.bits >= actual_needed_bits; |
| 37173 | 37352 | }, |
| 37174 | 37353 | .lazy_size => |lazy_ty| { |
| ... | ... | @@ -37381,7 +37560,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { |
| 37381 | 37560 | |
| 37382 | 37561 | const vector_info: struct { |
| 37383 | 37562 | host_size: u16 = 0, |
| 37384 | alignment: u32 = 0, | |
| 37563 | alignment: Alignment = .none, | |
| 37385 | 37564 | vector_index: VI = .none, |
| 37386 | 37565 | } = if (parent_ty.isVector(mod) and ptr_info.flags.size == .One) blk: { |
| 37387 | 37566 | const elem_bits = elem_ty.bitSize(mod); |
| ... | ... | @@ -37391,7 +37570,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { |
| 37391 | 37570 | |
| 37392 | 37571 | break :blk .{ |
| 37393 | 37572 | .host_size = @intCast(parent_ty.arrayLen(mod)), |
| 37394 | .alignment = @intCast(parent_ty.abiAlignment(mod)), | |
| 37573 | .alignment = parent_ty.abiAlignment(mod), | |
| 37395 | 37574 | .vector_index = if (offset) |some| @enumFromInt(some) else .runtime, |
| 37396 | 37575 | }; |
| 37397 | 37576 | } else .{}; |
| ... | ... | @@ -37399,9 +37578,9 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { |
| 37399 | 37578 | const alignment: Alignment = a: { |
| 37400 | 37579 | // Calculate the new pointer alignment. |
| 37401 | 37580 | if (ptr_info.flags.alignment == .none) { |
| 37402 | if (vector_info.alignment != 0) break :a Alignment.fromNonzeroByteUnits(vector_info.alignment); | |
| 37403 | // ABI-aligned pointer. Any pointer arithmetic maintains the same ABI-alignedness. | |
| 37404 | break :a .none; | |
| 37581 | // In case of an ABI-aligned pointer, any pointer arithmetic | |
| 37582 | // maintains the same ABI-alignedness. | |
| 37583 | break :a vector_info.alignment; | |
| 37405 | 37584 | } |
| 37406 | 37585 | // If the addend is not a comptime-known value we can still count on |
| 37407 | 37586 | // it being a multiple of the type size. |
| ... | ... | @@ -37413,12 +37592,12 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { |
| 37413 | 37592 | // non zero). |
| 37414 | 37593 | const new_align: Alignment = @enumFromInt(@min( |
| 37415 | 37594 | @ctz(addend), |
| 37416 | @intFromEnum(ptr_info.flags.alignment), | |
| 37595 | ptr_info.flags.alignment.toLog2Units(), | |
| 37417 | 37596 | )); |
| 37418 | 37597 | assert(new_align != .none); |
| 37419 | 37598 | break :a new_align; |
| 37420 | 37599 | }; |
| 37421 | return mod.ptrType(.{ | |
| 37600 | return sema.ptrType(.{ | |
| 37422 | 37601 | .child = elem_ty.toIntern(), |
| 37423 | 37602 | .flags = .{ |
| 37424 | 37603 | .alignment = alignment, |
| ... | ... | @@ -37473,3 +37652,10 @@ fn isKnownZigType(sema: *Sema, ref: Air.Inst.Ref, tag: std.builtin.TypeId) bool |
| 37473 | 37652 | }; |
| 37474 | 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 | 135 | |
| 136 | 136 | var i: u32 = 0; |
| 137 | 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 | 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 | 142 | if (elem_val.isUndef(mod)) break :str; |
| 142 | 143 | buf[i] = std.math.cast(u8, elem_val.toUnsignedInt(mod)) orelse break :str; |
| 143 | 144 | } |
| ... | ... | @@ -153,9 +154,10 @@ pub fn print( |
| 153 | 154 | var i: u32 = 0; |
| 154 | 155 | while (i < max_len) : (i += 1) { |
| 155 | 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 | 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 | 161 | try print(.{ |
| 160 | 162 | .ty = elem_ty, |
| 161 | 163 | .val = elem_val, |
| ... | ... | @@ -272,7 +274,8 @@ pub fn print( |
| 272 | 274 | const max_len = @min(len, max_string_len); |
| 273 | 275 | var buf: [max_string_len]u8 = undefined; |
| 274 | 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 | 279 | if (elem.isUndef(mod)) break :str; |
| 277 | 280 | c.* = @as(u8, @intCast(elem.toUnsignedInt(mod))); |
| 278 | 281 | } |
| ... | ... | @@ -283,9 +286,11 @@ pub fn print( |
| 283 | 286 | const max_len = @min(len, max_aggregate_items); |
| 284 | 287 | for (0..max_len) |i| { |
| 285 | 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 | 291 | try print(.{ |
| 287 | 292 | .ty = elem_ty, |
| 288 | .val = try val.elemValue(mod, i), | |
| 293 | .val = elem, | |
| 289 | 294 | }, writer, level - 1, mod); |
| 290 | 295 | } |
| 291 | 296 | if (len > max_aggregate_items) { |
| ... | ... | @@ -350,11 +355,11 @@ pub fn print( |
| 350 | 355 | const container_ty = ptr_container_ty.childType(mod); |
| 351 | 356 | switch (container_ty.zigTypeTag(mod)) { |
| 352 | 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 | 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 | 364 | .Union => { |
| 360 | 365 | const field_name = mod.typeToUnion(container_ty).?.field_names.get(ip)[@intCast(field.index)]; |
| ... | ... | @@ -432,7 +437,7 @@ fn printAggregate( |
| 432 | 437 | if (i != 0) try writer.writeAll(", "); |
| 433 | 438 | |
| 434 | 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 | 441 | .anon_struct_type => |x| if (x.isTuple()) .none else x.names.get(ip)[i].toOptional(), |
| 437 | 442 | else => unreachable, |
| 438 | 443 | }; |
src/Zir.zig+4-1| ... | ... | @@ -2840,7 +2840,10 @@ pub const Inst = struct { |
| 2840 | 2840 | is_tuple: bool, |
| 2841 | 2841 | name_strategy: NameStrategy, |
| 2842 | 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 | 23 | const leb128 = std.leb; |
| 24 | 24 | const log = std.log.scoped(.codegen); |
| 25 | 25 | const build_options = @import("build_options"); |
| 26 | const Alignment = InternPool.Alignment; | |
| 26 | 27 | |
| 27 | 28 | const CodeGenError = codegen.CodeGenError; |
| 28 | 29 | const Result = codegen.Result; |
| ... | ... | @@ -506,11 +507,9 @@ fn gen(self: *Self) !void { |
| 506 | 507 | // (or w0 when pointer size is 32 bits). As this register |
| 507 | 508 | // might get overwritten along the way, save the address |
| 508 | 509 | // to the stack. |
| 509 | const ptr_bits = self.target.ptrBitWidth(); | |
| 510 | const ptr_bytes = @divExact(ptr_bits, 8); | |
| 511 | 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 | 514 | try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = ret_ptr_reg }); |
| 516 | 515 | self.ret_mcv = MCValue{ .stack_offset = stack_offset }; |
| ... | ... | @@ -998,11 +997,11 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { |
| 998 | 997 | fn allocMem( |
| 999 | 998 | self: *Self, |
| 1000 | 999 | abi_size: u32, |
| 1001 | abi_align: u32, | |
| 1000 | abi_align: Alignment, | |
| 1002 | 1001 | maybe_inst: ?Air.Inst.Index, |
| 1003 | 1002 | ) !u32 { |
| 1004 | 1003 | assert(abi_size > 0); |
| 1005 | assert(abi_align > 0); | |
| 1004 | assert(abi_align != .none); | |
| 1006 | 1005 | |
| 1007 | 1006 | // In order to efficiently load and store stack items that fit |
| 1008 | 1007 | // into registers, we bump up the alignment to the next power of |
| ... | ... | @@ -1010,10 +1009,10 @@ fn allocMem( |
| 1010 | 1009 | const adjusted_align = if (abi_size > 8) |
| 1011 | 1010 | abi_align |
| 1012 | 1011 | else |
| 1013 | std.math.ceilPowerOfTwoAssert(u32, abi_size); | |
| 1012 | Alignment.fromNonzeroByteUnits(std.math.ceilPowerOfTwoAssert(u64, abi_size)); | |
| 1014 | 1013 | |
| 1015 | 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 | 1016 | self.next_stack_offset = offset; |
| 1018 | 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 | 1514 | const len = try self.resolveInst(bin_op.rhs); |
| 1516 | 1515 | const len_ty = self.typeOf(bin_op.rhs); |
| 1517 | 1516 | |
| 1518 | const ptr_bits = self.target.ptrBitWidth(); | |
| 1519 | const ptr_bytes = @divExact(ptr_bits, 8); | |
| 1520 | ||
| 1521 | const stack_offset = try self.allocMem(ptr_bytes * 2, ptr_bytes * 2, inst); | |
| 1517 | const stack_offset = try self.allocMem(16, .@"8", inst); | |
| 1522 | 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 | 1520 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1525 | 1521 | }; |
| 1526 | 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 | 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 | 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 | 3288 | const stack_offset = try self.allocMem(optional_abi_size, optional_abi_align, inst); |
| 3293 | 3289 | try self.genSetStack(payload_ty, stack_offset, operand); |
| ... | ... | @@ -3376,7 +3372,7 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3376 | 3372 | fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 3377 | 3373 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3378 | 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 | 3376 | const ptr_bytes = @divExact(ptr_bits, 8); |
| 3381 | 3377 | const mcv = try self.resolveInst(ty_op.operand); |
| 3382 | 3378 | switch (mcv) { |
| ... | ... | @@ -3400,7 +3396,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 3400 | 3396 | fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3401 | 3397 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3402 | 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 | 3400 | const ptr_bytes = @divExact(ptr_bits, 8); |
| 3405 | 3401 | const mcv = try self.resolveInst(ty_op.operand); |
| 3406 | 3402 | switch (mcv) { |
| ... | ... | @@ -4272,8 +4268,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4272 | 4268 | if (info.return_value == .stack_offset) { |
| 4273 | 4269 | log.debug("airCall: return by reference", .{}); |
| 4274 | 4270 | const ret_ty = fn_ty.fnReturnType(mod); |
| 4275 | const ret_abi_size = @as(u32, @intCast(ret_ty.abiSize(mod))); | |
| 4276 | const ret_abi_align = @as(u32, @intCast(ret_ty.abiAlignment(mod))); | |
| 4271 | const ret_abi_size: u32 = @intCast(ret_ty.abiSize(mod)); | |
| 4272 | const ret_abi_align = ret_ty.abiAlignment(mod); | |
| 4277 | 4273 | const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst); |
| 4278 | 4274 | |
| 4279 | 4275 | const ret_ptr_reg = self.registerAlias(.x0, Type.usize); |
| ... | ... | @@ -5939,11 +5935,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 5939 | 5935 | const ptr = try self.resolveInst(ty_op.operand); |
| 5940 | 5936 | const array_ty = ptr_ty.childType(mod); |
| 5941 | 5937 | const array_len = @as(u32, @intCast(array_ty.arrayLen(mod))); |
| 5942 | ||
| 5943 | const ptr_bits = self.target.ptrBitWidth(); | |
| 5944 | const ptr_bytes = @divExact(ptr_bits, 8); | |
| 5945 | ||
| 5946 | const stack_offset = try self.allocMem(ptr_bytes * 2, ptr_bytes * 2, inst); | |
| 5938 | const ptr_bytes = 8; | |
| 5939 | const stack_offset = try self.allocMem(ptr_bytes * 2, .@"8", inst); | |
| 5947 | 5940 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 5948 | 5941 | try self.genSetStack(Type.usize, stack_offset - ptr_bytes, .{ .immediate = array_len }); |
| 5949 | 5942 | break :result MCValue{ .stack_offset = stack_offset }; |
| ... | ... | @@ -6254,7 +6247,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6254 | 6247 | |
| 6255 | 6248 | // We round up NCRN only for non-Apple platforms which allow the 16-byte aligned |
| 6256 | 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 | 6251 | // Round up NCRN to the next even number |
| 6259 | 6252 | ncrn += ncrn % 2; |
| 6260 | 6253 | } |
| ... | ... | @@ -6272,7 +6265,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6272 | 6265 | ncrn = 8; |
| 6273 | 6266 | // TODO Apple allows the arguments on the stack to be non-8-byte aligned provided |
| 6274 | 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 | 6269 | if (nsaa % 8 != 0) { |
| 6277 | 6270 | nsaa += 8 - (nsaa % 8); |
| 6278 | 6271 | } |
| ... | ... | @@ -6312,10 +6305,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6312 | 6305 | |
| 6313 | 6306 | for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| { |
| 6314 | 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 | 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 | 6312 | result_arg.* = .{ .stack_argument_offset = stack_offset }; |
| 6320 | 6313 | stack_offset += param_size; |
| 6321 | 6314 | } else { |
src/arch/arm/CodeGen.zig+13-12| ... | ... | @@ -23,6 +23,7 @@ const DW = std.dwarf; |
| 23 | 23 | const leb128 = std.leb; |
| 24 | 24 | const log = std.log.scoped(.codegen); |
| 25 | 25 | const build_options = @import("build_options"); |
| 26 | const Alignment = InternPool.Alignment; | |
| 26 | 27 | |
| 27 | 28 | const Result = codegen.Result; |
| 28 | 29 | const CodeGenError = codegen.CodeGenError; |
| ... | ... | @@ -508,7 +509,7 @@ fn gen(self: *Self) !void { |
| 508 | 509 | // The address of where to store the return value is in |
| 509 | 510 | // r0. As this register might get overwritten along the |
| 510 | 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 | 514 | try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = .r0 }); |
| 514 | 515 | self.ret_mcv = MCValue{ .stack_offset = stack_offset }; |
| ... | ... | @@ -986,14 +987,14 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { |
| 986 | 987 | fn allocMem( |
| 987 | 988 | self: *Self, |
| 988 | 989 | abi_size: u32, |
| 989 | abi_align: u32, | |
| 990 | abi_align: Alignment, | |
| 990 | 991 | maybe_inst: ?Air.Inst.Index, |
| 991 | 992 | ) !u32 { |
| 992 | 993 | assert(abi_size > 0); |
| 993 | assert(abi_align > 0); | |
| 994 | assert(abi_align != .none); | |
| 994 | 995 | |
| 995 | 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 | 998 | self.next_stack_offset = offset; |
| 998 | 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 | 1491 | const len = try self.resolveInst(bin_op.rhs); |
| 1491 | 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 | 1495 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 1495 | 1496 | try self.genSetStack(len_ty, stack_offset - 4, len); |
| 1496 | 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 | 4252 | const r0_lock: ?RegisterLock = if (info.return_value == .stack_offset) blk: { |
| 4252 | 4253 | log.debug("airCall: return by reference", .{}); |
| 4253 | 4254 | const ret_ty = fn_ty.fnReturnType(mod); |
| 4254 | const ret_abi_size = @as(u32, @intCast(ret_ty.abiSize(mod))); | |
| 4255 | const ret_abi_align = @as(u32, @intCast(ret_ty.abiAlignment(mod))); | |
| 4255 | const ret_abi_size: u32 = @intCast(ret_ty.abiSize(mod)); | |
| 4256 | const ret_abi_align = ret_ty.abiAlignment(mod); | |
| 4256 | 4257 | const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst); |
| 4257 | 4258 | |
| 4258 | 4259 | const ptr_ty = try mod.singleMutPtrType(ret_ty); |
| ... | ... | @@ -5896,7 +5897,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 5896 | 5897 | const array_ty = ptr_ty.childType(mod); |
| 5897 | 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 | 5901 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 5901 | 5902 | try self.genSetStack(Type.usize, stack_offset - 4, .{ .immediate = array_len }); |
| 5902 | 5903 | break :result MCValue{ .stack_offset = stack_offset }; |
| ... | ... | @@ -6201,7 +6202,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6201 | 6202 | } |
| 6202 | 6203 | |
| 6203 | 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 | 6206 | ncrn = std.mem.alignForward(usize, ncrn, 2); |
| 6206 | 6207 | |
| 6207 | 6208 | const param_size = @as(u32, @intCast(ty.toType().abiSize(mod))); |
| ... | ... | @@ -6216,7 +6217,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6216 | 6217 | return self.fail("TODO MCValues split between registers and stack", .{}); |
| 6217 | 6218 | } else { |
| 6218 | 6219 | ncrn = 4; |
| 6219 | if (ty.toType().abiAlignment(mod) == 8) | |
| 6220 | if (ty.toType().abiAlignment(mod) == .@"8") | |
| 6220 | 6221 | nsaa = std.mem.alignForward(u32, nsaa, 8); |
| 6221 | 6222 | |
| 6222 | 6223 | result_arg.* = .{ .stack_argument_offset = nsaa }; |
| ... | ... | @@ -6252,10 +6253,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6252 | 6253 | |
| 6253 | 6254 | for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| { |
| 6254 | 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 | 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 | 6260 | result_arg.* = .{ .stack_argument_offset = stack_offset }; |
| 6260 | 6261 | stack_offset += param_size; |
| 6261 | 6262 | } else { |
src/arch/arm/abi.zig+2-2| ... | ... | @@ -47,7 +47,7 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class { |
| 47 | 47 | const field_ty = ty.structFieldType(i, mod); |
| 48 | 48 | const field_alignment = ty.structFieldAlign(i, mod); |
| 49 | 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 | 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 | 66 | |
| 67 | 67 | for (union_obj.field_types.get(ip), 0..) |field_ty, field_index| { |
| 68 | 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 | 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 | 23 | const log = std.log.scoped(.codegen); |
| 24 | 24 | const build_options = @import("build_options"); |
| 25 | 25 | const codegen = @import("../../codegen.zig"); |
| 26 | const Alignment = InternPool.Alignment; | |
| 26 | 27 | |
| 27 | 28 | const CodeGenError = codegen.CodeGenError; |
| 28 | 29 | const Result = codegen.Result; |
| ... | ... | @@ -53,7 +54,7 @@ ret_mcv: MCValue, |
| 53 | 54 | fn_type: Type, |
| 54 | 55 | arg_index: usize, |
| 55 | 56 | src_loc: Module.SrcLoc, |
| 56 | stack_align: u32, | |
| 57 | stack_align: Alignment, | |
| 57 | 58 | |
| 58 | 59 | /// MIR Instructions |
| 59 | 60 | mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, |
| ... | ... | @@ -788,11 +789,10 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { |
| 788 | 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 | if (abi_align > self.stack_align) | |
| 793 | self.stack_align = abi_align; | |
| 792 | fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: Alignment) !u32 { | |
| 793 | self.stack_align = self.stack_align.max(abi_align); | |
| 794 | 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 | 796 | self.next_stack_offset = offset + abi_size; |
| 797 | 797 | if (self.next_stack_offset > self.max_end_stack) |
| 798 | 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 | 822 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); |
| 823 | 823 | }; |
| 824 | 824 | const abi_align = elem_ty.abiAlignment(mod); |
| 825 | if (abi_align > self.stack_align) | |
| 826 | self.stack_align = abi_align; | |
| 825 | self.stack_align = self.stack_align.max(abi_align); | |
| 827 | 826 | |
| 828 | 827 | if (reg_ok) { |
| 829 | 828 | // Make sure the type can fit in a register before we try to allocate one. |
| ... | ... | @@ -2602,7 +2601,7 @@ const CallMCValues = struct { |
| 2602 | 2601 | args: []MCValue, |
| 2603 | 2602 | return_value: MCValue, |
| 2604 | 2603 | stack_byte_count: u32, |
| 2605 | stack_align: u32, | |
| 2604 | stack_align: Alignment, | |
| 2606 | 2605 | |
| 2607 | 2606 | fn deinit(self: *CallMCValues, func: *Self) void { |
| 2608 | 2607 | func.gpa.free(self.args); |
| ... | ... | @@ -2632,7 +2631,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 2632 | 2631 | assert(result.args.len == 0); |
| 2633 | 2632 | result.return_value = .{ .unreach = {} }; |
| 2634 | 2633 | result.stack_byte_count = 0; |
| 2635 | result.stack_align = 1; | |
| 2634 | result.stack_align = .@"1"; | |
| 2636 | 2635 | return result; |
| 2637 | 2636 | }, |
| 2638 | 2637 | .Unspecified, .C => { |
| ... | ... | @@ -2671,7 +2670,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 2671 | 2670 | } |
| 2672 | 2671 | |
| 2673 | 2672 | result.stack_byte_count = next_stack_offset; |
| 2674 | result.stack_align = 16; | |
| 2673 | result.stack_align = .@"16"; | |
| 2675 | 2674 | }, |
| 2676 | 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 | 24 | const Result = @import("../../codegen.zig").Result; |
| 25 | 25 | const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; |
| 26 | 26 | const Endian = std.builtin.Endian; |
| 27 | const Alignment = InternPool.Alignment; | |
| 27 | 28 | |
| 28 | 29 | const build_options = @import("build_options"); |
| 29 | 30 | |
| ... | ... | @@ -62,7 +63,7 @@ ret_mcv: MCValue, |
| 62 | 63 | fn_type: Type, |
| 63 | 64 | arg_index: usize, |
| 64 | 65 | src_loc: Module.SrcLoc, |
| 65 | stack_align: u32, | |
| 66 | stack_align: Alignment, | |
| 66 | 67 | |
| 67 | 68 | /// MIR Instructions |
| 68 | 69 | mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, |
| ... | ... | @@ -227,7 +228,7 @@ const CallMCValues = struct { |
| 227 | 228 | args: []MCValue, |
| 228 | 229 | return_value: MCValue, |
| 229 | 230 | stack_byte_count: u32, |
| 230 | stack_align: u32, | |
| 231 | stack_align: Alignment, | |
| 231 | 232 | |
| 232 | 233 | fn deinit(self: *CallMCValues, func: *Self) void { |
| 233 | 234 | func.gpa.free(self.args); |
| ... | ... | @@ -424,7 +425,7 @@ fn gen(self: *Self) !void { |
| 424 | 425 | |
| 425 | 426 | // Backpatch stack offset |
| 426 | 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 | 429 | if (math.cast(i13, stack_size)) |size| { |
| 429 | 430 | self.mir_instructions.set(save_inst, .{ |
| 430 | 431 | .tag = .save, |
| ... | ... | @@ -880,11 +881,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 880 | 881 | const ptr = try self.resolveInst(ty_op.operand); |
| 881 | 882 | const array_ty = ptr_ty.childType(mod); |
| 882 | 883 | const array_len = @as(u32, @intCast(array_ty.arrayLen(mod))); |
| 883 | ||
| 884 | const ptr_bits = self.target.ptrBitWidth(); | |
| 885 | const ptr_bytes = @divExact(ptr_bits, 8); | |
| 886 | ||
| 887 | const stack_offset = try self.allocMem(inst, ptr_bytes * 2, ptr_bytes * 2); | |
| 884 | const ptr_bytes = 8; | |
| 885 | const stack_offset = try self.allocMem(inst, ptr_bytes * 2, .@"8"); | |
| 888 | 886 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 889 | 887 | try self.genSetStack(Type.usize, stack_offset - ptr_bytes, .{ .immediate = array_len }); |
| 890 | 888 | break :result MCValue{ .stack_offset = stack_offset }; |
| ... | ... | @@ -2438,11 +2436,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 2438 | 2436 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 2439 | 2437 | const len = try self.resolveInst(bin_op.rhs); |
| 2440 | 2438 | const len_ty = self.typeOf(bin_op.rhs); |
| 2441 | ||
| 2442 | const ptr_bits = self.target.ptrBitWidth(); | |
| 2443 | const ptr_bytes = @divExact(ptr_bits, 8); | |
| 2444 | ||
| 2445 | const stack_offset = try self.allocMem(inst, ptr_bytes * 2, ptr_bytes * 2); | |
| 2439 | const ptr_bytes = 8; | |
| 2440 | const stack_offset = try self.allocMem(inst, ptr_bytes * 2, .@"8"); | |
| 2446 | 2441 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 2447 | 2442 | try self.genSetStack(len_ty, stack_offset - ptr_bytes, len); |
| 2448 | 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 | 2777 | return result_index; |
| 2783 | 2778 | } |
| 2784 | 2779 | |
| 2785 | fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 { | |
| 2786 | if (abi_align > self.stack_align) | |
| 2787 | self.stack_align = abi_align; | |
| 2780 | fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: Alignment) !u32 { | |
| 2781 | self.stack_align = self.stack_align.max(abi_align); | |
| 2788 | 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 | 2784 | self.next_stack_offset = offset; |
| 2791 | 2785 | if (self.next_stack_offset > self.max_end_stack) |
| 2792 | 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 | 2819 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); |
| 2826 | 2820 | }; |
| 2827 | 2821 | const abi_align = elem_ty.abiAlignment(mod); |
| 2828 | if (abi_align > self.stack_align) | |
| 2829 | self.stack_align = abi_align; | |
| 2822 | self.stack_align = self.stack_align.max(abi_align); | |
| 2830 | 2823 | |
| 2831 | 2824 | if (reg_ok) { |
| 2832 | 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 | 4472 | assert(result.args.len == 0); |
| 4480 | 4473 | result.return_value = .{ .unreach = {} }; |
| 4481 | 4474 | result.stack_byte_count = 0; |
| 4482 | result.stack_align = 1; | |
| 4475 | result.stack_align = .@"1"; | |
| 4483 | 4476 | return result; |
| 4484 | 4477 | }, |
| 4485 | 4478 | .Unspecified, .C => { |
| ... | ... | @@ -4521,7 +4514,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) |
| 4521 | 4514 | } |
| 4522 | 4515 | |
| 4523 | 4516 | result.stack_byte_count = next_stack_offset; |
| 4524 | result.stack_align = 16; | |
| 4517 | result.stack_align = .@"16"; | |
| 4525 | 4518 | |
| 4526 | 4519 | if (ret_ty.zigTypeTag(mod) == .NoReturn) { |
| 4527 | 4520 | result.return_value = .{ .unreach = {} }; |
src/arch/wasm/CodeGen.zig+88-75| ... | ... | @@ -25,6 +25,7 @@ const target_util = @import("../../target.zig"); |
| 25 | 25 | const Mir = @import("Mir.zig"); |
| 26 | 26 | const Emit = @import("Emit.zig"); |
| 27 | 27 | const abi = @import("abi.zig"); |
| 28 | const Alignment = InternPool.Alignment; | |
| 28 | 29 | const errUnionPayloadOffset = codegen.errUnionPayloadOffset; |
| 29 | 30 | const errUnionErrorOffset = codegen.errUnionErrorOffset; |
| 30 | 31 | |
| ... | ... | @@ -709,7 +710,7 @@ stack_size: u32 = 0, |
| 709 | 710 | /// tool-conventions: https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md |
| 710 | 711 | /// and also what the llvm backend will emit. |
| 711 | 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 | 715 | // For each individual Wasm valtype we store a seperate free list which |
| 715 | 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 | 992 | /// Using a given `Type`, returns the corresponding type |
| 992 | 993 | fn typeToValtype(ty: Type, mod: *Module) wasm.Valtype { |
| 993 | 994 | const target = mod.getTarget(); |
| 995 | const ip = &mod.intern_pool; | |
| 994 | 996 | return switch (ty.zigTypeTag(mod)) { |
| 995 | 997 | .Float => switch (ty.floatBits(target)) { |
| 996 | 998 | 16 => wasm.Valtype.i32, // stored/loaded as u16 |
| ... | ... | @@ -1005,12 +1007,12 @@ fn typeToValtype(ty: Type, mod: *Module) wasm.Valtype { |
| 1005 | 1007 | if (info.bits > 32 and info.bits <= 128) break :blk wasm.Valtype.i64; |
| 1006 | 1008 | break :blk wasm.Valtype.i32; // represented as pointer to stack |
| 1007 | 1009 | }, |
| 1008 | .Struct => switch (ty.containerLayout(mod)) { | |
| 1009 | .Packed => { | |
| 1010 | const struct_obj = mod.typeToStruct(ty).?; | |
| 1011 | return typeToValtype(struct_obj.backing_int_ty, mod); | |
| 1012 | }, | |
| 1013 | else => wasm.Valtype.i32, | |
| 1010 | .Struct => { | |
| 1011 | if (mod.typeToPackedStruct(ty)) |packed_struct| { | |
| 1012 | return typeToValtype(packed_struct.backingIntType(ip).toType(), mod); | |
| 1013 | } else { | |
| 1014 | return wasm.Valtype.i32; | |
| 1015 | } | |
| 1014 | 1016 | }, |
| 1015 | 1017 | .Vector => switch (determineSimdStoreStrategy(ty, mod)) { |
| 1016 | 1018 | .direct => wasm.Valtype.v128, |
| ... | ... | @@ -1285,12 +1287,12 @@ fn genFunc(func: *CodeGen) InnerError!void { |
| 1285 | 1287 | // store stack pointer so we can restore it when we return from the function |
| 1286 | 1288 | try prologue.append(.{ .tag = .local_tee, .data = .{ .label = func.initial_stack_value.local.value } }); |
| 1287 | 1289 | // get the total stack size |
| 1288 | const aligned_stack = std.mem.alignForward(u32, func.stack_size, func.stack_alignment); | |
| 1289 | try prologue.append(.{ .tag = .i32_const, .data = .{ .imm32 = @as(i32, @intCast(aligned_stack)) } }); | |
| 1290 | // substract it from the current stack pointer | |
| 1290 | const aligned_stack = func.stack_alignment.forward(func.stack_size); | |
| 1291 | try prologue.append(.{ .tag = .i32_const, .data = .{ .imm32 = @intCast(aligned_stack) } }); | |
| 1292 | // subtract it from the current stack pointer | |
| 1291 | 1293 | try prologue.append(.{ .tag = .i32_sub, .data = .{ .tag = {} } }); |
| 1292 | 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 | 1296 | // Bitwise-and the value to get the new stack pointer to ensure the pointers are aligned with the abi alignment |
| 1295 | 1297 | try prologue.append(.{ .tag = .i32_and, .data = .{ .tag = {} } }); |
| 1296 | 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 | 1440 | }); |
| 1439 | 1441 | try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{ |
| 1440 | 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 | 1529 | }; |
| 1528 | 1530 | const abi_align = ty.abiAlignment(mod); |
| 1529 | 1531 | |
| 1530 | if (abi_align > func.stack_alignment) { | |
| 1531 | func.stack_alignment = abi_align; | |
| 1532 | } | |
| 1532 | func.stack_alignment = func.stack_alignment.max(abi_align); | |
| 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 | 1535 | defer func.stack_size = offset + abi_size; |
| 1536 | 1536 | |
| 1537 | 1537 | return WValue{ .stack_offset = .{ .value = offset, .references = 1 } }; |
| ... | ... | @@ -1560,11 +1560,9 @@ fn allocStackPtr(func: *CodeGen, inst: Air.Inst.Index) !WValue { |
| 1560 | 1560 | pointee_ty.fmt(mod), pointee_ty.abiSize(mod), |
| 1561 | 1561 | }); |
| 1562 | 1562 | }; |
| 1563 | if (abi_alignment > func.stack_alignment) { | |
| 1564 | func.stack_alignment = abi_alignment; | |
| 1565 | } | |
| 1563 | func.stack_alignment = func.stack_alignment.max(abi_alignment); | |
| 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 | 1566 | defer func.stack_size = offset + abi_size; |
| 1569 | 1567 | |
| 1570 | 1568 | return WValue{ .stack_offset = .{ .value = offset, .references = 1 } }; |
| ... | ... | @@ -1749,10 +1747,8 @@ fn isByRef(ty: Type, mod: *Module) bool { |
| 1749 | 1747 | return ty.hasRuntimeBitsIgnoreComptime(mod); |
| 1750 | 1748 | }, |
| 1751 | 1749 | .Struct => { |
| 1752 | if (mod.typeToStruct(ty)) |struct_obj| { | |
| 1753 | if (struct_obj.layout == .Packed and struct_obj.haveFieldTypes()) { | |
| 1754 | return isByRef(struct_obj.backing_int_ty, mod); | |
| 1755 | } | |
| 1750 | if (mod.typeToPackedStruct(ty)) |packed_struct| { | |
| 1751 | return isByRef(packed_struct.backingIntType(ip).toType(), mod); | |
| 1756 | 1752 | } |
| 1757 | 1753 | return ty.hasRuntimeBitsIgnoreComptime(mod); |
| 1758 | 1754 | }, |
| ... | ... | @@ -2120,7 +2116,7 @@ fn airRet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2120 | 2116 | }); |
| 2121 | 2117 | try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{ |
| 2122 | 2118 | .offset = operand.offset(), |
| 2123 | .alignment = scalar_type.abiAlignment(mod), | |
| 2119 | .alignment = @intCast(scalar_type.abiAlignment(mod).toByteUnitsOptional().?), | |
| 2124 | 2120 | }); |
| 2125 | 2121 | }, |
| 2126 | 2122 | else => try func.emitWValue(operand), |
| ... | ... | @@ -2385,19 +2381,19 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE |
| 2385 | 2381 | }, |
| 2386 | 2382 | .Vector => switch (determineSimdStoreStrategy(ty, mod)) { |
| 2387 | 2383 | .unrolled => { |
| 2388 | const len = @as(u32, @intCast(abi_size)); | |
| 2384 | const len: u32 = @intCast(abi_size); | |
| 2389 | 2385 | return func.memcpy(lhs, rhs, .{ .imm32 = len }); |
| 2390 | 2386 | }, |
| 2391 | 2387 | .direct => { |
| 2392 | 2388 | try func.emitWValue(lhs); |
| 2393 | 2389 | try func.lowerToStack(rhs); |
| 2394 | 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 | 2392 | // stores as := opcode, offset, alignment (opcode::memarg) |
| 2397 | 2393 | try func.mir_extra.appendSlice(func.gpa, &[_]u32{ |
| 2398 | 2394 | std.wasm.simdOpcode(.v128_store), |
| 2399 | 2395 | offset + lhs.offset(), |
| 2400 | ty.abiAlignment(mod), | |
| 2396 | @intCast(ty.abiAlignment(mod).toByteUnits(0)), | |
| 2401 | 2397 | }); |
| 2402 | 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 | 2447 | // store rhs value at stack pointer's location in memory |
| 2452 | 2448 | try func.addMemArg( |
| 2453 | 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 | 2509 | try func.mir_extra.appendSlice(func.gpa, &[_]u32{ |
| 2511 | 2510 | std.wasm.simdOpcode(.v128_load), |
| 2512 | 2511 | offset + operand.offset(), |
| 2513 | ty.abiAlignment(mod), | |
| 2512 | @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?), | |
| 2514 | 2513 | }); |
| 2515 | 2514 | try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); |
| 2516 | 2515 | return WValue{ .stack = {} }; |
| ... | ... | @@ -2526,7 +2525,10 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu |
| 2526 | 2525 | |
| 2527 | 2526 | try func.addMemArg( |
| 2528 | 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 | 2534 | return WValue{ .stack = {} }; |
| ... | ... | @@ -3023,10 +3025,10 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue |
| 3023 | 3025 | else => blk: { |
| 3024 | 3026 | const layout: Module.UnionLayout = parent_ty.unionGetLayout(mod); |
| 3025 | 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 | 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 | 3034 | .Pointer => switch (parent_ty.ptrSize(mod)) { |
| ... | ... | @@ -3103,8 +3105,12 @@ fn toTwosComplement(value: anytype, bits: u7) std.meta.Int(.unsigned, @typeInfo( |
| 3103 | 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 | 3110 | fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { |
| 3107 | 3111 | const mod = func.bin_file.base.options.module.?; |
| 3112 | // TODO: enable this assertion | |
| 3113 | //assert(!isByRef(ty, mod)); | |
| 3108 | 3114 | const ip = &mod.intern_pool; |
| 3109 | 3115 | var val = arg_val; |
| 3110 | 3116 | switch (ip.indexToKey(val.ip_index)) { |
| ... | ... | @@ -3235,16 +3241,18 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { |
| 3235 | 3241 | val.writeToMemory(ty, mod, &buf) catch unreachable; |
| 3236 | 3242 | return func.storeSimdImmd(buf); |
| 3237 | 3243 | }, |
| 3238 | .struct_type, .anon_struct_type => { | |
| 3239 | const struct_obj = mod.typeToStruct(ty).?; | |
| 3240 | assert(struct_obj.layout == .Packed); | |
| 3244 | .struct_type => |struct_type| { | |
| 3245 | // non-packed structs are not handled in this function because they | |
| 3246 | // are by-ref types. | |
| 3247 | assert(struct_type.layout == .Packed); | |
| 3241 | 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 | 3251 | const int_val = try mod.intValue( |
| 3244 | struct_obj.backing_int_ty, | |
| 3245 | std.mem.readIntLittle(u64, &buf), | |
| 3252 | backing_int_ty, | |
| 3253 | mem.readIntLittle(u64, &buf), | |
| 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 | 3257 | else => unreachable, |
| 3250 | 3258 | }, |
| ... | ... | @@ -3269,6 +3277,7 @@ fn storeSimdImmd(func: *CodeGen, value: [16]u8) !WValue { |
| 3269 | 3277 | |
| 3270 | 3278 | fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue { |
| 3271 | 3279 | const mod = func.bin_file.base.options.module.?; |
| 3280 | const ip = &mod.intern_pool; | |
| 3272 | 3281 | switch (ty.zigTypeTag(mod)) { |
| 3273 | 3282 | .Bool, .ErrorSet => return WValue{ .imm32 = 0xaaaaaaaa }, |
| 3274 | 3283 | .Int, .Enum => switch (ty.intInfo(mod).bits) { |
| ... | ... | @@ -3298,9 +3307,8 @@ fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue { |
| 3298 | 3307 | return WValue{ .imm32 = 0xaaaaaaaa }; |
| 3299 | 3308 | }, |
| 3300 | 3309 | .Struct => { |
| 3301 | const struct_obj = mod.typeToStruct(ty).?; | |
| 3302 | assert(struct_obj.layout == .Packed); | |
| 3303 | return func.emitUndefined(struct_obj.backing_int_ty); | |
| 3310 | const packed_struct = mod.typeToPackedStruct(ty).?; | |
| 3311 | return func.emitUndefined(packed_struct.backingIntType(ip).toType()); | |
| 3304 | 3312 | }, |
| 3305 | 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 | 3348 | .i64 => |x| @as(i32, @intCast(x)), |
| 3341 | 3349 | .u64 => |x| @as(i32, @bitCast(@as(u32, @intCast(x)))), |
| 3342 | 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 | 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 | 3765 | |
| 3758 | 3766 | fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3759 | 3767 | const mod = func.bin_file.base.options.module.?; |
| 3768 | const ip = &mod.intern_pool; | |
| 3760 | 3769 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 3761 | 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 | 3778 | const result = switch (struct_ty.containerLayout(mod)) { |
| 3770 | 3779 | .Packed => switch (struct_ty.zigTypeTag(mod)) { |
| 3771 | 3780 | .Struct => result: { |
| 3772 | const struct_obj = mod.typeToStruct(struct_ty).?; | |
| 3773 | const offset = struct_obj.packedFieldBitOffset(mod, field_index); | |
| 3774 | const backing_ty = struct_obj.backing_int_ty; | |
| 3781 | const packed_struct = mod.typeToPackedStruct(struct_ty).?; | |
| 3782 | const offset = mod.structPackedFieldBitOffset(packed_struct, field_index); | |
| 3783 | const backing_ty = packed_struct.backingIntType(ip).toType(); | |
| 3775 | 3784 | const wasm_bits = toWasmBits(backing_ty.intInfo(mod).bits) orelse { |
| 3776 | 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 | 3802 | const truncated = try func.trunc(shifted_value, int_type, backing_ty); |
| 3794 | 3803 | const bitcasted = try func.bitcast(field_ty, int_type, truncated); |
| 3795 | 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 | 3806 | // In this case we do not have to perform any transformations, |
| 3798 | 3807 | // we can simply reuse the operand. |
| 3799 | 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 | 4062 | if (pl_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 4054 | 4063 | try func.addMemArg(.i32_load16_u, .{ |
| 4055 | 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 | 4150 | try func.emitWValue(err_union); |
| 4142 | 4151 | try func.addImm32(0); |
| 4143 | 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 | 4157 | break :result err_union; |
| 4146 | 4158 | }; |
| 4147 | 4159 | func.finishAir(inst, result, &.{ty_op.operand}); |
| ... | ... | @@ -4977,7 +4989,7 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4977 | 4989 | try func.mir_extra.appendSlice(func.gpa, &[_]u32{ |
| 4978 | 4990 | opcode, |
| 4979 | 4991 | operand.offset(), |
| 4980 | elem_ty.abiAlignment(mod), | |
| 4992 | @intCast(elem_ty.abiAlignment(mod).toByteUnitsOptional().?), | |
| 4981 | 4993 | }); |
| 4982 | 4994 | try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); |
| 4983 | 4995 | try func.addLabel(.local_set, result.local.value); |
| ... | ... | @@ -5065,7 +5077,7 @@ fn airShuffle(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5065 | 5077 | std.wasm.simdOpcode(.i8x16_shuffle), |
| 5066 | 5078 | } ++ [1]u32{undefined} ** 4; |
| 5067 | 5079 | |
| 5068 | var lanes = std.mem.asBytes(operands[1..]); | |
| 5080 | var lanes = mem.asBytes(operands[1..]); | |
| 5069 | 5081 | for (0..@as(usize, @intCast(mask_len))) |index| { |
| 5070 | 5082 | const mask_elem = (try mask.elemValue(mod, index)).toSignedInt(mod); |
| 5071 | 5083 | const base_index = if (mask_elem >= 0) |
| ... | ... | @@ -5099,6 +5111,7 @@ fn airReduce(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5099 | 5111 | |
| 5100 | 5112 | fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5101 | 5113 | const mod = func.bin_file.base.options.module.?; |
| 5114 | const ip = &mod.intern_pool; | |
| 5102 | 5115 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 5103 | 5116 | const result_ty = func.typeOfIndex(inst); |
| 5104 | 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 | 5163 | if (isByRef(result_ty, mod)) { |
| 5151 | 5164 | return func.fail("TODO: airAggregateInit for packed structs larger than 64 bits", .{}); |
| 5152 | 5165 | } |
| 5153 | const struct_obj = mod.typeToStruct(result_ty).?; | |
| 5154 | const fields = struct_obj.fields.values(); | |
| 5155 | const backing_type = struct_obj.backing_int_ty; | |
| 5166 | const packed_struct = mod.typeToPackedStruct(result_ty).?; | |
| 5167 | const field_types = packed_struct.field_types; | |
| 5168 | const backing_type = packed_struct.backingIntType(ip).toType(); | |
| 5156 | 5169 | |
| 5157 | 5170 | // ensure the result is zero'd |
| 5158 | 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 | 5173 | try func.addImm32(0) |
| 5161 | 5174 | else |
| 5162 | 5175 | try func.addImm64(0); |
| ... | ... | @@ -5164,22 +5177,22 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5164 | 5177 | |
| 5165 | 5178 | var current_bit: u16 = 0; |
| 5166 | 5179 | for (elements, 0..) |elem, elem_index| { |
| 5167 | const field = fields[elem_index]; | |
| 5168 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 5180 | const field_ty = field_types.get(ip)[elem_index].toType(); | |
| 5181 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 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 | 5184 | WValue{ .imm32 = current_bit } |
| 5172 | 5185 | else |
| 5173 | 5186 | WValue{ .imm64 = current_bit }; |
| 5174 | 5187 | |
| 5175 | 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 | 5190 | const int_ty = try mod.intType(.unsigned, value_bit_size); |
| 5178 | 5191 | |
| 5179 | 5192 | // load our current result on stack so we can perform all transformations |
| 5180 | 5193 | // using only stack values. Saving the cost of loads and stores. |
| 5181 | 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 | 5196 | const extended_val = try func.intcast(bitcasted, int_ty, backing_type); |
| 5184 | 5197 | // no need to shift any values when the current offset is 0 |
| 5185 | 5198 | const shifted = if (current_bit != 0) shifted: { |
| ... | ... | @@ -5199,7 +5212,7 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5199 | 5212 | if ((try result_ty.structFieldValueComptime(mod, elem_index)) != null) continue; |
| 5200 | 5213 | |
| 5201 | 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 | 5216 | const value = try func.resolveInst(elem); |
| 5204 | 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 | 5269 | if (isByRef(union_ty, mod)) { |
| 5257 | 5270 | const result_ptr = try func.allocStack(union_ty); |
| 5258 | 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 | 5273 | if (isByRef(field_ty, mod)) { |
| 5261 | 5274 | const payload_ptr = try func.buildPointerOffset(result_ptr, layout.tag_size, .new); |
| 5262 | 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 | 5433 | |
| 5421 | 5434 | // when the tag alignment is smaller than the payload, the field will be stored |
| 5422 | 5435 | // after the payload. |
| 5423 | const offset = if (layout.tag_align < layout.payload_align) blk: { | |
| 5424 | break :blk @as(u32, @intCast(layout.payload_size)); | |
| 5425 | } else @as(u32, 0); | |
| 5436 | const offset: u32 = if (layout.tag_align.compare(.lt, layout.payload_align)) blk: { | |
| 5437 | break :blk @intCast(layout.payload_size); | |
| 5438 | } else 0; | |
| 5426 | 5439 | try func.store(union_ptr, new_tag, tag_ty, offset); |
| 5427 | 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 | 5452 | const operand = try func.resolveInst(ty_op.operand); |
| 5440 | 5453 | // when the tag alignment is smaller than the payload, the field will be stored |
| 5441 | 5454 | // after the payload. |
| 5442 | const offset = if (layout.tag_align < layout.payload_align) blk: { | |
| 5443 | break :blk @as(u32, @intCast(layout.payload_size)); | |
| 5444 | } else @as(u32, 0); | |
| 5455 | const offset: u32 = if (layout.tag_align.compare(.lt, layout.payload_align)) blk: { | |
| 5456 | break :blk @intCast(layout.payload_size); | |
| 5457 | } else 0; | |
| 5445 | 5458 | const tag = try func.load(operand, tag_ty, offset); |
| 5446 | 5459 | const result = try tag.toLocal(func, tag_ty); |
| 5447 | 5460 | func.finishAir(inst, result, &.{ty_op.operand}); |
| ... | ... | @@ -6366,7 +6379,7 @@ fn lowerTry( |
| 6366 | 6379 | const err_offset = @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod))); |
| 6367 | 6380 | try func.addMemArg(.i32_load16_u, .{ |
| 6368 | 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 | 6385 | try func.addTag(.i32_eqz); |
| ... | ... | @@ -7287,7 +7300,7 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7287 | 7300 | else => |size| return func.fail("TODO: implement `@cmpxchg` for types with abi size '{d}'", .{size}), |
| 7288 | 7301 | }, .{ |
| 7289 | 7302 | .offset = ptr_operand.offset(), |
| 7290 | .alignment = ty.abiAlignment(mod), | |
| 7303 | .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?), | |
| 7291 | 7304 | }); |
| 7292 | 7305 | try func.addLabel(.local_tee, val_local.local.value); |
| 7293 | 7306 | _ = try func.cmp(.stack, expected_val, ty, .eq); |
| ... | ... | @@ -7349,7 +7362,7 @@ fn airAtomicLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7349 | 7362 | try func.emitWValue(ptr); |
| 7350 | 7363 | try func.addAtomicMemArg(tag, .{ |
| 7351 | 7364 | .offset = ptr.offset(), |
| 7352 | .alignment = ty.abiAlignment(mod), | |
| 7365 | .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?), | |
| 7353 | 7366 | }); |
| 7354 | 7367 | } else { |
| 7355 | 7368 | _ = try func.load(ptr, ty, 0); |
| ... | ... | @@ -7410,7 +7423,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7410 | 7423 | }, |
| 7411 | 7424 | .{ |
| 7412 | 7425 | .offset = ptr.offset(), |
| 7413 | .alignment = ty.abiAlignment(mod), | |
| 7426 | .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?), | |
| 7414 | 7427 | }, |
| 7415 | 7428 | ); |
| 7416 | 7429 | const select_res = try func.allocLocal(ty); |
| ... | ... | @@ -7470,7 +7483,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7470 | 7483 | }; |
| 7471 | 7484 | try func.addAtomicMemArg(tag, .{ |
| 7472 | 7485 | .offset = ptr.offset(), |
| 7473 | .alignment = ty.abiAlignment(mod), | |
| 7486 | .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?), | |
| 7474 | 7487 | }); |
| 7475 | 7488 | const result = try WValue.toLocal(.stack, func, ty); |
| 7476 | 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 | 7579 | try func.lowerToStack(operand); |
| 7567 | 7580 | try func.addAtomicMemArg(tag, .{ |
| 7568 | 7581 | .offset = ptr.offset(), |
| 7569 | .alignment = ty.abiAlignment(mod), | |
| 7582 | .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?), | |
| 7570 | 7583 | }); |
| 7571 | 7584 | } else { |
| 7572 | 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 | 28 | if (!ty.hasRuntimeBitsIgnoreComptime(mod)) return none; |
| 29 | 29 | switch (ty.zigTypeTag(mod)) { |
| 30 | 30 | .Struct => { |
| 31 | if (ty.containerLayout(mod) == .Packed) { | |
| 31 | const struct_type = mod.typeToStruct(ty).?; | |
| 32 | if (struct_type.layout == .Packed) { | |
| 32 | 33 | if (ty.bitSize(mod) <= 64) return direct; |
| 33 | 34 | return .{ .direct, .direct }; |
| 34 | 35 | } |
| 35 | // When the struct type is non-scalar | |
| 36 | if (ty.structFieldCount(mod) > 1) return memory; | |
| 37 | // When the struct's alignment is non-natural | |
| 38 | const field = ty.structFields(mod).values()[0]; | |
| 39 | if (field.abi_align != .none) { | |
| 40 | if (field.abi_align.toByteUnitsOptional().? > field.ty.abiAlignment(mod)) { | |
| 36 | if (struct_type.field_types.len > 1) { | |
| 37 | // The struct type is non-scalar. | |
| 38 | return memory; | |
| 39 | } | |
| 40 | const field_ty = struct_type.field_types.get(ip)[0].toType(); | |
| 41 | const explicit_align = struct_type.fieldAlign(ip, 0); | |
| 42 | if (explicit_align != .none) { | |
| 43 | if (explicit_align.compareStrict(.gt, field_ty.abiAlignment(mod))) | |
| 41 | 44 | return memory; |
| 42 | } | |
| 43 | 45 | } |
| 44 | return classifyType(field.ty, mod); | |
| 46 | return classifyType(field_ty, mod); | |
| 45 | 47 | }, |
| 46 | 48 | .Int, .Enum, .ErrorSet, .Vector => { |
| 47 | 49 | const int_bits = ty.intInfo(mod).bits; |
| ... | ... | @@ -101,15 +103,11 @@ pub fn scalarType(ty: Type, mod: *Module) Type { |
| 101 | 103 | const ip = &mod.intern_pool; |
| 102 | 104 | switch (ty.zigTypeTag(mod)) { |
| 103 | 105 | .Struct => { |
| 104 | switch (ty.containerLayout(mod)) { | |
| 105 | .Packed => { | |
| 106 | const struct_obj = mod.typeToStruct(ty).?; | |
| 107 | return scalarType(struct_obj.backing_int_ty, mod); | |
| 108 | }, | |
| 109 | else => { | |
| 110 | assert(ty.structFieldCount(mod) == 1); | |
| 111 | return scalarType(ty.structFieldType(0, mod), mod); | |
| 112 | }, | |
| 106 | if (mod.typeToPackedStruct(ty)) |packed_struct| { | |
| 107 | return scalarType(packed_struct.backingIntType(ip).toType(), mod); | |
| 108 | } else { | |
| 109 | assert(ty.structFieldCount(mod) == 1); | |
| 110 | return scalarType(ty.structFieldType(0, mod), mod); | |
| 113 | 111 | } |
| 114 | 112 | }, |
| 115 | 113 | .Union => { |
src/arch/x86_64/CodeGen.zig+61-58| ... | ... | @@ -27,6 +27,7 @@ const Lower = @import("Lower.zig"); |
| 27 | 27 | const Mir = @import("Mir.zig"); |
| 28 | 28 | const Module = @import("../../Module.zig"); |
| 29 | 29 | const InternPool = @import("../../InternPool.zig"); |
| 30 | const Alignment = InternPool.Alignment; | |
| 30 | 31 | const Target = std.Target; |
| 31 | 32 | const Type = @import("../../type.zig").Type; |
| 32 | 33 | const TypedValue = @import("../../TypedValue.zig"); |
| ... | ... | @@ -607,19 +608,21 @@ const InstTracking = struct { |
| 607 | 608 | |
| 608 | 609 | const FrameAlloc = struct { |
| 609 | 610 | abi_size: u31, |
| 610 | abi_align: u5, | |
| 611 | abi_align: Alignment, | |
| 611 | 612 | ref_count: u16, |
| 612 | 613 | |
| 613 | fn init(alloc_abi: struct { size: u64, alignment: u32 }) FrameAlloc { | |
| 614 | assert(math.isPowerOfTwo(alloc_abi.alignment)); | |
| 614 | fn init(alloc_abi: struct { size: u64, alignment: Alignment }) FrameAlloc { | |
| 615 | 615 | return .{ |
| 616 | 616 | .abi_size = @intCast(alloc_abi.size), |
| 617 | .abi_align = math.log2_int(u32, alloc_abi.alignment), | |
| 617 | .abi_align = alloc_abi.alignment, | |
| 618 | 618 | .ref_count = 0, |
| 619 | 619 | }; |
| 620 | 620 | } |
| 621 | 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 | 705 | @intFromEnum(FrameIndex.stack_frame), |
| 703 | 706 | FrameAlloc.init(.{ |
| 704 | 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 | 711 | function.frame_allocs.set( |
| 709 | 712 | @intFromEnum(FrameIndex.call_frame), |
| 710 | FrameAlloc.init(.{ .size = 0, .alignment = 1 }), | |
| 713 | FrameAlloc.init(.{ .size = 0, .alignment = .@"1" }), | |
| 711 | 714 | ); |
| 712 | 715 | |
| 713 | 716 | const fn_info = mod.typeToFunc(fn_type).?; |
| ... | ... | @@ -729,15 +732,21 @@ pub fn generate( |
| 729 | 732 | function.ret_mcv = call_info.return_value; |
| 730 | 733 | function.frame_allocs.set(@intFromEnum(FrameIndex.ret_addr), FrameAlloc.init(.{ |
| 731 | 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 | 737 | function.frame_allocs.set(@intFromEnum(FrameIndex.base_ptr), FrameAlloc.init(.{ |
| 735 | 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 | 744 | function.frame_allocs.set( |
| 739 | 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 | 752 | function.gen() catch |err| switch (err) { |
| ... | ... | @@ -2156,8 +2165,8 @@ fn setFrameLoc( |
| 2156 | 2165 | ) void { |
| 2157 | 2166 | const frame_i = @intFromEnum(frame_index); |
| 2158 | 2167 | if (aligned) { |
| 2159 | const alignment = @as(i32, 1) << self.frame_allocs.items(.abi_align)[frame_i]; | |
| 2160 | offset.* = mem.alignForward(i32, offset.*, alignment); | |
| 2168 | const alignment = self.frame_allocs.items(.abi_align)[frame_i]; | |
| 2169 | offset.* = @intCast(alignment.forward(@intCast(offset.*))); | |
| 2161 | 2170 | } |
| 2162 | 2171 | self.frame_locs.set(frame_i, .{ .base = base, .disp = offset.* }); |
| 2163 | 2172 | offset.* += self.frame_allocs.items(.abi_size)[frame_i]; |
| ... | ... | @@ -2179,7 +2188,7 @@ fn computeFrameLayout(self: *Self) !FrameLayout { |
| 2179 | 2188 | const SortContext = struct { |
| 2180 | 2189 | frame_align: @TypeOf(frame_align), |
| 2181 | 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 | 2194 | const sort_context = SortContext{ .frame_align = frame_align }; |
| ... | ... | @@ -2189,8 +2198,8 @@ fn computeFrameLayout(self: *Self) !FrameLayout { |
| 2189 | 2198 | const call_frame_align = frame_align[@intFromEnum(FrameIndex.call_frame)]; |
| 2190 | 2199 | const stack_frame_align = frame_align[@intFromEnum(FrameIndex.stack_frame)]; |
| 2191 | 2200 | const args_frame_align = frame_align[@intFromEnum(FrameIndex.args_frame)]; |
| 2192 | const needed_align = @max(call_frame_align, stack_frame_align); | |
| 2193 | const need_align_stack = needed_align > args_frame_align; | |
| 2201 | const needed_align = call_frame_align.max(stack_frame_align); | |
| 2202 | const need_align_stack = needed_align.compare(.gt, args_frame_align); | |
| 2194 | 2203 | |
| 2195 | 2204 | // Create list of registers to save in the prologue. |
| 2196 | 2205 | // TODO handle register classes |
| ... | ... | @@ -2214,21 +2223,21 @@ fn computeFrameLayout(self: *Self) !FrameLayout { |
| 2214 | 2223 | self.setFrameLoc(.stack_frame, .rsp, &rsp_offset, true); |
| 2215 | 2224 | for (stack_frame_order) |frame_index| self.setFrameLoc(frame_index, .rsp, &rsp_offset, true); |
| 2216 | 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 | 2227 | rsp_offset -= stack_frame_align_offset; |
| 2219 | 2228 | frame_size[@intFromEnum(FrameIndex.call_frame)] = |
| 2220 | 2229 | @intCast(rsp_offset - frame_offset[@intFromEnum(FrameIndex.stack_frame)]); |
| 2221 | 2230 | |
| 2222 | 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 | 2233 | .stack_adjust = @intCast(rsp_offset - frame_offset[@intFromEnum(FrameIndex.call_frame)]), |
| 2225 | 2234 | .save_reg_list = save_reg_list, |
| 2226 | 2235 | }; |
| 2227 | 2236 | } |
| 2228 | 2237 | |
| 2229 | fn getFrameAddrAlignment(self: *Self, frame_addr: FrameAddr) u32 { | |
| 2230 | const alloc_align = @as(u32, 1) << self.frame_allocs.get(@intFromEnum(frame_addr.index)).abi_align; | |
| 2231 | return @min(alloc_align, @as(u32, @bitCast(frame_addr.off)) & (alloc_align - 1)); | |
| 2238 | fn getFrameAddrAlignment(self: *Self, frame_addr: FrameAddr) Alignment { | |
| 2239 | const alloc_align = self.frame_allocs.get(@intFromEnum(frame_addr.index)).abi_align; | |
| 2240 | return @enumFromInt(@min(@intFromEnum(alloc_align), @ctz(frame_addr.off))); | |
| 2232 | 2241 | } |
| 2233 | 2242 | |
| 2234 | 2243 | fn getFrameAddrSize(self: *Self, frame_addr: FrameAddr) u32 { |
| ... | ... | @@ -2241,13 +2250,13 @@ fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex { |
| 2241 | 2250 | const frame_align = frame_allocs_slice.items(.abi_align); |
| 2242 | 2251 | |
| 2243 | 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 | 2255 | for (self.free_frame_indices.keys(), 0..) |frame_index, free_i| { |
| 2247 | 2256 | const abi_size = frame_size[@intFromEnum(frame_index)]; |
| 2248 | 2257 | if (abi_size != alloc.abi_size) continue; |
| 2249 | 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 | 2261 | _ = self.free_frame_indices.swapRemoveAt(free_i); |
| 2253 | 2262 | return frame_index; |
| ... | ... | @@ -2266,7 +2275,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !FrameIndex { |
| 2266 | 2275 | .size = math.cast(u32, val_ty.abiSize(mod)) orelse { |
| 2267 | 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 | 4275 | }; |
| 4267 | 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 | 4279 | // TODO reusing the operand |
| 4271 | 4280 | const reg = try self.copyToTmpRegister(ptr_union_ty, ptr); |
| 4272 | 4281 | try self.genBinOpMir( |
| ... | ... | @@ -4309,7 +4318,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 4309 | 4318 | switch (operand) { |
| 4310 | 4319 | .load_frame => |frame_addr| { |
| 4311 | 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 | 4322 | @intCast(layout.payload_size) |
| 4314 | 4323 | else |
| 4315 | 4324 | 0; |
| ... | ... | @@ -4321,7 +4330,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 4321 | 4330 | return self.fail("TODO implement get_union_tag for ABI larger than 8 bytes and operand {}", .{operand}); |
| 4322 | 4331 | }, |
| 4323 | 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 | 4334 | @intCast(layout.payload_size * 8) |
| 4326 | 4335 | else |
| 4327 | 4336 | 0; |
| ... | ... | @@ -5600,8 +5609,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 5600 | 5609 | const src_mcv = try self.resolveInst(operand); |
| 5601 | 5610 | const field_off: u32 = switch (container_ty.containerLayout(mod)) { |
| 5602 | 5611 | .Auto, .Extern => @intCast(container_ty.structFieldOffset(index, mod) * 8), |
| 5603 | .Packed => if (mod.typeToStruct(container_ty)) |struct_obj| | |
| 5604 | struct_obj.packedFieldBitOffset(mod, index) | |
| 5612 | .Packed => if (mod.typeToStruct(container_ty)) |struct_type| | |
| 5613 | mod.structPackedFieldBitOffset(struct_type, index) | |
| 5605 | 5614 | else |
| 5606 | 5615 | 0, |
| 5607 | 5616 | }; |
| ... | ... | @@ -8084,14 +8093,17 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 8084 | 8093 | // We need a properly aligned and sized call frame to be able to call this function. |
| 8085 | 8094 | { |
| 8086 | 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 | 8100 | const frame_allocs_slice = self.frame_allocs.slice(); |
| 8089 | 8101 | const stack_frame_size = |
| 8090 | 8102 | &frame_allocs_slice.items(.abi_size)[@intFromEnum(FrameIndex.call_frame)]; |
| 8091 | 8103 | stack_frame_size.* = @max(stack_frame_size.*, needed_call_frame.abi_size); |
| 8092 | 8104 | const stack_frame_align = |
| 8093 | 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 | 8109 | try self.spillEflagsIfOccupied(); |
| ... | ... | @@ -9944,7 +9956,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 9944 | 9956 | .indirect => try self.moveStrategy(ty, false), |
| 9945 | 9957 | .load_frame => |frame_addr| try self.moveStrategy( |
| 9946 | 9958 | ty, |
| 9947 | self.getFrameAddrAlignment(frame_addr) >= ty.abiAlignment(mod), | |
| 9959 | self.getFrameAddrAlignment(frame_addr).compare(.gte, ty.abiAlignment(mod)), | |
| 9948 | 9960 | ), |
| 9949 | 9961 | .lea_frame => .{ .move = .{ ._, .lea } }, |
| 9950 | 9962 | else => unreachable, |
| ... | ... | @@ -9973,10 +9985,8 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 9973 | 9985 | .base = .{ .reg = .ds }, |
| 9974 | 9986 | .disp = small_addr, |
| 9975 | 9987 | }); |
| 9976 | switch (try self.moveStrategy(ty, mem.isAlignedGeneric( | |
| 9977 | u32, | |
| 9988 | switch (try self.moveStrategy(ty, ty.abiAlignment(mod).check( | |
| 9978 | 9989 | @as(u32, @bitCast(small_addr)), |
| 9979 | ty.abiAlignment(mod), | |
| 9980 | 9990 | ))) { |
| 9981 | 9991 | .move => |tag| try self.asmRegisterMemory(tag, dst_alias, src_mem), |
| 9982 | 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 | 10152 | ); |
| 10143 | 10153 | const src_alias = registerAlias(src_reg, abi_size); |
| 10144 | 10154 | switch (try self.moveStrategy(ty, switch (base) { |
| 10145 | .none => mem.isAlignedGeneric( | |
| 10146 | u32, | |
| 10147 | @as(u32, @bitCast(disp)), | |
| 10148 | ty.abiAlignment(mod), | |
| 10149 | ), | |
| 10155 | .none => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))), | |
| 10150 | 10156 | .reg => |reg| switch (reg) { |
| 10151 | .es, .cs, .ss, .ds => mem.isAlignedGeneric( | |
| 10152 | u32, | |
| 10153 | @as(u32, @bitCast(disp)), | |
| 10154 | ty.abiAlignment(mod), | |
| 10155 | ), | |
| 10157 | .es, .cs, .ss, .ds => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))), | |
| 10156 | 10158 | else => false, |
| 10157 | 10159 | }, |
| 10158 | 10160 | .frame => |frame_index| self.getFrameAddrAlignment( |
| 10159 | 10161 | .{ .index = frame_index, .off = disp }, |
| 10160 | ) >= ty.abiAlignment(mod), | |
| 10162 | ).compare(.gte, ty.abiAlignment(mod)), | |
| 10161 | 10163 | })) { |
| 10162 | 10164 | .move => |tag| try self.asmMemoryRegister(tag, dst_mem, src_alias), |
| 10163 | 10165 | .insert_extract, .vex_insert_extract => |ie| try self.asmMemoryRegisterImmediate( |
| ... | ... | @@ -11079,7 +11081,7 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { |
| 11079 | 11081 | stack_frame_size.* = @max(stack_frame_size.*, needed_call_frame.abi_size); |
| 11080 | 11082 | const stack_frame_align = |
| 11081 | 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 | 11087 | try self.spillEflagsIfOccupied(); |
| ... | ... | @@ -11418,13 +11420,14 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 11418 | 11420 | const frame_index = |
| 11419 | 11421 | try self.allocFrameIndex(FrameAlloc.initType(result_ty, mod)); |
| 11420 | 11422 | if (result_ty.containerLayout(mod) == .Packed) { |
| 11421 | const struct_obj = mod.typeToStruct(result_ty).?; | |
| 11423 | const struct_type = mod.typeToStruct(result_ty).?; | |
| 11422 | 11424 | try self.genInlineMemset( |
| 11423 | 11425 | .{ .lea_frame = .{ .index = frame_index } }, |
| 11424 | 11426 | .{ .immediate = 0 }, |
| 11425 | 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 | 11431 | if ((try result_ty.structFieldValueComptime(mod, elem_i)) != null) continue; |
| 11429 | 11432 | |
| 11430 | 11433 | const elem_ty = result_ty.structFieldType(elem_i, mod); |
| ... | ... | @@ -11437,7 +11440,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 11437 | 11440 | } |
| 11438 | 11441 | const elem_abi_size: u32 = @intCast(elem_ty.abiSize(mod)); |
| 11439 | 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 | 11444 | const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size); |
| 11442 | 11445 | const elem_bit_off = elem_off % elem_abi_bits; |
| 11443 | 11446 | const elem_mcv = try self.resolveInst(elem); |
| ... | ... | @@ -11576,13 +11579,13 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void { |
| 11576 | 11579 | const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index); |
| 11577 | 11580 | const tag_int_val = try tag_val.intFromEnum(tag_ty, mod); |
| 11578 | 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 | 11583 | @intCast(layout.payload_size) |
| 11581 | 11584 | else |
| 11582 | 11585 | 0; |
| 11583 | 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 | 11589 | 0 |
| 11587 | 11590 | else |
| 11588 | 11591 | @intCast(layout.tag_size); |
| ... | ... | @@ -11823,7 +11826,7 @@ const CallMCValues = struct { |
| 11823 | 11826 | args: []MCValue, |
| 11824 | 11827 | return_value: InstTracking, |
| 11825 | 11828 | stack_byte_count: u31, |
| 11826 | stack_align: u31, | |
| 11829 | stack_align: Alignment, | |
| 11827 | 11830 | |
| 11828 | 11831 | fn deinit(self: *CallMCValues, func: *Self) void { |
| 11829 | 11832 | func.gpa.free(self.args); |
| ... | ... | @@ -11867,12 +11870,12 @@ fn resolveCallingConventionValues( |
| 11867 | 11870 | .Naked => { |
| 11868 | 11871 | assert(result.args.len == 0); |
| 11869 | 11872 | result.return_value = InstTracking.init(.unreach); |
| 11870 | result.stack_align = 8; | |
| 11873 | result.stack_align = .@"8"; | |
| 11871 | 11874 | }, |
| 11872 | 11875 | .C => { |
| 11873 | 11876 | var param_reg_i: usize = 0; |
| 11874 | 11877 | var param_sse_reg_i: usize = 0; |
| 11875 | result.stack_align = 16; | |
| 11878 | result.stack_align = .@"16"; | |
| 11876 | 11879 | |
| 11877 | 11880 | switch (self.target.os.tag) { |
| 11878 | 11881 | .windows => { |
| ... | ... | @@ -11957,7 +11960,7 @@ fn resolveCallingConventionValues( |
| 11957 | 11960 | } |
| 11958 | 11961 | |
| 11959 | 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 | 11964 | result.stack_byte_count = |
| 11962 | 11965 | mem.alignForward(u31, result.stack_byte_count, param_align); |
| 11963 | 11966 | arg.* = .{ .load_frame = .{ |
| ... | ... | @@ -11968,7 +11971,7 @@ fn resolveCallingConventionValues( |
| 11968 | 11971 | } |
| 11969 | 11972 | }, |
| 11970 | 11973 | .Unspecified => { |
| 11971 | result.stack_align = 16; | |
| 11974 | result.stack_align = .@"16"; | |
| 11972 | 11975 | |
| 11973 | 11976 | // Return values |
| 11974 | 11977 | if (ret_ty.zigTypeTag(mod) == .NoReturn) { |
| ... | ... | @@ -11997,7 +12000,7 @@ fn resolveCallingConventionValues( |
| 11997 | 12000 | continue; |
| 11998 | 12001 | } |
| 11999 | 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 | 12004 | result.stack_byte_count = |
| 12002 | 12005 | mem.alignForward(u31, result.stack_byte_count, param_align); |
| 12003 | 12006 | arg.* = .{ .load_frame = .{ |
| ... | ... | @@ -12010,7 +12013,7 @@ fn resolveCallingConventionValues( |
| 12010 | 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 | 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 | 210 | // it contains unaligned fields, it has class MEMORY" |
| 211 | 211 | // "If the size of the aggregate exceeds a single eightbyte, each is classified |
| 212 | 212 | // separately.". |
| 213 | const struct_type = mod.typeToStruct(ty).?; | |
| 213 | 214 | const ty_size = ty.abiSize(mod); |
| 214 | if (ty.containerLayout(mod) == .Packed) { | |
| 215 | if (struct_type.layout == .Packed) { | |
| 215 | 216 | assert(ty_size <= 128); |
| 216 | 217 | result[0] = .integer; |
| 217 | 218 | if (ty_size > 64) result[1] = .integer; |
| ... | ... | @@ -222,15 +223,13 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class { |
| 222 | 223 | |
| 223 | 224 | var result_i: usize = 0; // out of 8 |
| 224 | 225 | var byte_i: usize = 0; // out of 8 |
| 225 | const fields = ty.structFields(mod); | |
| 226 | for (fields.values()) |field| { | |
| 227 | if (field.abi_align != .none) { | |
| 228 | if (field.abi_align.toByteUnitsOptional().? < field.ty.abiAlignment(mod)) { | |
| 229 | return memory_class; | |
| 230 | } | |
| 231 | } | |
| 232 | const field_size = field.ty.abiSize(mod); | |
| 233 | const field_class_array = classifySystemV(field.ty, mod, .other); | |
| 226 | for (struct_type.field_types.get(ip), 0..) |field_ty_ip, i| { | |
| 227 | const field_ty = field_ty_ip.toType(); | |
| 228 | const field_align = struct_type.fieldAlign(ip, i); | |
| 229 | if (field_align != .none and field_align.compare(.lt, field_ty.abiAlignment(mod))) | |
| 230 | return memory_class; | |
| 231 | const field_size = field_ty.abiSize(mod); | |
| 232 | const field_class_array = classifySystemV(field_ty, mod, .other); | |
| 234 | 233 | const field_class = std.mem.sliceTo(&field_class_array, .none); |
| 235 | 234 | if (byte_i + field_size <= 8) { |
| 236 | 235 | // Combine this field with the previous one. |
| ... | ... | @@ -341,10 +340,11 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class { |
| 341 | 340 | return memory_class; |
| 342 | 341 | |
| 343 | 342 | for (union_obj.field_types.get(ip), 0..) |field_ty, field_index| { |
| 344 | if (union_obj.fieldAlign(ip, @intCast(field_index)).toByteUnitsOptional()) |a| { | |
| 345 | if (a < field_ty.toType().abiAlignment(mod)) { | |
| 346 | return memory_class; | |
| 347 | } | |
| 343 | const field_align = union_obj.fieldAlign(ip, @intCast(field_index)); | |
| 344 | if (field_align != .none and | |
| 345 | field_align.compare(.lt, field_ty.toType().abiAlignment(mod))) | |
| 346 | { | |
| 347 | return memory_class; | |
| 348 | 348 | } |
| 349 | 349 | // Combine this field with the previous one. |
| 350 | 350 | const field_class = classifySystemV(field_ty.toType(), mod, .other); |
| ... | ... | @@ -533,13 +533,3 @@ const Register = @import("bits.zig").Register; |
| 533 | 533 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; |
| 534 | 534 | const Type = @import("../../type.zig").Type; |
| 535 | 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 | 22 | const TypedValue = @import("TypedValue.zig"); |
| 23 | 23 | const Value = @import("value.zig").Value; |
| 24 | 24 | const Zir = @import("Zir.zig"); |
| 25 | const Alignment = InternPool.Alignment; | |
| 25 | 26 | |
| 26 | 27 | pub const Result = union(enum) { |
| 27 | 28 | /// The `code` parameter passed to `generateSymbol` has the value ok. |
| ... | ... | @@ -116,7 +117,8 @@ pub fn generateLazySymbol( |
| 116 | 117 | bin_file: *link.File, |
| 117 | 118 | src_loc: Module.SrcLoc, |
| 118 | 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 | 122 | code: *std.ArrayList(u8), |
| 121 | 123 | debug_output: DebugInfoOutput, |
| 122 | 124 | reloc_info: RelocInfo, |
| ... | ... | @@ -141,7 +143,7 @@ pub fn generateLazySymbol( |
| 141 | 143 | } |
| 142 | 144 | |
| 143 | 145 | if (lazy_sym.ty.isAnyError(mod)) { |
| 144 | alignment.* = 4; | |
| 146 | alignment.* = .@"4"; | |
| 145 | 147 | const err_names = mod.global_error_set.keys(); |
| 146 | 148 | mem.writeInt(u32, try code.addManyAsArray(4), @as(u32, @intCast(err_names.len)), endian); |
| 147 | 149 | var offset = code.items.len; |
| ... | ... | @@ -157,7 +159,7 @@ pub fn generateLazySymbol( |
| 157 | 159 | mem.writeInt(u32, code.items[offset..][0..4], @as(u32, @intCast(code.items.len)), endian); |
| 158 | 160 | return Result.ok; |
| 159 | 161 | } else if (lazy_sym.ty.zigTypeTag(mod) == .Enum) { |
| 160 | alignment.* = 1; | |
| 162 | alignment.* = .@"1"; | |
| 161 | 163 | for (lazy_sym.ty.enumFields(mod)) |tag_name_ip| { |
| 162 | 164 | const tag_name = mod.intern_pool.stringToSlice(tag_name_ip); |
| 163 | 165 | try code.ensureUnusedCapacity(tag_name.len + 1); |
| ... | ... | @@ -273,7 +275,7 @@ pub fn generateSymbol( |
| 273 | 275 | const abi_align = typed_value.ty.abiAlignment(mod); |
| 274 | 276 | |
| 275 | 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 | 279 | try code.writer().writeInt(u16, err_val, endian); |
| 278 | 280 | } |
| 279 | 281 | |
| ... | ... | @@ -291,7 +293,7 @@ pub fn generateSymbol( |
| 291 | 293 | .fail => |em| return .{ .fail = em }, |
| 292 | 294 | } |
| 293 | 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 | 297 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; |
| 296 | 298 | |
| 297 | 299 | if (padding > 0) { |
| ... | ... | @@ -300,11 +302,11 @@ pub fn generateSymbol( |
| 300 | 302 | } |
| 301 | 303 | |
| 302 | 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 | 306 | const begin = code.items.len; |
| 305 | 307 | try code.writer().writeInt(u16, err_val, endian); |
| 306 | 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 | 310 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; |
| 309 | 311 | |
| 310 | 312 | if (padding > 0) { |
| ... | ... | @@ -474,23 +476,18 @@ pub fn generateSymbol( |
| 474 | 476 | } |
| 475 | 477 | } |
| 476 | 478 | }, |
| 477 | .struct_type => |struct_type| { | |
| 478 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 479 | ||
| 480 | if (struct_obj.layout == .Packed) { | |
| 481 | const fields = struct_obj.fields.values(); | |
| 479 | .struct_type => |struct_type| switch (struct_type.layout) { | |
| 480 | .Packed => { | |
| 482 | 481 | const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse |
| 483 | 482 | return error.Overflow; |
| 484 | 483 | const current_pos = code.items.len; |
| 485 | 484 | try code.resize(current_pos + abi_size); |
| 486 | 485 | var bits: u16 = 0; |
| 487 | 486 | |
| 488 | for (fields, 0..) |field, index| { | |
| 489 | const field_ty = field.ty; | |
| 490 | ||
| 487 | for (struct_type.field_types.get(ip), 0..) |field_ty, index| { | |
| 491 | 488 | const field_val = switch (aggregate.storage) { |
| 492 | 489 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ |
| 493 | .ty = field_ty.toIntern(), | |
| 490 | .ty = field_ty, | |
| 494 | 491 | .storage = .{ .u64 = bytes[index] }, |
| 495 | 492 | } }), |
| 496 | 493 | .elems => |elems| elems[index], |
| ... | ... | @@ -499,48 +496,51 @@ pub fn generateSymbol( |
| 499 | 496 | |
| 500 | 497 | // pointer may point to a decl which must be marked used |
| 501 | 498 | // but can also result in a relocation. Therefore we handle those separately. |
| 502 | if (field_ty.zigTypeTag(mod) == .Pointer) { | |
| 503 | const field_size = math.cast(usize, field_ty.abiSize(mod)) orelse | |
| 499 | if (field_ty.toType().zigTypeTag(mod) == .Pointer) { | |
| 500 | const field_size = math.cast(usize, field_ty.toType().abiSize(mod)) orelse | |
| 504 | 501 | return error.Overflow; |
| 505 | 502 | var tmp_list = try std.ArrayList(u8).initCapacity(code.allocator, field_size); |
| 506 | 503 | defer tmp_list.deinit(); |
| 507 | 504 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 508 | .ty = field_ty, | |
| 505 | .ty = field_ty.toType(), | |
| 509 | 506 | .val = field_val.toValue(), |
| 510 | 507 | }, &tmp_list, debug_output, reloc_info)) { |
| 511 | 508 | .ok => @memcpy(code.items[current_pos..][0..tmp_list.items.len], tmp_list.items), |
| 512 | 509 | .fail => |em| return Result{ .fail = em }, |
| 513 | 510 | } |
| 514 | 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 | 518 | const struct_begin = code.items.len; |
| 521 | const fields = struct_obj.fields.values(); | |
| 522 | ||
| 523 | var it = typed_value.ty.iterateStructOffsets(mod); | |
| 519 | const field_types = struct_type.field_types.get(ip); | |
| 520 | const offsets = struct_type.offsets.get(ip); | |
| 524 | 521 | |
| 525 | while (it.next()) |field_offset| { | |
| 526 | const field_ty = fields[field_offset.field].ty; | |
| 527 | ||
| 528 | if (!field_ty.hasRuntimeBits(mod)) continue; | |
| 522 | var it = struct_type.iterateRuntimeOrder(ip); | |
| 523 | while (it.next()) |field_index| { | |
| 524 | const field_ty = field_types[field_index]; | |
| 525 | if (!field_ty.toType().hasRuntimeBits(mod)) continue; | |
| 529 | 526 | |
| 530 | 527 | const field_val = switch (ip.indexToKey(typed_value.val.toIntern()).aggregate.storage) { |
| 531 | 528 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ |
| 532 | .ty = field_ty.toIntern(), | |
| 533 | .storage = .{ .u64 = bytes[field_offset.field] }, | |
| 529 | .ty = field_ty, | |
| 530 | .storage = .{ .u64 = bytes[field_index] }, | |
| 534 | 531 | } }), |
| 535 | .elems => |elems| elems[field_offset.field], | |
| 532 | .elems => |elems| elems[field_index], | |
| 536 | 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 | 540 | if (padding > 0) try code.appendNTimes(0, padding); |
| 541 | 541 | |
| 542 | 542 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 543 | .ty = field_ty, | |
| 543 | .ty = field_ty.toType(), | |
| 544 | 544 | .val = field_val.toValue(), |
| 545 | 545 | }, code, debug_output, reloc_info)) { |
| 546 | 546 | .ok => {}, |
| ... | ... | @@ -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 | 559 | if (padding > 0) try code.appendNTimes(0, padding); |
| 553 | } | |
| 560 | }, | |
| 554 | 561 | }, |
| 555 | 562 | else => unreachable, |
| 556 | 563 | }, |
| ... | ... | @@ -565,7 +572,7 @@ pub fn generateSymbol( |
| 565 | 572 | } |
| 566 | 573 | |
| 567 | 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 | 576 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 570 | 577 | .ty = typed_value.ty.unionTagType(mod).?, |
| 571 | 578 | .val = un.tag.toValue(), |
| ... | ... | @@ -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 | 606 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 600 | 607 | .ty = union_obj.enum_tag_ty.toType(), |
| 601 | 608 | .val = un.tag.toValue(), |
| ... | ... | @@ -695,9 +702,9 @@ fn lowerParentPtr( |
| 695 | 702 | @intCast(field.index), |
| 696 | 703 | mod, |
| 697 | 704 | )), |
| 698 | .Packed => if (mod.typeToStruct(base_type.toType())) |struct_obj| | |
| 699 | math.divExact(u16, struct_obj.packedFieldBitOffset( | |
| 700 | mod, | |
| 705 | .Packed => if (mod.typeToStruct(base_type.toType())) |struct_type| | |
| 706 | math.divExact(u16, mod.structPackedFieldBitOffset( | |
| 707 | struct_type, | |
| 701 | 708 | @intCast(field.index), |
| 702 | 709 | ), 8) catch |err| switch (err) { |
| 703 | 710 | error.UnexpectedRemainder => 0, |
| ... | ... | @@ -844,12 +851,12 @@ fn genDeclRef( |
| 844 | 851 | // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`? |
| 845 | 852 | if (tv.ty.castPtrToFn(mod)) |fn_ty| { |
| 846 | 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 | 856 | } else if (tv.ty.zigTypeTag(mod) == .Pointer) { |
| 850 | 857 | const elem_ty = tv.ty.elemType2(mod); |
| 851 | 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 | 1043 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return 0; |
| 1037 | 1044 | const payload_align = payload_ty.abiAlignment(mod); |
| 1038 | 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 | 1047 | return 0; |
| 1041 | 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 | 1054 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return 0; |
| 1048 | 1055 | const payload_align = payload_ty.abiAlignment(mod); |
| 1049 | 1056 | const error_align = Type.anyerror.abiAlignment(mod); |
| 1050 | if (payload_align >= error_align and payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 1051 | return mem.alignForward(u64, payload_ty.abiSize(mod), error_align); | |
| 1057 | if (payload_align.compare(.gte, error_align) and payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 1058 | return error_align.forward(payload_ty.abiSize(mod)); | |
| 1052 | 1059 | } else { |
| 1053 | 1060 | return 0; |
| 1054 | 1061 | } |
src/codegen/c.zig+138-140| ... | ... | @@ -17,6 +17,7 @@ const LazySrcLoc = Module.LazySrcLoc; |
| 17 | 17 | const Air = @import("../Air.zig"); |
| 18 | 18 | const Liveness = @import("../Liveness.zig"); |
| 19 | 19 | const InternPool = @import("../InternPool.zig"); |
| 20 | const Alignment = InternPool.Alignment; | |
| 20 | 21 | |
| 21 | 22 | const BigIntLimb = std.math.big.Limb; |
| 22 | 23 | const BigInt = std.math.big.int; |
| ... | ... | @@ -292,7 +293,7 @@ pub const Function = struct { |
| 292 | 293 | |
| 293 | 294 | const result: CValue = if (lowersToArray(ty, mod)) result: { |
| 294 | 295 | const writer = f.object.code_header.writer(); |
| 295 | const alignment = 0; | |
| 296 | const alignment: Alignment = .none; | |
| 296 | 297 | const decl_c_value = try f.allocLocalValue(ty, alignment); |
| 297 | 298 | const gpa = f.object.dg.gpa; |
| 298 | 299 | try f.allocs.put(gpa, decl_c_value.new_local, false); |
| ... | ... | @@ -318,25 +319,25 @@ pub const Function = struct { |
| 318 | 319 | /// Skips the reuse logic. This function should be used for any persistent allocation, i.e. |
| 319 | 320 | /// those which go into `allocs`. This function does not add the resulting local into `allocs`; |
| 320 | 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 | 323 | const mod = f.object.dg.module; |
| 323 | 324 | const gpa = f.object.dg.gpa; |
| 324 | 325 | try f.locals.append(gpa, .{ |
| 325 | 326 | .cty_idx = try f.typeToIndex(ty, .complete), |
| 326 | 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 | 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 | 334 | log.debug("%{d}: allocating t{d}", .{ inst, result.new_local }); |
| 334 | 335 | return result; |
| 335 | 336 | } |
| 336 | 337 | |
| 337 | 338 | /// Only allocates the local; does not print anything. Will attempt to re-use locals, so should |
| 338 | 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 | 341 | const mod = f.object.dg.module; |
| 341 | 342 | if (f.free_locals_map.getPtr(.{ |
| 342 | 343 | .cty_idx = try f.typeToIndex(ty, .complete), |
| ... | ... | @@ -1299,139 +1300,134 @@ pub const DeclGen = struct { |
| 1299 | 1300 | } |
| 1300 | 1301 | try writer.writeByte('}'); |
| 1301 | 1302 | }, |
| 1302 | .struct_type => |struct_type| { | |
| 1303 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 1304 | switch (struct_obj.layout) { | |
| 1305 | .Auto, .Extern => { | |
| 1306 | if (!location.isInitializer()) { | |
| 1303 | .struct_type => |struct_type| switch (struct_type.layout) { | |
| 1304 | .Auto, .Extern => { | |
| 1305 | if (!location.isInitializer()) { | |
| 1306 | try writer.writeByte('('); | |
| 1307 | try dg.renderType(writer, ty); | |
| 1308 | try writer.writeByte(')'); | |
| 1309 | } | |
| 1310 | ||
| 1311 | try writer.writeByte('{'); | |
| 1312 | var empty = true; | |
| 1313 | for (0..struct_type.field_types.len) |field_i| { | |
| 1314 | const field_ty = struct_type.field_types.get(ip)[field_i].toType(); | |
| 1315 | if (struct_type.fieldIsComptime(ip, field_i)) continue; | |
| 1316 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 1317 | ||
| 1318 | if (!empty) try writer.writeByte(','); | |
| 1319 | const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) { | |
| 1320 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ | |
| 1321 | .ty = field_ty.toIntern(), | |
| 1322 | .storage = .{ .u64 = bytes[field_i] }, | |
| 1323 | } }), | |
| 1324 | .elems => |elems| elems[field_i], | |
| 1325 | .repeated_elem => |elem| elem, | |
| 1326 | }; | |
| 1327 | try dg.renderValue(writer, field_ty, field_val.toValue(), initializer_type); | |
| 1328 | ||
| 1329 | empty = false; | |
| 1330 | } | |
| 1331 | try writer.writeByte('}'); | |
| 1332 | }, | |
| 1333 | .Packed => { | |
| 1334 | const int_info = ty.intInfo(mod); | |
| 1335 | ||
| 1336 | const bits = Type.smallestUnsignedBits(int_info.bits - 1); | |
| 1337 | const bit_offset_ty = try mod.intType(.unsigned, bits); | |
| 1338 | const field_types = struct_type.field_types.get(ip); | |
| 1339 | ||
| 1340 | var bit_offset: u64 = 0; | |
| 1341 | var eff_num_fields: usize = 0; | |
| 1342 | ||
| 1343 | for (field_types) |field_ty| { | |
| 1344 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 1345 | eff_num_fields += 1; | |
| 1346 | } | |
| 1347 | ||
| 1348 | if (eff_num_fields == 0) { | |
| 1349 | try writer.writeByte('('); | |
| 1350 | try dg.renderValue(writer, ty, Value.undef, initializer_type); | |
| 1351 | try writer.writeByte(')'); | |
| 1352 | } else if (ty.bitSize(mod) > 64) { | |
| 1353 | // zig_or_u128(zig_or_u128(zig_shl_u128(a, a_off), zig_shl_u128(b, b_off)), zig_shl_u128(c, c_off)) | |
| 1354 | var num_or = eff_num_fields - 1; | |
| 1355 | while (num_or > 0) : (num_or -= 1) { | |
| 1356 | try writer.writeAll("zig_or_"); | |
| 1357 | try dg.renderTypeForBuiltinFnName(writer, ty); | |
| 1307 | 1358 | try writer.writeByte('('); |
| 1308 | try dg.renderType(writer, ty); | |
| 1309 | try writer.writeByte(')'); | |
| 1310 | 1359 | } |
| 1311 | 1360 | |
| 1312 | try writer.writeByte('{'); | |
| 1313 | var empty = true; | |
| 1314 | for (struct_obj.fields.values(), 0..) |field, field_i| { | |
| 1315 | if (field.is_comptime) continue; | |
| 1316 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 1361 | var eff_index: usize = 0; | |
| 1362 | var needs_closing_paren = false; | |
| 1363 | for (field_types, 0..) |field_ty, field_i| { | |
| 1364 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 1317 | 1365 | |
| 1318 | if (!empty) try writer.writeByte(','); | |
| 1319 | 1366 | const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) { |
| 1320 | 1367 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ |
| 1321 | .ty = field.ty.toIntern(), | |
| 1368 | .ty = field_ty, | |
| 1322 | 1369 | .storage = .{ .u64 = bytes[field_i] }, |
| 1323 | 1370 | } }), |
| 1324 | 1371 | .elems => |elems| elems[field_i], |
| 1325 | 1372 | .repeated_elem => |elem| elem, |
| 1326 | 1373 | }; |
| 1327 | try dg.renderValue(writer, field.ty, field_val.toValue(), initializer_type); | |
| 1328 | ||
| 1329 | empty = false; | |
| 1330 | } | |
| 1331 | try writer.writeByte('}'); | |
| 1332 | }, | |
| 1333 | .Packed => { | |
| 1334 | const int_info = ty.intInfo(mod); | |
| 1335 | ||
| 1336 | const bits = Type.smallestUnsignedBits(int_info.bits - 1); | |
| 1337 | const bit_offset_ty = try mod.intType(.unsigned, bits); | |
| 1338 | ||
| 1339 | var bit_offset: u64 = 0; | |
| 1340 | var eff_num_fields: usize = 0; | |
| 1374 | const cast_context = IntCastContext{ .value = .{ .value = field_val.toValue() } }; | |
| 1375 | if (bit_offset != 0) { | |
| 1376 | try writer.writeAll("zig_shl_"); | |
| 1377 | try dg.renderTypeForBuiltinFnName(writer, ty); | |
| 1378 | try writer.writeByte('('); | |
| 1379 | try dg.renderIntCast(writer, ty, cast_context, field_ty.toType(), .FunctionArgument); | |
| 1380 | try writer.writeAll(", "); | |
| 1381 | const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset); | |
| 1382 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | |
| 1383 | try writer.writeByte(')'); | |
| 1384 | } else { | |
| 1385 | try dg.renderIntCast(writer, ty, cast_context, field_ty.toType(), .FunctionArgument); | |
| 1386 | } | |
| 1341 | 1387 | |
| 1342 | for (struct_obj.fields.values()) |field| { | |
| 1343 | if (field.is_comptime) continue; | |
| 1344 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 1388 | if (needs_closing_paren) try writer.writeByte(')'); | |
| 1389 | if (eff_index != eff_num_fields - 1) try writer.writeAll(", "); | |
| 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 | 1403 | try writer.writeByte('('); |
| 1351 | try dg.renderValue(writer, ty, Value.undef, initializer_type); | |
| 1404 | try dg.renderType(writer, ty); | |
| 1352 | 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; | |
| 1363 | var needs_closing_paren = false; | |
| 1364 | for (struct_obj.fields.values(), 0..) |field, field_i| { | |
| 1365 | if (field.is_comptime) continue; | |
| 1366 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 1367 | ||
| 1368 | const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) { | |
| 1369 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ | |
| 1370 | .ty = field.ty.toIntern(), | |
| 1371 | .storage = .{ .u64 = bytes[field_i] }, | |
| 1372 | } }), | |
| 1373 | .elems => |elems| elems[field_i], | |
| 1374 | .repeated_elem => |elem| elem, | |
| 1375 | }; | |
| 1376 | const cast_context = IntCastContext{ .value = .{ .value = field_val.toValue() } }; | |
| 1377 | if (bit_offset != 0) { | |
| 1378 | try writer.writeAll("zig_shl_"); | |
| 1379 | try dg.renderTypeForBuiltinFnName(writer, ty); | |
| 1380 | try writer.writeByte('('); | |
| 1381 | try dg.renderIntCast(writer, ty, cast_context, field.ty, .FunctionArgument); | |
| 1382 | try writer.writeAll(", "); | |
| 1383 | const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset); | |
| 1384 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | |
| 1385 | try writer.writeByte(')'); | |
| 1386 | } else { | |
| 1387 | try dg.renderIntCast(writer, ty, cast_context, field.ty, .FunctionArgument); | |
| 1388 | } | |
| 1389 | ||
| 1390 | if (needs_closing_paren) try writer.writeByte(')'); | |
| 1391 | if (eff_index != eff_num_fields - 1) try writer.writeAll(", "); | |
| 1392 | ||
| 1393 | bit_offset += field.ty.bitSize(mod); | |
| 1394 | needs_closing_paren = true; | |
| 1395 | eff_index += 1; | |
| 1396 | } | |
| 1397 | } else { | |
| 1398 | try writer.writeByte('('); | |
| 1399 | // a << a_off | b << b_off | c << c_off | |
| 1400 | var empty = true; | |
| 1401 | for (struct_obj.fields.values(), 0..) |field, field_i| { | |
| 1402 | if (field.is_comptime) continue; | |
| 1403 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 1404 | ||
| 1405 | if (!empty) try writer.writeAll(" | "); | |
| 1406 | try writer.writeByte('('); | |
| 1407 | try dg.renderType(writer, ty); | |
| 1408 | try writer.writeByte(')'); | |
| 1407 | const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) { | |
| 1408 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ | |
| 1409 | .ty = field_ty, | |
| 1410 | .storage = .{ .u64 = bytes[field_i] }, | |
| 1411 | } }), | |
| 1412 | .elems => |elems| elems[field_i], | |
| 1413 | .repeated_elem => |elem| elem, | |
| 1414 | }; | |
| 1409 | 1415 | |
| 1410 | const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) { | |
| 1411 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ | |
| 1412 | .ty = field.ty.toIntern(), | |
| 1413 | .storage = .{ .u64 = bytes[field_i] }, | |
| 1414 | } }), | |
| 1415 | .elems => |elems| elems[field_i], | |
| 1416 | .repeated_elem => |elem| elem, | |
| 1417 | }; | |
| 1418 | ||
| 1419 | if (bit_offset != 0) { | |
| 1420 | try dg.renderValue(writer, field.ty, field_val.toValue(), .Other); | |
| 1421 | try writer.writeAll(" << "); | |
| 1422 | const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset); | |
| 1423 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | |
| 1424 | } else { | |
| 1425 | try dg.renderValue(writer, field.ty, field_val.toValue(), .Other); | |
| 1426 | } | |
| 1427 | ||
| 1428 | bit_offset += field.ty.bitSize(mod); | |
| 1429 | empty = false; | |
| 1416 | if (bit_offset != 0) { | |
| 1417 | try dg.renderValue(writer, field_ty.toType(), field_val.toValue(), .Other); | |
| 1418 | try writer.writeAll(" << "); | |
| 1419 | const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset); | |
| 1420 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | |
| 1421 | } else { | |
| 1422 | try dg.renderValue(writer, field_ty.toType(), field_val.toValue(), .Other); | |
| 1430 | 1423 | } |
| 1431 | try writer.writeByte(')'); | |
| 1424 | ||
| 1425 | bit_offset += field_ty.toType().bitSize(mod); | |
| 1426 | empty = false; | |
| 1432 | 1427 | } |
| 1433 | }, | |
| 1434 | } | |
| 1428 | try writer.writeByte(')'); | |
| 1429 | } | |
| 1430 | }, | |
| 1435 | 1431 | }, |
| 1436 | 1432 | else => unreachable, |
| 1437 | 1433 | }, |
| ... | ... | @@ -1723,7 +1719,7 @@ pub const DeclGen = struct { |
| 1723 | 1719 | ty: Type, |
| 1724 | 1720 | name: CValue, |
| 1725 | 1721 | qualifiers: CQualifiers, |
| 1726 | alignment: u64, | |
| 1722 | alignment: Alignment, | |
| 1727 | 1723 | kind: CType.Kind, |
| 1728 | 1724 | ) error{ OutOfMemory, AnalysisFail }!void { |
| 1729 | 1725 | const mod = dg.module; |
| ... | ... | @@ -1854,7 +1850,7 @@ pub const DeclGen = struct { |
| 1854 | 1850 | decl.ty, |
| 1855 | 1851 | .{ .decl = decl_index }, |
| 1856 | 1852 | CQualifiers.init(.{ .@"const" = variable.is_const }), |
| 1857 | @as(u32, @intCast(decl.alignment.toByteUnits(0))), | |
| 1853 | decl.alignment, | |
| 1858 | 1854 | .complete, |
| 1859 | 1855 | ); |
| 1860 | 1856 | try fwd_decl_writer.writeAll(";\n"); |
| ... | ... | @@ -2460,7 +2456,7 @@ pub fn genErrDecls(o: *Object) !void { |
| 2460 | 2456 | } }); |
| 2461 | 2457 | |
| 2462 | 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 | 2460 | try writer.writeAll(" = "); |
| 2465 | 2461 | try o.dg.renderValue(writer, name_ty, name_val.toValue(), .StaticInitializer); |
| 2466 | 2462 | try writer.writeAll(";\n"); |
| ... | ... | @@ -2472,7 +2468,7 @@ pub fn genErrDecls(o: *Object) !void { |
| 2472 | 2468 | }); |
| 2473 | 2469 | |
| 2474 | 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 | 2472 | try writer.writeAll(" = {"); |
| 2477 | 2473 | for (mod.global_error_set.keys(), 0..) |name_nts, value| { |
| 2478 | 2474 | const name = mod.intern_pool.stringToSlice(name_nts); |
| ... | ... | @@ -2523,7 +2519,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { |
| 2523 | 2519 | try w.writeByte(' '); |
| 2524 | 2520 | try w.writeAll(fn_name); |
| 2525 | 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 | 2523 | try w.writeAll(") {\n switch (tag) {\n"); |
| 2528 | 2524 | for (enum_ty.enumFields(mod), 0..) |name_ip, index_usize| { |
| 2529 | 2525 | const index = @as(u32, @intCast(index_usize)); |
| ... | ... | @@ -2546,7 +2542,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { |
| 2546 | 2542 | try w.print(" case {}: {{\n static ", .{ |
| 2547 | 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 | 2546 | try w.writeAll(" = "); |
| 2551 | 2547 | try o.dg.renderValue(w, name_ty, name_val.toValue(), .Initializer); |
| 2552 | 2548 | try w.writeAll(";\n return ("); |
| ... | ... | @@ -2706,7 +2702,7 @@ pub fn genDecl(o: *Object) !void { |
| 2706 | 2702 | if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage "); |
| 2707 | 2703 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| |
| 2708 | 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 | 2706 | if (decl.@"linksection" != .none) try w.writeAll(", read, write)"); |
| 2711 | 2707 | try w.writeAll(" = "); |
| 2712 | 2708 | try o.dg.renderValue(w, tv.ty, variable.init.toValue(), .StaticInitializer); |
| ... | ... | @@ -2717,14 +2713,14 @@ pub fn genDecl(o: *Object) !void { |
| 2717 | 2713 | const fwd_decl_writer = o.dg.fwd_decl.writer(); |
| 2718 | 2714 | |
| 2719 | 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 | 2717 | try fwd_decl_writer.writeAll(";\n"); |
| 2722 | 2718 | |
| 2723 | 2719 | const w = o.writer(); |
| 2724 | 2720 | if (!is_global) try w.writeAll("static "); |
| 2725 | 2721 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| |
| 2726 | 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 | 2724 | if (decl.@"linksection" != .none) try w.writeAll(", read)"); |
| 2729 | 2725 | try w.writeAll(" = "); |
| 2730 | 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 | 3349 | |
| 3354 | 3350 | try reap(f, inst, &.{ty_op.operand}); |
| 3355 | 3351 | |
| 3356 | const is_aligned = if (ptr_info.flags.alignment.toByteUnitsOptional()) |alignment| | |
| 3357 | alignment >= src_ty.abiAlignment(mod) | |
| 3352 | const is_aligned = if (ptr_info.flags.alignment != .none) | |
| 3353 | ptr_info.flags.alignment.compare(.gte, src_ty.abiAlignment(mod)) | |
| 3358 | 3354 | else |
| 3359 | 3355 | true; |
| 3360 | 3356 | const is_array = lowersToArray(src_ty, mod); |
| ... | ... | @@ -3625,8 +3621,8 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 3625 | 3621 | return .none; |
| 3626 | 3622 | } |
| 3627 | 3623 | |
| 3628 | const is_aligned = if (ptr_info.flags.alignment.toByteUnitsOptional()) |alignment| | |
| 3629 | alignment >= src_ty.abiAlignment(mod) | |
| 3624 | const is_aligned = if (ptr_info.flags.alignment != .none) | |
| 3625 | ptr_info.flags.alignment.compare(.gte, src_ty.abiAlignment(mod)) | |
| 3630 | 3626 | else |
| 3631 | 3627 | true; |
| 3632 | 3628 | const is_array = lowersToArray(ptr_info.child.toType(), mod); |
| ... | ... | @@ -4847,7 +4843,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4847 | 4843 | if (is_reg) { |
| 4848 | 4844 | const output_ty = if (output == .none) inst_ty else f.typeOf(output).childType(mod); |
| 4849 | 4845 | try writer.writeAll("register "); |
| 4850 | const alignment = 0; | |
| 4846 | const alignment: Alignment = .none; | |
| 4851 | 4847 | const local_value = try f.allocLocalValue(output_ty, alignment); |
| 4852 | 4848 | try f.allocs.put(gpa, local_value.new_local, false); |
| 4853 | 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 | 4876 | if (asmInputNeedsLocal(f, constraint, input_val)) { |
| 4881 | 4877 | const input_ty = f.typeOf(input); |
| 4882 | 4878 | if (is_reg) try writer.writeAll("register "); |
| 4883 | const alignment = 0; | |
| 4879 | const alignment: Alignment = .none; | |
| 4884 | 4880 | const local_value = try f.allocLocalValue(input_ty, alignment); |
| 4885 | 4881 | try f.allocs.put(gpa, local_value.new_local, false); |
| 4886 | 4882 | try f.object.dg.renderTypeAndName(writer, input_ty, local_value, Const, alignment, .complete); |
| ... | ... | @@ -5230,7 +5226,8 @@ fn fieldLocation( |
| 5230 | 5226 | const container_ty = container_ptr_ty.childType(mod); |
| 5231 | 5227 | return switch (container_ty.zigTypeTag(mod)) { |
| 5232 | 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 | 5231 | if (container_ty.structFieldIsComptime(next_field_index, mod)) continue; |
| 5235 | 5232 | const field_ty = container_ty.structFieldType(next_field_index, mod); |
| 5236 | 5233 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| ... | ... | @@ -5238,7 +5235,7 @@ fn fieldLocation( |
| 5238 | 5235 | break .{ .field = if (container_ty.isSimpleTuple(mod)) |
| 5239 | 5236 | .{ .field = next_field_index } |
| 5240 | 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 | 5239 | } else if (container_ty.hasRuntimeBitsIgnoreComptime(mod)) .end else .begin, |
| 5243 | 5240 | .Packed => if (field_ptr_ty.ptrInfo(mod).packed_offset.host_size == 0) |
| 5244 | 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 | 5422 | .Auto, .Extern => if (struct_ty.isSimpleTuple(mod)) |
| 5426 | 5423 | .{ .field = extra.field_index } |
| 5427 | 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 | 5426 | .Packed => { |
| 5430 | const struct_obj = mod.typeToStruct(struct_ty).?; | |
| 5427 | const struct_type = mod.typeToStruct(struct_ty).?; | |
| 5431 | 5428 | const int_info = struct_ty.intInfo(mod); |
| 5432 | 5429 | |
| 5433 | 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 | 5433 | const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset); |
| 5437 | 5434 | |
| 5438 | 5435 | const field_int_signedness = if (inst_ty.isAbiInt(mod)) |
| ... | ... | @@ -5487,7 +5484,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5487 | 5484 | .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len == 0) |
| 5488 | 5485 | .{ .field = extra.field_index } |
| 5489 | 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 | 5489 | .union_type => |union_type| field_name: { |
| 5493 | 5490 | const union_obj = ip.loadUnionType(union_type); |
| ... | ... | @@ -6820,7 +6817,8 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6820 | 6817 | } |
| 6821 | 6818 | }, |
| 6822 | 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 | 6822 | if (inst_ty.structFieldIsComptime(field_i, mod)) continue; |
| 6825 | 6823 | const field_ty = inst_ty.structFieldType(field_i, mod); |
| 6826 | 6824 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| ... | ... | @@ -6829,7 +6827,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6829 | 6827 | try f.writeCValueMember(writer, local, if (inst_ty.isSimpleTuple(mod)) |
| 6830 | 6828 | .{ .field = field_i } |
| 6831 | 6829 | else |
| 6832 | .{ .identifier = ip.stringToSlice(inst_ty.structFieldName(field_i, mod)) }); | |
| 6830 | .{ .identifier = ip.stringToSlice(inst_ty.legacyStructFieldName(field_i, mod)) }); | |
| 6833 | 6831 | try a.assign(f, writer); |
| 6834 | 6832 | try f.writeCValue(writer, element, .Other); |
| 6835 | 6833 | try a.end(f, writer); |
src/codegen/c/type.zig+24-15| ... | ... | @@ -283,14 +283,20 @@ pub const CType = extern union { |
| 283 | 283 | @"align": Alignment, |
| 284 | 284 | abi: Alignment, |
| 285 | 285 | |
| 286 | pub fn init(alignment: u64, abi_alignment: u32) AlignAs { | |
| 287 | const @"align" = Alignment.fromByteUnits(alignment); | |
| 288 | const abi_align = Alignment.fromNonzeroByteUnits(abi_alignment); | |
| 286 | pub fn init(@"align": Alignment, abi_align: Alignment) AlignAs { | |
| 287 | assert(abi_align != .none); | |
| 289 | 288 | return .{ |
| 290 | 289 | .@"align" = if (@"align" != .none) @"align" else abi_align, |
| 291 | 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 | 300 | pub fn abiAlign(ty: Type, mod: *Module) AlignAs { |
| 295 | 301 | const abi_align = ty.abiAlignment(mod); |
| 296 | 302 | return init(abi_align, abi_align); |
| ... | ... | @@ -1360,6 +1366,7 @@ pub const CType = extern union { |
| 1360 | 1366 | |
| 1361 | 1367 | pub fn initType(self: *@This(), ty: Type, kind: Kind, lookup: Lookup) !void { |
| 1362 | 1368 | const mod = lookup.getModule(); |
| 1369 | const ip = &mod.intern_pool; | |
| 1363 | 1370 | |
| 1364 | 1371 | self.* = undefined; |
| 1365 | 1372 | if (!ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) |
| ... | ... | @@ -1382,12 +1389,12 @@ pub const CType = extern union { |
| 1382 | 1389 | .array => switch (kind) { |
| 1383 | 1390 | .forward, .complete, .global => { |
| 1384 | 1391 | const abi_size = ty.abiSize(mod); |
| 1385 | const abi_align = ty.abiAlignment(mod); | |
| 1392 | const abi_align = ty.abiAlignment(mod).toByteUnits(0); | |
| 1386 | 1393 | self.storage = .{ .seq = .{ .base = .{ .tag = .array }, .data = .{ |
| 1387 | 1394 | .len = @divExact(abi_size, abi_align), |
| 1388 | 1395 | .elem_type = tagFromIntInfo(.{ |
| 1389 | 1396 | .signedness = .unsigned, |
| 1390 | .bits = @as(u16, @intCast(abi_align * 8)), | |
| 1397 | .bits = @intCast(abi_align * 8), | |
| 1391 | 1398 | }).toIndex(), |
| 1392 | 1399 | } } }; |
| 1393 | 1400 | self.value = .{ .cty = initPayload(&self.storage.seq) }; |
| ... | ... | @@ -1488,10 +1495,10 @@ pub const CType = extern union { |
| 1488 | 1495 | }, |
| 1489 | 1496 | |
| 1490 | 1497 | .Struct, .Union => |zig_ty_tag| if (ty.containerLayout(mod) == .Packed) { |
| 1491 | if (mod.typeToStruct(ty)) |struct_obj| { | |
| 1492 | try self.initType(struct_obj.backing_int_ty, kind, lookup); | |
| 1498 | if (mod.typeToPackedStruct(ty)) |packed_struct| { | |
| 1499 | try self.initType(packed_struct.backingIntType(ip).toType(), kind, lookup); | |
| 1493 | 1500 | } else { |
| 1494 | const bits = @as(u16, @intCast(ty.bitSize(mod))); | |
| 1501 | const bits: u16 = @intCast(ty.bitSize(mod)); | |
| 1495 | 1502 | const int_ty = try mod.intType(.unsigned, bits); |
| 1496 | 1503 | try self.initType(int_ty, kind, lookup); |
| 1497 | 1504 | } |
| ... | ... | @@ -1722,7 +1729,6 @@ pub const CType = extern union { |
| 1722 | 1729 | |
| 1723 | 1730 | .Fn => { |
| 1724 | 1731 | const info = mod.typeToFunc(ty).?; |
| 1725 | const ip = &mod.intern_pool; | |
| 1726 | 1732 | if (!info.is_generic) { |
| 1727 | 1733 | if (lookup.isMutable()) { |
| 1728 | 1734 | const param_kind: Kind = switch (kind) { |
| ... | ... | @@ -1947,7 +1953,8 @@ pub const CType = extern union { |
| 1947 | 1953 | |
| 1948 | 1954 | const fields_pl = try arena.alloc(Payload.Fields.Field, c_fields_len); |
| 1949 | 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 | 1958 | const field_ty = ty.structFieldType(field_i, mod); |
| 1952 | 1959 | if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or |
| 1953 | 1960 | !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| ... | ... | @@ -1958,7 +1965,7 @@ pub const CType = extern union { |
| 1958 | 1965 | std.fmt.allocPrintZ(arena, "f{}", .{field_i}) |
| 1959 | 1966 | else |
| 1960 | 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 | 1969 | .Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i], |
| 1963 | 1970 | else => unreachable, |
| 1964 | 1971 | })), |
| ... | ... | @@ -2091,7 +2098,8 @@ pub const CType = extern union { |
| 2091 | 2098 | .Struct => ty.structFieldCount(mod), |
| 2092 | 2099 | .Union => mod.typeToUnion(ty).?.field_names.len, |
| 2093 | 2100 | else => unreachable, |
| 2094 | }) |field_i| { | |
| 2101 | }) |field_i_usize| { | |
| 2102 | const field_i: u32 = @intCast(field_i_usize); | |
| 2095 | 2103 | const field_ty = ty.structFieldType(field_i, mod); |
| 2096 | 2104 | if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or |
| 2097 | 2105 | !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| ... | ... | @@ -2110,7 +2118,7 @@ pub const CType = extern union { |
| 2110 | 2118 | std.fmt.bufPrintZ(&name_buf, "f{}", .{field_i}) catch unreachable |
| 2111 | 2119 | else |
| 2112 | 2120 | ip.stringToSlice(switch (zig_ty_tag) { |
| 2113 | .Struct => ty.structFieldName(field_i, mod), | |
| 2121 | .Struct => ty.legacyStructFieldName(field_i, mod), | |
| 2114 | 2122 | .Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i], |
| 2115 | 2123 | else => unreachable, |
| 2116 | 2124 | }), |
| ... | ... | @@ -2219,7 +2227,8 @@ pub const CType = extern union { |
| 2219 | 2227 | .Struct => ty.structFieldCount(mod), |
| 2220 | 2228 | .Union => mod.typeToUnion(ty).?.field_names.len, |
| 2221 | 2229 | else => unreachable, |
| 2222 | }) |field_i| { | |
| 2230 | }) |field_i_usize| { | |
| 2231 | const field_i: u32 = @intCast(field_i_usize); | |
| 2223 | 2232 | const field_ty = ty.structFieldType(field_i, mod); |
| 2224 | 2233 | if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or |
| 2225 | 2234 | !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| ... | ... | @@ -2234,7 +2243,7 @@ pub const CType = extern union { |
| 2234 | 2243 | std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable |
| 2235 | 2244 | else |
| 2236 | 2245 | mod.intern_pool.stringToSlice(switch (zig_ty_tag) { |
| 2237 | .Struct => ty.structFieldName(field_i, mod), | |
| 2246 | .Struct => ty.legacyStructFieldName(field_i, mod), | |
| 2238 | 2247 | .Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i], |
| 2239 | 2248 | else => unreachable, |
| 2240 | 2249 | })); |
src/codegen/llvm.zig+341-295| ... | ... | @@ -833,7 +833,10 @@ pub const Object = struct { |
| 833 | 833 | |
| 834 | 834 | /// When an LLVM struct type is created, an entry is inserted into this |
| 835 | 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 | 840 | /// The value is the LLVM struct field index. |
| 838 | 841 | /// This is denormalized data. |
| 839 | 842 | struct_field_map: std.AutoHashMapUnmanaged(ZigStructField, c_uint), |
| ... | ... | @@ -1076,7 +1079,7 @@ pub const Object = struct { |
| 1076 | 1079 | table_variable_index.setMutability(.constant, &o.builder); |
| 1077 | 1080 | table_variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); |
| 1078 | 1081 | table_variable_index.setAlignment( |
| 1079 | Builder.Alignment.fromByteUnits(slice_ty.abiAlignment(mod)), | |
| 1082 | slice_ty.abiAlignment(mod).toLlvm(), | |
| 1080 | 1083 | &o.builder, |
| 1081 | 1084 | ); |
| 1082 | 1085 | |
| ... | ... | @@ -1318,8 +1321,9 @@ pub const Object = struct { |
| 1318 | 1321 | _ = try attributes.removeFnAttr(.@"noinline"); |
| 1319 | 1322 | } |
| 1320 | 1323 | |
| 1321 | if (func.analysis(ip).stack_alignment.toByteUnitsOptional()) |alignment| { | |
| 1322 | try attributes.addFnAttr(.{ .alignstack = Builder.Alignment.fromByteUnits(alignment) }, &o.builder); | |
| 1324 | const stack_alignment = func.analysis(ip).stack_alignment; | |
| 1325 | if (stack_alignment != .none) { | |
| 1326 | try attributes.addFnAttr(.{ .alignstack = stack_alignment.toLlvm() }, &o.builder); | |
| 1323 | 1327 | try attributes.addFnAttr(.@"noinline", &o.builder); |
| 1324 | 1328 | } else { |
| 1325 | 1329 | _ = try attributes.removeFnAttr(.alignstack); |
| ... | ... | @@ -1407,7 +1411,7 @@ pub const Object = struct { |
| 1407 | 1411 | const param = wip.arg(llvm_arg_i); |
| 1408 | 1412 | |
| 1409 | 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 | 1415 | const param_llvm_ty = param.typeOfWip(&wip); |
| 1412 | 1416 | const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target); |
| 1413 | 1417 | _ = try wip.store(.normal, param, arg_ptr, alignment); |
| ... | ... | @@ -1423,7 +1427,7 @@ pub const Object = struct { |
| 1423 | 1427 | const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType(); |
| 1424 | 1428 | const param_llvm_ty = try o.lowerType(param_ty); |
| 1425 | 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 | 1432 | try o.addByRefParamAttrs(&attributes, llvm_arg_i, alignment, it.byval_attr, param_llvm_ty); |
| 1429 | 1433 | llvm_arg_i += 1; |
| ... | ... | @@ -1438,7 +1442,7 @@ pub const Object = struct { |
| 1438 | 1442 | const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType(); |
| 1439 | 1443 | const param_llvm_ty = try o.lowerType(param_ty); |
| 1440 | 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 | 1447 | try attributes.addParamAttr(llvm_arg_i, .noundef, &o.builder); |
| 1444 | 1448 | llvm_arg_i += 1; |
| ... | ... | @@ -1456,7 +1460,7 @@ pub const Object = struct { |
| 1456 | 1460 | llvm_arg_i += 1; |
| 1457 | 1461 | |
| 1458 | 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 | 1464 | const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target); |
| 1461 | 1465 | _ = try wip.store(.normal, param, arg_ptr, alignment); |
| 1462 | 1466 | |
| ... | ... | @@ -1481,10 +1485,10 @@ pub const Object = struct { |
| 1481 | 1485 | if (ptr_info.flags.is_const) { |
| 1482 | 1486 | try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder); |
| 1483 | 1487 | } |
| 1484 | const elem_align = Builder.Alignment.fromByteUnits( | |
| 1485 | ptr_info.flags.alignment.toByteUnitsOptional() orelse | |
| 1486 | @max(ptr_info.child.toType().abiAlignment(mod), 1), | |
| 1487 | ); | |
| 1488 | const elem_align = (if (ptr_info.flags.alignment != .none) | |
| 1489 | @as(InternPool.Alignment, ptr_info.flags.alignment) | |
| 1490 | else | |
| 1491 | ptr_info.child.toType().abiAlignment(mod).max(.@"1")).toLlvm(); | |
| 1488 | 1492 | try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder); |
| 1489 | 1493 | const ptr_param = wip.arg(llvm_arg_i); |
| 1490 | 1494 | llvm_arg_i += 1; |
| ... | ... | @@ -1501,7 +1505,7 @@ pub const Object = struct { |
| 1501 | 1505 | const field_types = it.types_buffer[0..it.types_len]; |
| 1502 | 1506 | const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType(); |
| 1503 | 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 | 1509 | const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, param_alignment, target); |
| 1506 | 1510 | const llvm_ty = try o.builder.structType(.normal, field_types); |
| 1507 | 1511 | for (0..field_types.len) |field_i| { |
| ... | ... | @@ -1531,7 +1535,7 @@ pub const Object = struct { |
| 1531 | 1535 | const param = wip.arg(llvm_arg_i); |
| 1532 | 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 | 1539 | const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target); |
| 1536 | 1540 | _ = try wip.store(.normal, param, arg_ptr, alignment); |
| 1537 | 1541 | |
| ... | ... | @@ -1546,7 +1550,7 @@ pub const Object = struct { |
| 1546 | 1550 | const param = wip.arg(llvm_arg_i); |
| 1547 | 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 | 1554 | const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target); |
| 1551 | 1555 | _ = try wip.store(.normal, param, arg_ptr, alignment); |
| 1552 | 1556 | |
| ... | ... | @@ -1967,7 +1971,7 @@ pub const Object = struct { |
| 1967 | 1971 | di_file, |
| 1968 | 1972 | owner_decl.src_node + 1, |
| 1969 | 1973 | ty.abiSize(mod) * 8, |
| 1970 | ty.abiAlignment(mod) * 8, | |
| 1974 | ty.abiAlignment(mod).toByteUnits(0) * 8, | |
| 1971 | 1975 | enumerators.ptr, |
| 1972 | 1976 | @intCast(enumerators.len), |
| 1973 | 1977 | try o.lowerDebugType(int_ty, .full), |
| ... | ... | @@ -2055,7 +2059,7 @@ pub const Object = struct { |
| 2055 | 2059 | |
| 2056 | 2060 | var offset: u64 = 0; |
| 2057 | 2061 | offset += ptr_size; |
| 2058 | offset = std.mem.alignForward(u64, offset, len_align); | |
| 2062 | offset = len_align.forward(offset); | |
| 2059 | 2063 | const len_offset = offset; |
| 2060 | 2064 | |
| 2061 | 2065 | const fields: [2]*llvm.DIType = .{ |
| ... | ... | @@ -2065,7 +2069,7 @@ pub const Object = struct { |
| 2065 | 2069 | di_file, |
| 2066 | 2070 | line, |
| 2067 | 2071 | ptr_size * 8, // size in bits |
| 2068 | ptr_align * 8, // align in bits | |
| 2072 | ptr_align.toByteUnits(0) * 8, // align in bits | |
| 2069 | 2073 | 0, // offset in bits |
| 2070 | 2074 | 0, // flags |
| 2071 | 2075 | try o.lowerDebugType(ptr_ty, .full), |
| ... | ... | @@ -2076,7 +2080,7 @@ pub const Object = struct { |
| 2076 | 2080 | di_file, |
| 2077 | 2081 | line, |
| 2078 | 2082 | len_size * 8, // size in bits |
| 2079 | len_align * 8, // align in bits | |
| 2083 | len_align.toByteUnits(0) * 8, // align in bits | |
| 2080 | 2084 | len_offset * 8, // offset in bits |
| 2081 | 2085 | 0, // flags |
| 2082 | 2086 | try o.lowerDebugType(len_ty, .full), |
| ... | ... | @@ -2089,7 +2093,7 @@ pub const Object = struct { |
| 2089 | 2093 | di_file, |
| 2090 | 2094 | line, |
| 2091 | 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 | 2097 | 0, // flags |
| 2094 | 2098 | null, // derived from |
| 2095 | 2099 | &fields, |
| ... | ... | @@ -2110,7 +2114,7 @@ pub const Object = struct { |
| 2110 | 2114 | const ptr_di_ty = dib.createPointerType( |
| 2111 | 2115 | elem_di_ty, |
| 2112 | 2116 | target.ptrBitWidth(), |
| 2113 | ty.ptrAlignment(mod) * 8, | |
| 2117 | ty.ptrAlignment(mod).toByteUnits(0) * 8, | |
| 2114 | 2118 | name, |
| 2115 | 2119 | ); |
| 2116 | 2120 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| ... | ... | @@ -2142,7 +2146,7 @@ pub const Object = struct { |
| 2142 | 2146 | .Array => { |
| 2143 | 2147 | const array_di_ty = dib.createArrayType( |
| 2144 | 2148 | ty.abiSize(mod) * 8, |
| 2145 | ty.abiAlignment(mod) * 8, | |
| 2149 | ty.abiAlignment(mod).toByteUnits(0) * 8, | |
| 2146 | 2150 | try o.lowerDebugType(ty.childType(mod), .full), |
| 2147 | 2151 | @intCast(ty.arrayLen(mod)), |
| 2148 | 2152 | ); |
| ... | ... | @@ -2174,7 +2178,7 @@ pub const Object = struct { |
| 2174 | 2178 | |
| 2175 | 2179 | const vector_di_ty = dib.createVectorType( |
| 2176 | 2180 | ty.abiSize(mod) * 8, |
| 2177 | ty.abiAlignment(mod) * 8, | |
| 2181 | @intCast(ty.abiAlignment(mod).toByteUnits(0) * 8), | |
| 2178 | 2182 | elem_di_type, |
| 2179 | 2183 | ty.vectorLen(mod), |
| 2180 | 2184 | ); |
| ... | ... | @@ -2223,7 +2227,7 @@ pub const Object = struct { |
| 2223 | 2227 | |
| 2224 | 2228 | var offset: u64 = 0; |
| 2225 | 2229 | offset += payload_size; |
| 2226 | offset = std.mem.alignForward(u64, offset, non_null_align); | |
| 2230 | offset = non_null_align.forward(offset); | |
| 2227 | 2231 | const non_null_offset = offset; |
| 2228 | 2232 | |
| 2229 | 2233 | const fields: [2]*llvm.DIType = .{ |
| ... | ... | @@ -2233,7 +2237,7 @@ pub const Object = struct { |
| 2233 | 2237 | di_file, |
| 2234 | 2238 | line, |
| 2235 | 2239 | payload_size * 8, // size in bits |
| 2236 | payload_align * 8, // align in bits | |
| 2240 | payload_align.toByteUnits(0) * 8, // align in bits | |
| 2237 | 2241 | 0, // offset in bits |
| 2238 | 2242 | 0, // flags |
| 2239 | 2243 | try o.lowerDebugType(child_ty, .full), |
| ... | ... | @@ -2244,7 +2248,7 @@ pub const Object = struct { |
| 2244 | 2248 | di_file, |
| 2245 | 2249 | line, |
| 2246 | 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 | 2252 | non_null_offset * 8, // offset in bits |
| 2249 | 2253 | 0, // flags |
| 2250 | 2254 | try o.lowerDebugType(non_null_ty, .full), |
| ... | ... | @@ -2257,7 +2261,7 @@ pub const Object = struct { |
| 2257 | 2261 | di_file, |
| 2258 | 2262 | line, |
| 2259 | 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 | 2265 | 0, // flags |
| 2262 | 2266 | null, // derived from |
| 2263 | 2267 | &fields, |
| ... | ... | @@ -2306,16 +2310,16 @@ pub const Object = struct { |
| 2306 | 2310 | var payload_index: u32 = undefined; |
| 2307 | 2311 | var error_offset: u64 = undefined; |
| 2308 | 2312 | var payload_offset: u64 = undefined; |
| 2309 | if (error_align > payload_align) { | |
| 2313 | if (error_align.compare(.gt, payload_align)) { | |
| 2310 | 2314 | error_index = 0; |
| 2311 | 2315 | payload_index = 1; |
| 2312 | 2316 | error_offset = 0; |
| 2313 | payload_offset = std.mem.alignForward(u64, error_size, payload_align); | |
| 2317 | payload_offset = payload_align.forward(error_size); | |
| 2314 | 2318 | } else { |
| 2315 | 2319 | payload_index = 0; |
| 2316 | 2320 | error_index = 1; |
| 2317 | 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 | 2325 | var fields: [2]*llvm.DIType = undefined; |
| ... | ... | @@ -2325,7 +2329,7 @@ pub const Object = struct { |
| 2325 | 2329 | di_file, |
| 2326 | 2330 | line, |
| 2327 | 2331 | error_size * 8, // size in bits |
| 2328 | error_align * 8, // align in bits | |
| 2332 | error_align.toByteUnits(0) * 8, // align in bits | |
| 2329 | 2333 | error_offset * 8, // offset in bits |
| 2330 | 2334 | 0, // flags |
| 2331 | 2335 | try o.lowerDebugType(Type.anyerror, .full), |
| ... | ... | @@ -2336,7 +2340,7 @@ pub const Object = struct { |
| 2336 | 2340 | di_file, |
| 2337 | 2341 | line, |
| 2338 | 2342 | payload_size * 8, // size in bits |
| 2339 | payload_align * 8, // align in bits | |
| 2343 | payload_align.toByteUnits(0) * 8, // align in bits | |
| 2340 | 2344 | payload_offset * 8, // offset in bits |
| 2341 | 2345 | 0, // flags |
| 2342 | 2346 | try o.lowerDebugType(payload_ty, .full), |
| ... | ... | @@ -2348,7 +2352,7 @@ pub const Object = struct { |
| 2348 | 2352 | di_file, |
| 2349 | 2353 | line, |
| 2350 | 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 | 2356 | 0, // flags |
| 2353 | 2357 | null, // derived from |
| 2354 | 2358 | &fields, |
| ... | ... | @@ -2374,10 +2378,10 @@ pub const Object = struct { |
| 2374 | 2378 | const name = try o.allocTypeName(ty); |
| 2375 | 2379 | defer gpa.free(name); |
| 2376 | 2380 | |
| 2377 | if (mod.typeToStruct(ty)) |struct_obj| { | |
| 2378 | if (struct_obj.layout == .Packed and struct_obj.haveFieldTypes()) { | |
| 2379 | assert(struct_obj.haveLayout()); | |
| 2380 | const info = struct_obj.backing_int_ty.intInfo(mod); | |
| 2381 | if (mod.typeToPackedStruct(ty)) |struct_type| { | |
| 2382 | const backing_int_ty = struct_type.backingIntType(ip).*; | |
| 2383 | if (backing_int_ty != .none) { | |
| 2384 | const info = backing_int_ty.toType().intInfo(mod); | |
| 2381 | 2385 | const dwarf_encoding: c_uint = switch (info.signedness) { |
| 2382 | 2386 | .signed => DW.ATE.signed, |
| 2383 | 2387 | .unsigned => DW.ATE.unsigned, |
| ... | ... | @@ -2417,7 +2421,7 @@ pub const Object = struct { |
| 2417 | 2421 | |
| 2418 | 2422 | const field_size = field_ty.toType().abiSize(mod); |
| 2419 | 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 | 2425 | offset = field_offset + field_size; |
| 2422 | 2426 | |
| 2423 | 2427 | const field_name = if (tuple.names.len != 0) |
| ... | ... | @@ -2432,7 +2436,7 @@ pub const Object = struct { |
| 2432 | 2436 | null, // file |
| 2433 | 2437 | 0, // line |
| 2434 | 2438 | field_size * 8, // size in bits |
| 2435 | field_align * 8, // align in bits | |
| 2439 | field_align.toByteUnits(0) * 8, // align in bits | |
| 2436 | 2440 | field_offset * 8, // offset in bits |
| 2437 | 2441 | 0, // flags |
| 2438 | 2442 | try o.lowerDebugType(field_ty.toType(), .full), |
| ... | ... | @@ -2445,7 +2449,7 @@ pub const Object = struct { |
| 2445 | 2449 | null, // file |
| 2446 | 2450 | 0, // line |
| 2447 | 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 | 2453 | 0, // flags |
| 2450 | 2454 | null, // derived from |
| 2451 | 2455 | di_fields.items.ptr, |
| ... | ... | @@ -2459,10 +2463,8 @@ pub const Object = struct { |
| 2459 | 2463 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(full_di_ty)); |
| 2460 | 2464 | return full_di_ty; |
| 2461 | 2465 | }, |
| 2462 | .struct_type => |struct_type| s: { | |
| 2463 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :s; | |
| 2464 | ||
| 2465 | if (!struct_obj.haveFieldTypes()) { | |
| 2466 | .struct_type => |struct_type| { | |
| 2467 | if (!struct_type.haveFieldTypes(ip)) { | |
| 2466 | 2468 | // This can happen if a struct type makes it all the way to |
| 2467 | 2469 | // flush() without ever being instantiated or referenced (even |
| 2468 | 2470 | // via pointer). The only reason we are hearing about it now is |
| ... | ... | @@ -2492,37 +2494,41 @@ pub const Object = struct { |
| 2492 | 2494 | return struct_di_ty; |
| 2493 | 2495 | } |
| 2494 | 2496 | |
| 2495 | const fields = ty.structFields(mod); | |
| 2496 | const layout = ty.containerLayout(mod); | |
| 2497 | const struct_type = mod.typeToStruct(ty).?; | |
| 2497 | 2498 | |
| 2498 | 2499 | var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{}; |
| 2499 | 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 | 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); | |
| 2507 | while (it.next()) |field_and_index| { | |
| 2508 | const field = field_and_index.field; | |
| 2509 | const field_size = field.ty.abiSize(mod); | |
| 2510 | const field_align = field.alignment(mod, layout); | |
| 2511 | const field_offset = std.mem.alignForward(u64, offset, field_align); | |
| 2512 | offset = field_offset + field_size; | |
| 2517 | const field_name = struct_type.fieldName(ip, field_index).unwrap() orelse | |
| 2518 | try ip.getOrPutStringFmt(gpa, "{d}", .{field_index}); | |
| 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 | 2522 | try di_fields.append(gpa, dib.createMemberType( |
| 2517 | 2523 | fwd_decl.toScope(), |
| 2518 | field_name, | |
| 2524 | ip.stringToSlice(field_name), | |
| 2519 | 2525 | null, // file |
| 2520 | 2526 | 0, // line |
| 2521 | 2527 | field_size * 8, // size in bits |
| 2522 | field_align * 8, // align in bits | |
| 2528 | field_align.toByteUnits(0) * 8, // align in bits | |
| 2523 | 2529 | field_offset * 8, // offset in bits |
| 2524 | 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 | 2538 | null, // file |
| 2533 | 2539 | 0, // line |
| 2534 | 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 | 2542 | 0, // flags |
| 2537 | 2543 | null, // derived from |
| 2538 | 2544 | di_fields.items.ptr, |
| ... | ... | @@ -2588,7 +2594,7 @@ pub const Object = struct { |
| 2588 | 2594 | null, // file |
| 2589 | 2595 | 0, // line |
| 2590 | 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 | 2598 | 0, // flags |
| 2593 | 2599 | null, // derived from |
| 2594 | 2600 | &di_fields, |
| ... | ... | @@ -2624,7 +2630,7 @@ pub const Object = struct { |
| 2624 | 2630 | null, // file |
| 2625 | 2631 | 0, // line |
| 2626 | 2632 | field_size * 8, // size in bits |
| 2627 | field_align * 8, // align in bits | |
| 2633 | field_align.toByteUnits(0) * 8, // align in bits | |
| 2628 | 2634 | 0, // offset in bits |
| 2629 | 2635 | 0, // flags |
| 2630 | 2636 | field_di_ty, |
| ... | ... | @@ -2644,7 +2650,7 @@ pub const Object = struct { |
| 2644 | 2650 | null, // file |
| 2645 | 2651 | 0, // line |
| 2646 | 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 | 2654 | 0, // flags |
| 2649 | 2655 | di_fields.items.ptr, |
| 2650 | 2656 | @intCast(di_fields.items.len), |
| ... | ... | @@ -2661,12 +2667,12 @@ pub const Object = struct { |
| 2661 | 2667 | |
| 2662 | 2668 | var tag_offset: u64 = undefined; |
| 2663 | 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 | 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 | 2673 | } else { |
| 2668 | 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 | 2678 | const tag_di = dib.createMemberType( |
| ... | ... | @@ -2675,7 +2681,7 @@ pub const Object = struct { |
| 2675 | 2681 | null, // file |
| 2676 | 2682 | 0, // line |
| 2677 | 2683 | layout.tag_size * 8, |
| 2678 | layout.tag_align * 8, // align in bits | |
| 2684 | layout.tag_align.toByteUnits(0) * 8, | |
| 2679 | 2685 | tag_offset * 8, // offset in bits |
| 2680 | 2686 | 0, // flags |
| 2681 | 2687 | try o.lowerDebugType(union_obj.enum_tag_ty.toType(), .full), |
| ... | ... | @@ -2687,14 +2693,14 @@ pub const Object = struct { |
| 2687 | 2693 | null, // file |
| 2688 | 2694 | 0, // line |
| 2689 | 2695 | layout.payload_size * 8, // size in bits |
| 2690 | layout.payload_align * 8, // align in bits | |
| 2696 | layout.payload_align.toByteUnits(0) * 8, | |
| 2691 | 2697 | payload_offset * 8, // offset in bits |
| 2692 | 2698 | 0, // flags |
| 2693 | 2699 | union_di_ty, |
| 2694 | 2700 | ); |
| 2695 | 2701 | |
| 2696 | 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 | 2704 | .{ tag_di, payload_di } |
| 2699 | 2705 | else |
| 2700 | 2706 | .{ payload_di, tag_di }; |
| ... | ... | @@ -2705,7 +2711,7 @@ pub const Object = struct { |
| 2705 | 2711 | null, // file |
| 2706 | 2712 | 0, // line |
| 2707 | 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 | 2715 | 0, // flags |
| 2710 | 2716 | null, // derived from |
| 2711 | 2717 | &full_di_fields, |
| ... | ... | @@ -2925,8 +2931,8 @@ pub const Object = struct { |
| 2925 | 2931 | else => function_index.setCallConv(toLlvmCallConv(fn_info.cc, target), &o.builder), |
| 2926 | 2932 | } |
| 2927 | 2933 | |
| 2928 | if (fn_info.alignment.toByteUnitsOptional()) |alignment| | |
| 2929 | function_index.setAlignment(Builder.Alignment.fromByteUnits(alignment), &o.builder); | |
| 2934 | if (fn_info.alignment != .none) | |
| 2935 | function_index.setAlignment(fn_info.alignment.toLlvm(), &o.builder); | |
| 2930 | 2936 | |
| 2931 | 2937 | // Function attributes that are independent of analysis results of the function body. |
| 2932 | 2938 | try o.addCommonFnAttributes(&attributes); |
| ... | ... | @@ -2949,9 +2955,8 @@ pub const Object = struct { |
| 2949 | 2955 | .byref => { |
| 2950 | 2956 | const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1]; |
| 2951 | 2957 | const param_llvm_ty = try o.lowerType(param_ty.toType()); |
| 2952 | const alignment = | |
| 2953 | Builder.Alignment.fromByteUnits(param_ty.toType().abiAlignment(mod)); | |
| 2954 | try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty); | |
| 2958 | const alignment = param_ty.toType().abiAlignment(mod); | |
| 2959 | try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment.toLlvm(), it.byval_attr, param_llvm_ty); | |
| 2955 | 2960 | }, |
| 2956 | 2961 | .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder), |
| 2957 | 2962 | // No attributes needed for these. |
| ... | ... | @@ -3248,21 +3253,21 @@ pub const Object = struct { |
| 3248 | 3253 | |
| 3249 | 3254 | var fields: [3]Builder.Type = undefined; |
| 3250 | 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 | 3257 | fields[0] = error_type; |
| 3253 | 3258 | fields[1] = payload_type; |
| 3254 | 3259 | const payload_end = |
| 3255 | std.mem.alignForward(u64, error_size, payload_align) + | |
| 3260 | payload_align.forward(error_size) + | |
| 3256 | 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 | 3263 | break :pad abi_size - payload_end; |
| 3259 | 3264 | } else pad: { |
| 3260 | 3265 | fields[0] = payload_type; |
| 3261 | 3266 | fields[1] = error_type; |
| 3262 | 3267 | const error_end = |
| 3263 | std.mem.alignForward(u64, payload_size, error_align) + | |
| 3268 | error_align.forward(payload_size) + | |
| 3264 | 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 | 3271 | break :pad abi_size - error_end; |
| 3267 | 3272 | }; |
| 3268 | 3273 | if (padding_len > 0) { |
| ... | ... | @@ -3276,60 +3281,74 @@ pub const Object = struct { |
| 3276 | 3281 | const gop = try o.type_map.getOrPut(o.gpa, t.toIntern()); |
| 3277 | 3282 | if (gop.found_existing) return gop.value_ptr.*; |
| 3278 | 3283 | |
| 3279 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 3280 | if (struct_obj.layout == .Packed) { | |
| 3281 | assert(struct_obj.haveLayout()); | |
| 3282 | const int_ty = try o.lowerType(struct_obj.backing_int_ty); | |
| 3284 | if (struct_type.layout == .Packed) { | |
| 3285 | const int_ty = try o.lowerType(struct_type.backingIntType(ip).toType()); | |
| 3283 | 3286 | gop.value_ptr.* = int_ty; |
| 3284 | 3287 | return int_ty; |
| 3285 | 3288 | } |
| 3286 | 3289 | |
| 3287 | 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 | 3293 | const ty = try o.builder.opaqueType(name); |
| 3291 | 3294 | gop.value_ptr.* = ty; // must be done before any recursive calls |
| 3292 | 3295 | |
| 3293 | assert(struct_obj.haveFieldTypes()); | |
| 3294 | ||
| 3295 | 3296 | var llvm_field_types = std.ArrayListUnmanaged(Builder.Type){}; |
| 3296 | 3297 | defer llvm_field_types.deinit(o.gpa); |
| 3297 | 3298 | // Although we can estimate how much capacity to add, these cannot be |
| 3298 | 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 o.struct_field_map.ensureUnusedCapacity(o.gpa, @intCast(struct_obj.fields.count())); | |
| 3300 | try llvm_field_types.ensureUnusedCapacity(o.gpa, struct_type.field_types.len); | |
| 3301 | try o.struct_field_map.ensureUnusedCapacity(o.gpa, struct_type.field_types.len); | |
| 3301 | 3302 | |
| 3302 | 3303 | comptime assert(struct_layout_version == 2); |
| 3303 | 3304 | var offset: u64 = 0; |
| 3304 | var big_align: u32 = 1; | |
| 3305 | var big_align: InternPool.Alignment = .@"1"; | |
| 3305 | 3306 | var struct_kind: Builder.Type.Structure.Kind = .normal; |
| 3306 | ||
| 3307 | var it = struct_obj.runtimeFieldIterator(mod); | |
| 3308 | while (it.next()) |field_and_index| { | |
| 3309 | const field = field_and_index.field; | |
| 3310 | const field_align = field.alignment(mod, struct_obj.layout); | |
| 3311 | const field_ty_align = field.ty.abiAlignment(mod); | |
| 3312 | if (field_align < field_ty_align) struct_kind = .@"packed"; | |
| 3313 | big_align = @max(big_align, field_align); | |
| 3307 | // When we encounter a zero-bit field, we place it here so we know to map it to the next non-zero-bit field (if any). | |
| 3308 | var it = struct_type.iterateRuntimeOrder(ip); | |
| 3309 | while (it.next()) |field_index| { | |
| 3310 | const field_ty = struct_type.field_types.get(ip)[field_index].toType(); | |
| 3311 | const field_align = mod.structFieldAlignment( | |
| 3312 | struct_type.fieldAlign(ip, field_index), | |
| 3313 | field_ty, | |
| 3314 | struct_type.layout, | |
| 3315 | ); | |
| 3316 | const field_ty_align = field_ty.abiAlignment(mod); | |
| 3317 | if (field_align.compare(.lt, field_ty_align)) struct_kind = .@"packed"; | |
| 3318 | big_align = big_align.max(field_align); | |
| 3314 | 3319 | const prev_offset = offset; |
| 3315 | offset = std.mem.alignForward(u64, offset, field_align); | |
| 3320 | offset = field_align.forward(offset); | |
| 3316 | 3321 | |
| 3317 | 3322 | const padding_len = offset - prev_offset; |
| 3318 | 3323 | if (padding_len > 0) try llvm_field_types.append( |
| 3319 | 3324 | o.gpa, |
| 3320 | 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 | 3341 | try o.struct_field_map.put(o.gpa, .{ |
| 3323 | 3342 | .struct_ty = t.toIntern(), |
| 3324 | .field_index = field_and_index.index, | |
| 3343 | .field_index = field_index, | |
| 3325 | 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 | 3350 | const prev_offset = offset; |
| 3332 | offset = std.mem.alignForward(u64, offset, big_align); | |
| 3351 | offset = big_align.forward(offset); | |
| 3333 | 3352 | const padding_len = offset - prev_offset; |
| 3334 | 3353 | if (padding_len > 0) try llvm_field_types.append( |
| 3335 | 3354 | o.gpa, |
| ... | ... | @@ -3353,25 +3372,39 @@ pub const Object = struct { |
| 3353 | 3372 | |
| 3354 | 3373 | comptime assert(struct_layout_version == 2); |
| 3355 | 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 | 3379 | for ( |
| 3359 | 3380 | anon_struct_type.types.get(ip), |
| 3360 | 3381 | anon_struct_type.values.get(ip), |
| 3361 | 3382 | 0.., |
| 3362 | 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 | 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 | 3388 | const prev_offset = offset; |
| 3368 | offset = std.mem.alignForward(u64, offset, field_align); | |
| 3389 | offset = field_align.forward(offset); | |
| 3369 | 3390 | |
| 3370 | 3391 | const padding_len = offset - prev_offset; |
| 3371 | 3392 | if (padding_len > 0) try llvm_field_types.append( |
| 3372 | 3393 | o.gpa, |
| 3373 | 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 | 3408 | try o.struct_field_map.put(o.gpa, .{ |
| 3376 | 3409 | .struct_ty = t.toIntern(), |
| 3377 | 3410 | .field_index = @intCast(field_index), |
| ... | ... | @@ -3382,7 +3415,7 @@ pub const Object = struct { |
| 3382 | 3415 | } |
| 3383 | 3416 | { |
| 3384 | 3417 | const prev_offset = offset; |
| 3385 | offset = std.mem.alignForward(u64, offset, big_align); | |
| 3418 | offset = big_align.forward(offset); | |
| 3386 | 3419 | const padding_len = offset - prev_offset; |
| 3387 | 3420 | if (padding_len > 0) try llvm_field_types.append( |
| 3388 | 3421 | o.gpa, |
| ... | ... | @@ -3447,7 +3480,7 @@ pub const Object = struct { |
| 3447 | 3480 | var llvm_fields: [3]Builder.Type = undefined; |
| 3448 | 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 | 3484 | llvm_fields = .{ enum_tag_ty, payload_ty, .none }; |
| 3452 | 3485 | } else { |
| 3453 | 3486 | llvm_fields = .{ payload_ty, enum_tag_ty, .none }; |
| ... | ... | @@ -3687,7 +3720,7 @@ pub const Object = struct { |
| 3687 | 3720 | |
| 3688 | 3721 | var fields: [3]Builder.Type = undefined; |
| 3689 | 3722 | var vals: [3]Builder.Constant = undefined; |
| 3690 | if (error_align > payload_align) { | |
| 3723 | if (error_align.compare(.gt, payload_align)) { | |
| 3691 | 3724 | vals[0] = llvm_error_value; |
| 3692 | 3725 | vals[1] = llvm_payload_value; |
| 3693 | 3726 | } else { |
| ... | ... | @@ -3910,7 +3943,7 @@ pub const Object = struct { |
| 3910 | 3943 | comptime assert(struct_layout_version == 2); |
| 3911 | 3944 | var llvm_index: usize = 0; |
| 3912 | 3945 | var offset: u64 = 0; |
| 3913 | var big_align: u32 = 0; | |
| 3946 | var big_align: InternPool.Alignment = .none; | |
| 3914 | 3947 | var need_unnamed = false; |
| 3915 | 3948 | for ( |
| 3916 | 3949 | tuple.types.get(ip), |
| ... | ... | @@ -3921,9 +3954,9 @@ pub const Object = struct { |
| 3921 | 3954 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 3922 | 3955 | |
| 3923 | 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 | 3958 | const prev_offset = offset; |
| 3926 | offset = std.mem.alignForward(u64, offset, field_align); | |
| 3959 | offset = field_align.forward(offset); | |
| 3927 | 3960 | |
| 3928 | 3961 | const padding_len = offset - prev_offset; |
| 3929 | 3962 | if (padding_len > 0) { |
| ... | ... | @@ -3946,7 +3979,7 @@ pub const Object = struct { |
| 3946 | 3979 | } |
| 3947 | 3980 | { |
| 3948 | 3981 | const prev_offset = offset; |
| 3949 | offset = std.mem.alignForward(u64, offset, big_align); | |
| 3982 | offset = big_align.forward(offset); | |
| 3950 | 3983 | const padding_len = offset - prev_offset; |
| 3951 | 3984 | if (padding_len > 0) { |
| 3952 | 3985 | fields[llvm_index] = try o.builder.arrayType(padding_len, .i8); |
| ... | ... | @@ -3963,22 +3996,21 @@ pub const Object = struct { |
| 3963 | 3996 | struct_ty, vals); |
| 3964 | 3997 | }, |
| 3965 | 3998 | .struct_type => |struct_type| { |
| 3966 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 3967 | assert(struct_obj.haveLayout()); | |
| 3999 | assert(struct_type.haveLayout(ip)); | |
| 3968 | 4000 | const struct_ty = try o.lowerType(ty); |
| 3969 | if (struct_obj.layout == .Packed) { | |
| 4001 | if (struct_type.layout == .Packed) { | |
| 3970 | 4002 | comptime assert(Type.packed_struct_layout_version == 2); |
| 3971 | 4003 | var running_int = try o.builder.intConst(struct_ty, 0); |
| 3972 | 4004 | var running_bits: u16 = 0; |
| 3973 | for (struct_obj.fields.values(), 0..) |field, field_index| { | |
| 3974 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 4005 | for (struct_type.field_types.get(ip), 0..) |field_ty, field_index| { | |
| 4006 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 3975 | 4007 | |
| 3976 | 4008 | const non_int_val = |
| 3977 | 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 | 4011 | const small_int_ty = try o.builder.intType(ty_bit_size); |
| 3980 | 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 | 4014 | non_int_val, |
| 3983 | 4015 | small_int_ty, |
| 3984 | 4016 | ); |
| ... | ... | @@ -4010,15 +4042,19 @@ pub const Object = struct { |
| 4010 | 4042 | comptime assert(struct_layout_version == 2); |
| 4011 | 4043 | var llvm_index: usize = 0; |
| 4012 | 4044 | var offset: u64 = 0; |
| 4013 | var big_align: u32 = 0; | |
| 4045 | var big_align: InternPool.Alignment = .@"1"; | |
| 4014 | 4046 | var need_unnamed = false; |
| 4015 | var field_it = struct_obj.runtimeFieldIterator(mod); | |
| 4016 | while (field_it.next()) |field_and_index| { | |
| 4017 | const field = field_and_index.field; | |
| 4018 | const field_align = field.alignment(mod, struct_obj.layout); | |
| 4019 | big_align = @max(big_align, field_align); | |
| 4047 | var field_it = struct_type.iterateRuntimeOrder(ip); | |
| 4048 | while (field_it.next()) |field_index| { | |
| 4049 | const field_ty = struct_type.field_types.get(ip)[field_index].toType(); | |
| 4050 | const field_align = mod.structFieldAlignment( | |
| 4051 | struct_type.fieldAlign(ip, field_index), | |
| 4052 | field_ty, | |
| 4053 | struct_type.layout, | |
| 4054 | ); | |
| 4055 | big_align = big_align.max(field_align); | |
| 4020 | 4056 | const prev_offset = offset; |
| 4021 | offset = std.mem.alignForward(u64, offset, field_align); | |
| 4057 | offset = field_align.forward(offset); | |
| 4022 | 4058 | |
| 4023 | 4059 | const padding_len = offset - prev_offset; |
| 4024 | 4060 | if (padding_len > 0) { |
| ... | ... | @@ -4031,19 +4067,24 @@ pub const Object = struct { |
| 4031 | 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 | 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 | 4078 | fields[llvm_index] = vals[llvm_index].typeOf(&o.builder); |
| 4038 | 4079 | if (fields[llvm_index] != struct_ty.structFields(&o.builder)[llvm_index]) |
| 4039 | 4080 | need_unnamed = true; |
| 4040 | 4081 | llvm_index += 1; |
| 4041 | 4082 | |
| 4042 | offset += field.ty.abiSize(mod); | |
| 4083 | offset += field_ty.abiSize(mod); | |
| 4043 | 4084 | } |
| 4044 | 4085 | { |
| 4045 | 4086 | const prev_offset = offset; |
| 4046 | offset = std.mem.alignForward(u64, offset, big_align); | |
| 4087 | offset = big_align.forward(offset); | |
| 4047 | 4088 | const padding_len = offset - prev_offset; |
| 4048 | 4089 | if (padding_len > 0) { |
| 4049 | 4090 | fields[llvm_index] = try o.builder.arrayType(padding_len, .i8); |
| ... | ... | @@ -4093,7 +4134,7 @@ pub const Object = struct { |
| 4093 | 4134 | const payload = try o.lowerValue(un.val); |
| 4094 | 4135 | const payload_ty = payload.typeOf(&o.builder); |
| 4095 | 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 | 4138 | ]) need_unnamed = true; |
| 4098 | 4139 | const field_size = field_ty.abiSize(mod); |
| 4099 | 4140 | if (field_size == layout.payload_size) break :p payload; |
| ... | ... | @@ -4115,7 +4156,7 @@ pub const Object = struct { |
| 4115 | 4156 | var fields: [3]Builder.Type = undefined; |
| 4116 | 4157 | var vals: [3]Builder.Constant = undefined; |
| 4117 | 4158 | var len: usize = 2; |
| 4118 | if (layout.tag_align >= layout.payload_align) { | |
| 4159 | if (layout.tag_align.compare(.gte, layout.payload_align)) { | |
| 4119 | 4160 | fields = .{ tag_ty, payload_ty, undefined }; |
| 4120 | 4161 | vals = .{ tag, payload, undefined }; |
| 4121 | 4162 | } else { |
| ... | ... | @@ -4174,14 +4215,15 @@ pub const Object = struct { |
| 4174 | 4215 | |
| 4175 | 4216 | fn lowerParentPtr(o: *Object, ptr_val: Value, byte_aligned: bool) Allocator.Error!Builder.Constant { |
| 4176 | 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 | 4220 | .decl => |decl| o.lowerParentPtrDecl(decl), |
| 4179 | 4221 | .mut_decl => |mut_decl| o.lowerParentPtrDecl(mut_decl.decl), |
| 4180 | 4222 | .int => |int| try o.lowerIntAsPtr(int), |
| 4181 | 4223 | .eu_payload => |eu_ptr| { |
| 4182 | 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 | 4227 | const payload_ty = eu_ty.errorUnionPayload(mod); |
| 4186 | 4228 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 4187 | 4229 | // In this case, we represent pointer to error union the same as pointer |
| ... | ... | @@ -4189,8 +4231,9 @@ pub const Object = struct { |
| 4189 | 4231 | return parent_ptr; |
| 4190 | 4232 | } |
| 4191 | 4233 | |
| 4192 | const index: u32 = | |
| 4193 | if (payload_ty.abiAlignment(mod) > Type.err_int.abiSize(mod)) 2 else 1; | |
| 4234 | const payload_align = payload_ty.abiAlignment(mod); | |
| 4235 | const err_align = Type.err_int.abiAlignment(mod); | |
| 4236 | const index: u32 = if (payload_align.compare(.gt, err_align)) 2 else 1; | |
| 4194 | 4237 | return o.builder.gepConst(.inbounds, try o.lowerType(eu_ty), parent_ptr, null, &.{ |
| 4195 | 4238 | try o.builder.intConst(.i32, 0), try o.builder.intConst(.i32, index), |
| 4196 | 4239 | }); |
| ... | ... | @@ -4198,7 +4241,7 @@ pub const Object = struct { |
| 4198 | 4241 | .opt_payload => |opt_ptr| { |
| 4199 | 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 | 4245 | const payload_ty = opt_ty.optionalChild(mod); |
| 4203 | 4246 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod) or |
| 4204 | 4247 | payload_ty.optionalReprIsPayload(mod)) |
| ... | ... | @@ -4215,7 +4258,7 @@ pub const Object = struct { |
| 4215 | 4258 | .comptime_field => unreachable, |
| 4216 | 4259 | .elem => |elem_ptr| { |
| 4217 | 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 | 4263 | return o.builder.gepConst(.inbounds, try o.lowerType(elem_ty), parent_ptr, null, &.{ |
| 4221 | 4264 | try o.builder.intConst(try o.lowerType(Type.usize), elem_ptr.index), |
| ... | ... | @@ -4223,7 +4266,7 @@ pub const Object = struct { |
| 4223 | 4266 | }, |
| 4224 | 4267 | .field => |field_ptr| { |
| 4225 | 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 | 4271 | const field_index: u32 = @intCast(field_ptr.index); |
| 4229 | 4272 | switch (parent_ty.zigTypeTag(mod)) { |
| ... | ... | @@ -4241,24 +4284,26 @@ pub const Object = struct { |
| 4241 | 4284 | |
| 4242 | 4285 | const parent_llvm_ty = try o.lowerType(parent_ty); |
| 4243 | 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( | |
| 4245 | layout.tag_size > 0 and layout.tag_align >= layout.payload_align, | |
| 4287 | try o.builder.intConst(.i32, 0), | |
| 4288 | try o.builder.intConst(.i32, @intFromBool( | |
| 4289 | layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align), | |
| 4246 | 4290 | )), |
| 4247 | 4291 | }); |
| 4248 | 4292 | }, |
| 4249 | 4293 | .Struct => { |
| 4250 | if (parent_ty.containerLayout(mod) == .Packed) { | |
| 4294 | if (mod.typeToPackedStruct(parent_ty)) |struct_type| { | |
| 4251 | 4295 | if (!byte_aligned) return parent_ptr; |
| 4252 | 4296 | const llvm_usize = try o.lowerType(Type.usize); |
| 4253 | 4297 | const base_addr = |
| 4254 | 4298 | try o.builder.castConst(.ptrtoint, parent_ptr, llvm_usize); |
| 4255 | 4299 | // count bits of fields before this one |
| 4300 | // TODO https://github.com/ziglang/zig/issues/17178 | |
| 4256 | 4301 | const prev_bits = b: { |
| 4257 | 4302 | var b: usize = 0; |
| 4258 | for (parent_ty.structFields(mod).values()[0..field_index]) |field| { | |
| 4259 | if (field.is_comptime) continue; | |
| 4260 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 4261 | b += @intCast(field.ty.bitSize(mod)); | |
| 4303 | for (0..field_index) |i| { | |
| 4304 | const field_ty = struct_type.field_types.get(ip)[i].toType(); | |
| 4305 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 4306 | b += @intCast(field_ty.bitSize(mod)); | |
| 4262 | 4307 | } |
| 4263 | 4308 | break :b b; |
| 4264 | 4309 | }; |
| ... | ... | @@ -4407,11 +4452,11 @@ pub const Object = struct { |
| 4407 | 4452 | if (ptr_info.flags.is_const) { |
| 4408 | 4453 | try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder); |
| 4409 | 4454 | } |
| 4410 | const elem_align = Builder.Alignment.fromByteUnits( | |
| 4411 | ptr_info.flags.alignment.toByteUnitsOptional() orelse | |
| 4412 | @max(ptr_info.child.toType().abiAlignment(mod), 1), | |
| 4413 | ); | |
| 4414 | try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder); | |
| 4455 | const elem_align = if (ptr_info.flags.alignment != .none) | |
| 4456 | ptr_info.flags.alignment | |
| 4457 | else | |
| 4458 | ptr_info.child.toType().abiAlignment(mod).max(.@"1"); | |
| 4459 | try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align.toLlvm() }, &o.builder); | |
| 4415 | 4460 | } else if (ccAbiPromoteInt(fn_info.cc, mod, param_ty)) |s| switch (s) { |
| 4416 | 4461 | .signed => try attributes.addParamAttr(llvm_arg_i, .signext, &o.builder), |
| 4417 | 4462 | .unsigned => try attributes.addParamAttr(llvm_arg_i, .zeroext, &o.builder), |
| ... | ... | @@ -4469,7 +4514,7 @@ pub const DeclGen = struct { |
| 4469 | 4514 | } else { |
| 4470 | 4515 | const variable_index = try o.resolveGlobalDecl(decl_index); |
| 4471 | 4516 | variable_index.setAlignment( |
| 4472 | Builder.Alignment.fromByteUnits(decl.getAlignment(mod)), | |
| 4517 | decl.getAlignment(mod).toLlvm(), | |
| 4473 | 4518 | &o.builder, |
| 4474 | 4519 | ); |
| 4475 | 4520 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |section| |
| ... | ... | @@ -4611,9 +4656,7 @@ pub const FuncGen = struct { |
| 4611 | 4656 | variable_index.setLinkage(.private, &o.builder); |
| 4612 | 4657 | variable_index.setMutability(.constant, &o.builder); |
| 4613 | 4658 | variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); |
| 4614 | variable_index.setAlignment(Builder.Alignment.fromByteUnits( | |
| 4615 | tv.ty.abiAlignment(mod), | |
| 4616 | ), &o.builder); | |
| 4659 | variable_index.setAlignment(tv.ty.abiAlignment(mod).toLlvm(), &o.builder); | |
| 4617 | 4660 | return o.builder.convConst( |
| 4618 | 4661 | .unneeded, |
| 4619 | 4662 | variable_index.toConst(&o.builder), |
| ... | ... | @@ -4929,7 +4972,7 @@ pub const FuncGen = struct { |
| 4929 | 4972 | const llvm_ret_ty = try o.lowerType(return_type); |
| 4930 | 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 | 4976 | const ret_ptr = try self.buildAlloca(llvm_ret_ty, alignment); |
| 4934 | 4977 | try llvm_args.append(ret_ptr); |
| 4935 | 4978 | break :blk ret_ptr; |
| ... | ... | @@ -4951,7 +4994,7 @@ pub const FuncGen = struct { |
| 4951 | 4994 | const llvm_arg = try self.resolveInst(arg); |
| 4952 | 4995 | const llvm_param_ty = try o.lowerType(param_ty); |
| 4953 | 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 | 4998 | const loaded = try self.wip.load(.normal, llvm_param_ty, llvm_arg, alignment, ""); |
| 4956 | 4999 | try llvm_args.append(loaded); |
| 4957 | 5000 | } else { |
| ... | ... | @@ -4965,7 +5008,7 @@ pub const FuncGen = struct { |
| 4965 | 5008 | if (isByRef(param_ty, mod)) { |
| 4966 | 5009 | try llvm_args.append(llvm_arg); |
| 4967 | 5010 | } else { |
| 4968 | const alignment = Builder.Alignment.fromByteUnits(param_ty.abiAlignment(mod)); | |
| 5011 | const alignment = param_ty.abiAlignment(mod).toLlvm(); | |
| 4969 | 5012 | const param_llvm_ty = llvm_arg.typeOfWip(&self.wip); |
| 4970 | 5013 | const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment); |
| 4971 | 5014 | _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment); |
| ... | ... | @@ -4977,7 +5020,7 @@ pub const FuncGen = struct { |
| 4977 | 5020 | const param_ty = self.typeOf(arg); |
| 4978 | 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 | 5024 | const param_llvm_ty = try o.lowerType(param_ty); |
| 4982 | 5025 | const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment); |
| 4983 | 5026 | if (isByRef(param_ty, mod)) { |
| ... | ... | @@ -4995,13 +5038,13 @@ pub const FuncGen = struct { |
| 4995 | 5038 | const int_llvm_ty = try o.builder.intType(@intCast(param_ty.abiSize(mod) * 8)); |
| 4996 | 5039 | |
| 4997 | 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 | 5042 | const loaded = try self.wip.load(.normal, int_llvm_ty, llvm_arg, alignment, ""); |
| 5000 | 5043 | try llvm_args.append(loaded); |
| 5001 | 5044 | } else { |
| 5002 | 5045 | // LLVM does not allow bitcasting structs so we must allocate |
| 5003 | 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 | 5048 | const int_ptr = try self.buildAlloca(int_llvm_ty, alignment); |
| 5006 | 5049 | _ = try self.wip.store(.normal, llvm_arg, int_ptr, alignment); |
| 5007 | 5050 | const loaded = try self.wip.load(.normal, int_llvm_ty, int_ptr, alignment, ""); |
| ... | ... | @@ -5022,7 +5065,7 @@ pub const FuncGen = struct { |
| 5022 | 5065 | const llvm_arg = try self.resolveInst(arg); |
| 5023 | 5066 | const is_by_ref = isByRef(param_ty, mod); |
| 5024 | 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 | 5069 | const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment); |
| 5027 | 5070 | _ = try self.wip.store(.normal, llvm_arg, ptr, alignment); |
| 5028 | 5071 | break :ptr ptr; |
| ... | ... | @@ -5048,7 +5091,7 @@ pub const FuncGen = struct { |
| 5048 | 5091 | const arg = args[it.zig_index - 1]; |
| 5049 | 5092 | const arg_ty = self.typeOf(arg); |
| 5050 | 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 | 5095 | if (!isByRef(arg_ty, mod)) { |
| 5053 | 5096 | const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment); |
| 5054 | 5097 | _ = try self.wip.store(.normal, llvm_arg, ptr, alignment); |
| ... | ... | @@ -5066,7 +5109,7 @@ pub const FuncGen = struct { |
| 5066 | 5109 | const arg = args[it.zig_index - 1]; |
| 5067 | 5110 | const arg_ty = self.typeOf(arg); |
| 5068 | 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 | 5113 | if (!isByRef(arg_ty, mod)) { |
| 5071 | 5114 | const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment); |
| 5072 | 5115 | _ = try self.wip.store(.normal, llvm_arg, ptr, alignment); |
| ... | ... | @@ -5097,7 +5140,7 @@ pub const FuncGen = struct { |
| 5097 | 5140 | const param_index = it.zig_index - 1; |
| 5098 | 5141 | const param_ty = fn_info.param_types.get(ip)[param_index].toType(); |
| 5099 | 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 | 5144 | try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty); |
| 5102 | 5145 | }, |
| 5103 | 5146 | .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder), |
| ... | ... | @@ -5128,10 +5171,10 @@ pub const FuncGen = struct { |
| 5128 | 5171 | if (ptr_info.flags.is_const) { |
| 5129 | 5172 | try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder); |
| 5130 | 5173 | } |
| 5131 | const elem_align = Builder.Alignment.fromByteUnits( | |
| 5132 | ptr_info.flags.alignment.toByteUnitsOptional() orelse | |
| 5133 | @max(ptr_info.child.toType().abiAlignment(mod), 1), | |
| 5134 | ); | |
| 5174 | const elem_align = (if (ptr_info.flags.alignment != .none) | |
| 5175 | @as(InternPool.Alignment, ptr_info.flags.alignment) | |
| 5176 | else | |
| 5177 | ptr_info.child.toType().abiAlignment(mod).max(.@"1")).toLlvm(); | |
| 5135 | 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 | 5209 | return rp; |
| 5167 | 5210 | } else { |
| 5168 | 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 | 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 | 5220 | // In this case the function return type is honoring the calling convention by having |
| 5178 | 5221 | // a different LLVM type than the usual one. We solve this here at the callsite |
| 5179 | 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 | 5224 | if (o.builder.useLibLlvm()) |
| 5182 | 5225 | assert(o.target_data.abiSizeOfType(abi_ret_ty.toLlvm(&o.builder)) >= |
| 5183 | 5226 | o.target_data.abiSizeOfType(llvm_ret_ty.toLlvm(&o.builder))); |
| ... | ... | @@ -5192,7 +5235,7 @@ pub const FuncGen = struct { |
| 5192 | 5235 | if (isByRef(return_type, mod)) { |
| 5193 | 5236 | // our by-ref status disagrees with sret so we must allocate, store, |
| 5194 | 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 | 5239 | const rp = try self.buildAlloca(llvm_ret_ty, alignment); |
| 5197 | 5240 | _ = try self.wip.store(.normal, call, rp, alignment); |
| 5198 | 5241 | return rp; |
| ... | ... | @@ -5266,7 +5309,7 @@ pub const FuncGen = struct { |
| 5266 | 5309 | |
| 5267 | 5310 | const abi_ret_ty = try lowerFnRetTy(o, fn_info); |
| 5268 | 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 | 5314 | if (isByRef(ret_ty, mod)) { |
| 5272 | 5315 | // operand is a pointer however self.ret_ptr is null so that means |
| ... | ... | @@ -5311,7 +5354,7 @@ pub const FuncGen = struct { |
| 5311 | 5354 | } |
| 5312 | 5355 | const ptr = try self.resolveInst(un_op); |
| 5313 | 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 | 5358 | _ = try self.wip.ret(try self.wip.load(.normal, abi_ret_ty, ptr, alignment, "")); |
| 5316 | 5359 | return .none; |
| 5317 | 5360 | } |
| ... | ... | @@ -5334,7 +5377,7 @@ pub const FuncGen = struct { |
| 5334 | 5377 | const llvm_va_list_ty = try o.lowerType(va_list_ty); |
| 5335 | 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 | 5381 | const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment); |
| 5339 | 5382 | |
| 5340 | 5383 | _ = try self.wip.callIntrinsic(.normal, .none, .va_copy, &.{}, &.{ dest_list, src_list }, ""); |
| ... | ... | @@ -5358,7 +5401,7 @@ pub const FuncGen = struct { |
| 5358 | 5401 | const va_list_ty = self.typeOfIndex(inst); |
| 5359 | 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 | 5405 | const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment); |
| 5363 | 5406 | |
| 5364 | 5407 | _ = try self.wip.callIntrinsic(.normal, .none, .va_start, &.{}, &.{dest_list}, ""); |
| ... | ... | @@ -5690,7 +5733,7 @@ pub const FuncGen = struct { |
| 5690 | 5733 | return fg.wip.gepStruct(err_union_llvm_ty, err_union, offset, ""); |
| 5691 | 5734 | } else if (isByRef(err_union_ty, mod)) { |
| 5692 | 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 | 5737 | if (isByRef(payload_ty, mod)) { |
| 5695 | 5738 | if (can_elide_load) |
| 5696 | 5739 | return payload_ptr; |
| ... | ... | @@ -5997,7 +6040,7 @@ pub const FuncGen = struct { |
| 5997 | 6040 | if (self.canElideLoad(body_tail)) |
| 5998 | 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 | 6044 | return self.loadByRef(ptr, elem_ty, elem_alignment, .normal); |
| 6002 | 6045 | } |
| 6003 | 6046 | |
| ... | ... | @@ -6037,7 +6080,7 @@ pub const FuncGen = struct { |
| 6037 | 6080 | const elem_ptr = |
| 6038 | 6081 | try self.wip.gep(.inbounds, array_llvm_ty, array_llvm_val, &indices, ""); |
| 6039 | 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 | 6084 | return self.loadByRef(elem_ptr, elem_ty, elem_alignment, .normal); |
| 6042 | 6085 | } else { |
| 6043 | 6086 | const elem_llvm_ty = try o.lowerType(elem_ty); |
| ... | ... | @@ -6097,7 +6140,7 @@ pub const FuncGen = struct { |
| 6097 | 6140 | &.{rhs}, ""); |
| 6098 | 6141 | if (isByRef(elem_ty, mod)) { |
| 6099 | 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 | 6144 | return self.loadByRef(ptr, elem_ty, elem_alignment, .normal); |
| 6102 | 6145 | } |
| 6103 | 6146 | |
| ... | ... | @@ -6111,7 +6154,7 @@ pub const FuncGen = struct { |
| 6111 | 6154 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 6112 | 6155 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 6113 | 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 | 6159 | const base_ptr = try self.resolveInst(bin_op.lhs); |
| 6117 | 6160 | const rhs = try self.resolveInst(bin_op.rhs); |
| ... | ... | @@ -6163,8 +6206,8 @@ pub const FuncGen = struct { |
| 6163 | 6206 | switch (struct_ty.zigTypeTag(mod)) { |
| 6164 | 6207 | .Struct => switch (struct_ty.containerLayout(mod)) { |
| 6165 | 6208 | .Packed => { |
| 6166 | const struct_obj = mod.typeToStruct(struct_ty).?; | |
| 6167 | const bit_offset = struct_obj.packedFieldBitOffset(mod, field_index); | |
| 6209 | const struct_type = mod.typeToStruct(struct_ty).?; | |
| 6210 | const bit_offset = mod.structPackedFieldBitOffset(struct_type, field_index); | |
| 6168 | 6211 | const containing_int = struct_llvm_val; |
| 6169 | 6212 | const shift_amt = |
| 6170 | 6213 | try o.builder.intValue(containing_int.typeOfWip(&self.wip), bit_offset); |
| ... | ... | @@ -6220,16 +6263,14 @@ pub const FuncGen = struct { |
| 6220 | 6263 | const alignment = struct_ty.structFieldAlign(field_index, mod); |
| 6221 | 6264 | const field_ptr_ty = try mod.ptrType(.{ |
| 6222 | 6265 | .child = field_ty.toIntern(), |
| 6223 | .flags = .{ | |
| 6224 | .alignment = InternPool.Alignment.fromNonzeroByteUnits(alignment), | |
| 6225 | }, | |
| 6266 | .flags = .{ .alignment = alignment }, | |
| 6226 | 6267 | }); |
| 6227 | 6268 | if (isByRef(field_ty, mod)) { |
| 6228 | 6269 | if (canElideLoad(self, body_tail)) |
| 6229 | 6270 | return field_ptr; |
| 6230 | 6271 | |
| 6231 | assert(alignment != 0); | |
| 6232 | const field_alignment = Builder.Alignment.fromByteUnits(alignment); | |
| 6272 | assert(alignment != .none); | |
| 6273 | const field_alignment = alignment.toLlvm(); | |
| 6233 | 6274 | return self.loadByRef(field_ptr, field_ty, field_alignment, .normal); |
| 6234 | 6275 | } else { |
| 6235 | 6276 | return self.load(field_ptr, field_ptr_ty); |
| ... | ... | @@ -6238,11 +6279,11 @@ pub const FuncGen = struct { |
| 6238 | 6279 | .Union => { |
| 6239 | 6280 | const union_llvm_ty = try o.lowerType(struct_ty); |
| 6240 | 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 | 6283 | const field_ptr = |
| 6243 | 6284 | try self.wip.gepStruct(union_llvm_ty, struct_llvm_val, payload_index, ""); |
| 6244 | 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 | 6287 | if (isByRef(field_ty, mod)) { |
| 6247 | 6288 | if (canElideLoad(self, body_tail)) return field_ptr; |
| 6248 | 6289 | return self.loadByRef(field_ptr, field_ty, payload_alignment, .normal); |
| ... | ... | @@ -6457,7 +6498,7 @@ pub const FuncGen = struct { |
| 6457 | 6498 | if (isByRef(operand_ty, mod)) { |
| 6458 | 6499 | _ = dib.insertDeclareAtEnd(operand.toLlvm(&self.wip), di_local_var, debug_loc, insert_block); |
| 6459 | 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 | 6502 | const alloca = try self.buildAlloca(operand.typeOfWip(&self.wip), alignment); |
| 6462 | 6503 | _ = try self.wip.store(.normal, operand, alloca, alignment); |
| 6463 | 6504 | _ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block); |
| ... | ... | @@ -6612,7 +6653,7 @@ pub const FuncGen = struct { |
| 6612 | 6653 | llvm_param_values[llvm_param_i] = arg_llvm_value; |
| 6613 | 6654 | llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip); |
| 6614 | 6655 | } else { |
| 6615 | const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod)); | |
| 6656 | const alignment = arg_ty.abiAlignment(mod).toLlvm(); | |
| 6616 | 6657 | const arg_llvm_ty = try o.lowerType(arg_ty); |
| 6617 | 6658 | const load_inst = |
| 6618 | 6659 | try self.wip.load(.normal, arg_llvm_ty, arg_llvm_value, alignment, ""); |
| ... | ... | @@ -6624,7 +6665,7 @@ pub const FuncGen = struct { |
| 6624 | 6665 | llvm_param_values[llvm_param_i] = arg_llvm_value; |
| 6625 | 6666 | llvm_param_types[llvm_param_i] = arg_llvm_value.typeOfWip(&self.wip); |
| 6626 | 6667 | } else { |
| 6627 | const alignment = Builder.Alignment.fromByteUnits(arg_ty.abiAlignment(mod)); | |
| 6668 | const alignment = arg_ty.abiAlignment(mod).toLlvm(); | |
| 6628 | 6669 | const arg_ptr = try self.buildAlloca(arg_llvm_value.typeOfWip(&self.wip), alignment); |
| 6629 | 6670 | _ = try self.wip.store(.normal, arg_llvm_value, arg_ptr, alignment); |
| 6630 | 6671 | llvm_param_values[llvm_param_i] = arg_ptr; |
| ... | ... | @@ -6676,7 +6717,7 @@ pub const FuncGen = struct { |
| 6676 | 6717 | llvm_param_values[llvm_param_i] = llvm_rw_val; |
| 6677 | 6718 | llvm_param_types[llvm_param_i] = llvm_rw_val.typeOfWip(&self.wip); |
| 6678 | 6719 | } else { |
| 6679 | const alignment = Builder.Alignment.fromByteUnits(rw_ty.abiAlignment(mod)); | |
| 6720 | const alignment = rw_ty.abiAlignment(mod).toLlvm(); | |
| 6680 | 6721 | const loaded = try self.wip.load(.normal, llvm_elem_ty, llvm_rw_val, alignment, ""); |
| 6681 | 6722 | llvm_param_values[llvm_param_i] = loaded; |
| 6682 | 6723 | llvm_param_types[llvm_param_i] = llvm_elem_ty; |
| ... | ... | @@ -6837,7 +6878,7 @@ pub const FuncGen = struct { |
| 6837 | 6878 | const output_ptr = try self.resolveInst(output); |
| 6838 | 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 | 6882 | _ = try self.wip.store(.normal, output_value, output_ptr, alignment); |
| 6842 | 6883 | } else { |
| 6843 | 6884 | ret_val = output_value; |
| ... | ... | @@ -7030,7 +7071,7 @@ pub const FuncGen = struct { |
| 7030 | 7071 | if (operand_is_ptr) { |
| 7031 | 7072 | return self.wip.gepStruct(err_union_llvm_ty, operand, offset, ""); |
| 7032 | 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 | 7075 | const payload_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, offset, ""); |
| 7035 | 7076 | if (isByRef(payload_ty, mod)) { |
| 7036 | 7077 | if (self.canElideLoad(body_tail)) return payload_ptr; |
| ... | ... | @@ -7093,7 +7134,7 @@ pub const FuncGen = struct { |
| 7093 | 7134 | } |
| 7094 | 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 | 7138 | const error_offset = errUnionErrorOffset(payload_ty, mod); |
| 7098 | 7139 | // First set the non-error value. |
| 7099 | 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 | 7174 | const field_ty = struct_ty.structFieldType(field_index, mod); |
| 7134 | 7175 | const field_ptr_ty = try mod.ptrType(.{ |
| 7135 | 7176 | .child = field_ty.toIntern(), |
| 7136 | .flags = .{ | |
| 7137 | .alignment = InternPool.Alignment.fromNonzeroByteUnits(field_alignment), | |
| 7138 | }, | |
| 7177 | .flags = .{ .alignment = field_alignment }, | |
| 7139 | 7178 | }); |
| 7140 | 7179 | return self.load(field_ptr, field_ptr_ty); |
| 7141 | 7180 | } |
| ... | ... | @@ -7153,7 +7192,7 @@ pub const FuncGen = struct { |
| 7153 | 7192 | if (optional_ty.optionalReprIsPayload(mod)) return operand; |
| 7154 | 7193 | const llvm_optional_ty = try o.lowerType(optional_ty); |
| 7155 | 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 | 7196 | const optional_ptr = try self.buildAlloca(llvm_optional_ty, alignment); |
| 7158 | 7197 | const payload_ptr = try self.wip.gepStruct(llvm_optional_ty, optional_ptr, 0, ""); |
| 7159 | 7198 | const payload_ptr_ty = try mod.singleMutPtrType(payload_ty); |
| ... | ... | @@ -7181,10 +7220,10 @@ pub const FuncGen = struct { |
| 7181 | 7220 | const payload_offset = errUnionPayloadOffset(payload_ty, mod); |
| 7182 | 7221 | const error_offset = errUnionErrorOffset(payload_ty, mod); |
| 7183 | 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 | 7224 | const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment); |
| 7186 | 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 | 7227 | _ = try self.wip.store(.normal, ok_err_code, err_ptr, error_alignment); |
| 7189 | 7228 | const payload_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, payload_offset, ""); |
| 7190 | 7229 | const payload_ptr_ty = try mod.singleMutPtrType(payload_ty); |
| ... | ... | @@ -7210,10 +7249,10 @@ pub const FuncGen = struct { |
| 7210 | 7249 | const payload_offset = errUnionPayloadOffset(payload_ty, mod); |
| 7211 | 7250 | const error_offset = errUnionErrorOffset(payload_ty, mod); |
| 7212 | 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 | 7253 | const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment); |
| 7215 | 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 | 7256 | _ = try self.wip.store(.normal, operand, err_ptr, error_alignment); |
| 7218 | 7257 | const payload_ptr = try self.wip.gepStruct(err_un_llvm_ty, result_ptr, payload_offset, ""); |
| 7219 | 7258 | const payload_ptr_ty = try mod.singleMutPtrType(payload_ty); |
| ... | ... | @@ -7260,7 +7299,7 @@ pub const FuncGen = struct { |
| 7260 | 7299 | const access_kind: Builder.MemoryAccessKind = |
| 7261 | 7300 | if (vector_ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal; |
| 7262 | 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 | 7303 | const loaded = try self.wip.load(access_kind, elem_llvm_ty, vector_ptr, alignment, ""); |
| 7265 | 7304 | |
| 7266 | 7305 | const new_vector = try self.wip.insertElement(loaded, operand, index, ""); |
| ... | ... | @@ -7690,7 +7729,7 @@ pub const FuncGen = struct { |
| 7690 | 7729 | const overflow_index = o.llvmFieldIndex(inst_ty, 1).?; |
| 7691 | 7730 | |
| 7692 | 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 | 7733 | const alloca_inst = try self.buildAlloca(llvm_inst_ty, result_alignment); |
| 7695 | 7734 | { |
| 7696 | 7735 | const field_ptr = try self.wip.gepStruct(llvm_inst_ty, alloca_inst, result_index, ""); |
| ... | ... | @@ -8048,7 +8087,7 @@ pub const FuncGen = struct { |
| 8048 | 8087 | const overflow_index = o.llvmFieldIndex(dest_ty, 1).?; |
| 8049 | 8088 | |
| 8050 | 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 | 8091 | const alloca_inst = try self.buildAlloca(llvm_dest_ty, result_alignment); |
| 8053 | 8092 | { |
| 8054 | 8093 | const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, result_index, ""); |
| ... | ... | @@ -8321,7 +8360,7 @@ pub const FuncGen = struct { |
| 8321 | 8360 | const array_ptr = try self.buildAlloca(llvm_dest_ty, .default); |
| 8322 | 8361 | const bitcast_ok = elem_ty.bitSize(mod) == elem_ty.abiSize(mod) * 8; |
| 8323 | 8362 | if (bitcast_ok) { |
| 8324 | const alignment = Builder.Alignment.fromByteUnits(inst_ty.abiAlignment(mod)); | |
| 8363 | const alignment = inst_ty.abiAlignment(mod).toLlvm(); | |
| 8325 | 8364 | _ = try self.wip.store(.normal, operand, array_ptr, alignment); |
| 8326 | 8365 | } else { |
| 8327 | 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 | 8388 | if (bitcast_ok) { |
| 8350 | 8389 | // The array is aligned to the element's alignment, while the vector might have a completely |
| 8351 | 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 | 8392 | return self.wip.load(.normal, llvm_vector_ty, operand, alignment, ""); |
| 8354 | 8393 | } else { |
| 8355 | 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 | 8413 | } |
| 8375 | 8414 | |
| 8376 | 8415 | if (operand_is_ref) { |
| 8377 | const alignment = Builder.Alignment.fromByteUnits(operand_ty.abiAlignment(mod)); | |
| 8416 | const alignment = operand_ty.abiAlignment(mod).toLlvm(); | |
| 8378 | 8417 | return self.wip.load(.normal, llvm_dest_ty, operand, alignment, ""); |
| 8379 | 8418 | } |
| 8380 | 8419 | |
| 8381 | 8420 | if (result_is_ref) { |
| 8382 | const alignment = Builder.Alignment.fromByteUnits( | |
| 8383 | @max(operand_ty.abiAlignment(mod), inst_ty.abiAlignment(mod)), | |
| 8384 | ); | |
| 8421 | const alignment = operand_ty.abiAlignment(mod).max(inst_ty.abiAlignment(mod)).toLlvm(); | |
| 8385 | 8422 | const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment); |
| 8386 | 8423 | _ = try self.wip.store(.normal, operand, result_ptr, alignment); |
| 8387 | 8424 | return result_ptr; |
| ... | ... | @@ -8393,9 +8430,7 @@ pub const FuncGen = struct { |
| 8393 | 8430 | // Both our operand and our result are values, not pointers, |
| 8394 | 8431 | // but LLVM won't let us bitcast struct values or vectors with padding bits. |
| 8395 | 8432 | // Therefore, we store operand to alloca, then load for result. |
| 8396 | const alignment = Builder.Alignment.fromByteUnits( | |
| 8397 | @max(operand_ty.abiAlignment(mod), inst_ty.abiAlignment(mod)), | |
| 8398 | ); | |
| 8433 | const alignment = operand_ty.abiAlignment(mod).max(inst_ty.abiAlignment(mod)).toLlvm(); | |
| 8399 | 8434 | const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment); |
| 8400 | 8435 | _ = try self.wip.store(.normal, operand, result_ptr, alignment); |
| 8401 | 8436 | return self.wip.load(.normal, llvm_dest_ty, result_ptr, alignment, ""); |
| ... | ... | @@ -8441,7 +8476,7 @@ pub const FuncGen = struct { |
| 8441 | 8476 | if (isByRef(inst_ty, mod)) { |
| 8442 | 8477 | _ = dib.insertDeclareAtEnd(arg_val.toLlvm(&self.wip), di_local_var, debug_loc, insert_block); |
| 8443 | 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 | 8480 | const alloca = try self.buildAlloca(arg_val.typeOfWip(&self.wip), alignment); |
| 8446 | 8481 | _ = try self.wip.store(.normal, arg_val, alloca, alignment); |
| 8447 | 8482 | _ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block); |
| ... | ... | @@ -8462,7 +8497,7 @@ pub const FuncGen = struct { |
| 8462 | 8497 | return (try o.lowerPtrToVoid(ptr_ty)).toValue(); |
| 8463 | 8498 | |
| 8464 | 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 | 8501 | return self.buildAlloca(pointee_llvm_ty, alignment); |
| 8467 | 8502 | } |
| 8468 | 8503 | |
| ... | ... | @@ -8475,7 +8510,7 @@ pub const FuncGen = struct { |
| 8475 | 8510 | return (try o.lowerPtrToVoid(ptr_ty)).toValue(); |
| 8476 | 8511 | if (self.ret_ptr != .none) return self.ret_ptr; |
| 8477 | 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 | 8514 | return self.buildAlloca(ret_llvm_ty, alignment); |
| 8480 | 8515 | } |
| 8481 | 8516 | |
| ... | ... | @@ -8515,7 +8550,7 @@ pub const FuncGen = struct { |
| 8515 | 8550 | const len = try o.builder.intValue(try o.lowerType(Type.usize), operand_ty.abiSize(mod)); |
| 8516 | 8551 | _ = try self.wip.callMemSet( |
| 8517 | 8552 | dest_ptr, |
| 8518 | Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod)), | |
| 8553 | ptr_ty.ptrAlignment(mod).toLlvm(), | |
| 8519 | 8554 | if (safety) try o.builder.intValue(.i8, 0xaa) else try o.builder.undefValue(.i8), |
| 8520 | 8555 | len, |
| 8521 | 8556 | if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal, |
| ... | ... | @@ -8646,7 +8681,7 @@ pub const FuncGen = struct { |
| 8646 | 8681 | self.sync_scope, |
| 8647 | 8682 | toLlvmAtomicOrdering(extra.successOrder()), |
| 8648 | 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 | 8720 | |
| 8686 | 8721 | const access_kind: Builder.MemoryAccessKind = |
| 8687 | 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 | 8725 | if (llvm_abi_ty != .none) { |
| 8691 | 8726 | // operand needs widening and truncating or bitcasting. |
| ... | ... | @@ -8741,9 +8776,10 @@ pub const FuncGen = struct { |
| 8741 | 8776 | if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none; |
| 8742 | 8777 | const ordering = toLlvmAtomicOrdering(atomic_load.order); |
| 8743 | 8778 | const llvm_abi_ty = try o.getAtomicAbiType(elem_ty, false); |
| 8744 | const ptr_alignment = Builder.Alignment.fromByteUnits( | |
| 8745 | info.flags.alignment.toByteUnitsOptional() orelse info.child.toType().abiAlignment(mod), | |
| 8746 | ); | |
| 8779 | const ptr_alignment = (if (info.flags.alignment != .none) | |
| 8780 | @as(InternPool.Alignment, info.flags.alignment) | |
| 8781 | else | |
| 8782 | info.child.toType().abiAlignment(mod)).toLlvm(); | |
| 8747 | 8783 | const access_kind: Builder.MemoryAccessKind = |
| 8748 | 8784 | if (info.flags.is_volatile) .@"volatile" else .normal; |
| 8749 | 8785 | const elem_llvm_ty = try o.lowerType(elem_ty); |
| ... | ... | @@ -8807,7 +8843,7 @@ pub const FuncGen = struct { |
| 8807 | 8843 | const dest_slice = try self.resolveInst(bin_op.lhs); |
| 8808 | 8844 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 8809 | 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 | 8847 | const dest_ptr = try self.sliceOrArrayPtr(dest_slice, ptr_ty); |
| 8812 | 8848 | const access_kind: Builder.MemoryAccessKind = |
| 8813 | 8849 | if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal; |
| ... | ... | @@ -8911,15 +8947,13 @@ pub const FuncGen = struct { |
| 8911 | 8947 | |
| 8912 | 8948 | self.wip.cursor = .{ .block = body_block }; |
| 8913 | 8949 | const elem_abi_align = elem_ty.abiAlignment(mod); |
| 8914 | const it_ptr_align = Builder.Alignment.fromByteUnits( | |
| 8915 | @min(elem_abi_align, dest_ptr_align.toByteUnits() orelse std.math.maxInt(u64)), | |
| 8916 | ); | |
| 8950 | const it_ptr_align = InternPool.Alignment.fromLlvm(dest_ptr_align).min(elem_abi_align).toLlvm(); | |
| 8917 | 8951 | if (isByRef(elem_ty, mod)) { |
| 8918 | 8952 | _ = try self.wip.callMemCpy( |
| 8919 | 8953 | it_ptr.toValue(), |
| 8920 | 8954 | it_ptr_align, |
| 8921 | 8955 | value, |
| 8922 | Builder.Alignment.fromByteUnits(elem_abi_align), | |
| 8956 | elem_abi_align.toLlvm(), | |
| 8923 | 8957 | try o.builder.intValue(llvm_usize_ty, elem_abi_size), |
| 8924 | 8958 | access_kind, |
| 8925 | 8959 | ); |
| ... | ... | @@ -8985,9 +9019,9 @@ pub const FuncGen = struct { |
| 8985 | 9019 | self.wip.cursor = .{ .block = memcpy_block }; |
| 8986 | 9020 | _ = try self.wip.callMemCpy( |
| 8987 | 9021 | dest_ptr, |
| 8988 | Builder.Alignment.fromByteUnits(dest_ptr_ty.ptrAlignment(mod)), | |
| 9022 | dest_ptr_ty.ptrAlignment(mod).toLlvm(), | |
| 8989 | 9023 | src_ptr, |
| 8990 | Builder.Alignment.fromByteUnits(src_ptr_ty.ptrAlignment(mod)), | |
| 9024 | src_ptr_ty.ptrAlignment(mod).toLlvm(), | |
| 8991 | 9025 | len, |
| 8992 | 9026 | access_kind, |
| 8993 | 9027 | ); |
| ... | ... | @@ -8998,9 +9032,9 @@ pub const FuncGen = struct { |
| 8998 | 9032 | |
| 8999 | 9033 | _ = try self.wip.callMemCpy( |
| 9000 | 9034 | dest_ptr, |
| 9001 | Builder.Alignment.fromByteUnits(dest_ptr_ty.ptrAlignment(mod)), | |
| 9035 | dest_ptr_ty.ptrAlignment(mod).toLlvm(), | |
| 9002 | 9036 | src_ptr, |
| 9003 | Builder.Alignment.fromByteUnits(src_ptr_ty.ptrAlignment(mod)), | |
| 9037 | src_ptr_ty.ptrAlignment(mod).toLlvm(), | |
| 9004 | 9038 | len, |
| 9005 | 9039 | access_kind, |
| 9006 | 9040 | ); |
| ... | ... | @@ -9021,7 +9055,7 @@ pub const FuncGen = struct { |
| 9021 | 9055 | _ = try self.wip.store(.normal, new_tag, union_ptr, .default); |
| 9022 | 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 | 9059 | const tag_field_ptr = try self.wip.gepStruct(try o.lowerType(un_ty), union_ptr, tag_index, ""); |
| 9026 | 9060 | // TODO alignment on this store |
| 9027 | 9061 | _ = try self.wip.store(.normal, new_tag, tag_field_ptr, .default); |
| ... | ... | @@ -9040,13 +9074,13 @@ pub const FuncGen = struct { |
| 9040 | 9074 | const llvm_un_ty = try o.lowerType(un_ty); |
| 9041 | 9075 | if (layout.payload_size == 0) |
| 9042 | 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 | 9078 | const tag_field_ptr = try self.wip.gepStruct(llvm_un_ty, union_handle, tag_index, ""); |
| 9045 | 9079 | const llvm_tag_ty = llvm_un_ty.structFields(&o.builder)[tag_index]; |
| 9046 | 9080 | return self.wip.load(.normal, llvm_tag_ty, tag_field_ptr, .default, ""); |
| 9047 | 9081 | } else { |
| 9048 | 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 | 9084 | return self.wip.extractValue(union_handle, &.{tag_index}, ""); |
| 9051 | 9085 | } |
| 9052 | 9086 | } |
| ... | ... | @@ -9605,6 +9639,7 @@ pub const FuncGen = struct { |
| 9605 | 9639 | fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 9606 | 9640 | const o = self.dg.object; |
| 9607 | 9641 | const mod = o.module; |
| 9642 | const ip = &mod.intern_pool; | |
| 9608 | 9643 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 9609 | 9644 | const result_ty = self.typeOfIndex(inst); |
| 9610 | 9645 | const len: usize = @intCast(result_ty.arrayLen(mod)); |
| ... | ... | @@ -9622,23 +9657,21 @@ pub const FuncGen = struct { |
| 9622 | 9657 | return vector; |
| 9623 | 9658 | }, |
| 9624 | 9659 | .Struct => { |
| 9625 | if (result_ty.containerLayout(mod) == .Packed) { | |
| 9626 | const struct_obj = mod.typeToStruct(result_ty).?; | |
| 9627 | assert(struct_obj.haveLayout()); | |
| 9628 | const big_bits = struct_obj.backing_int_ty.bitSize(mod); | |
| 9660 | if (mod.typeToPackedStruct(result_ty)) |struct_type| { | |
| 9661 | const backing_int_ty = struct_type.backingIntType(ip).*; | |
| 9662 | assert(backing_int_ty != .none); | |
| 9663 | const big_bits = backing_int_ty.toType().bitSize(mod); | |
| 9629 | 9664 | const int_ty = try o.builder.intType(@intCast(big_bits)); |
| 9630 | const fields = struct_obj.fields.values(); | |
| 9631 | 9665 | comptime assert(Type.packed_struct_layout_version == 2); |
| 9632 | 9666 | var running_int = try o.builder.intValue(int_ty, 0); |
| 9633 | 9667 | var running_bits: u16 = 0; |
| 9634 | for (elements, 0..) |elem, i| { | |
| 9635 | const field = fields[i]; | |
| 9636 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 9668 | for (elements, struct_type.field_types.get(ip)) |elem, field_ty| { | |
| 9669 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 9637 | 9670 | |
| 9638 | 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 | 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 | 9675 | try self.wip.cast(.ptrtoint, non_int_val, small_int_ty, "") |
| 9643 | 9676 | else |
| 9644 | 9677 | try self.wip.cast(.bitcast, non_int_val, small_int_ty, ""); |
| ... | ... | @@ -9652,10 +9685,12 @@ pub const FuncGen = struct { |
| 9652 | 9685 | return running_int; |
| 9653 | 9686 | } |
| 9654 | 9687 | |
| 9688 | assert(result_ty.containerLayout(mod) != .Packed); | |
| 9689 | ||
| 9655 | 9690 | if (isByRef(result_ty, mod)) { |
| 9656 | 9691 | // TODO in debug builds init to undef so that the padding will be 0xaa |
| 9657 | 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 | 9694 | const alloca_inst = try self.buildAlloca(llvm_result_ty, alignment); |
| 9660 | 9695 | |
| 9661 | 9696 | for (elements, 0..) |elem, i| { |
| ... | ... | @@ -9668,9 +9703,7 @@ pub const FuncGen = struct { |
| 9668 | 9703 | const field_ptr_ty = try mod.ptrType(.{ |
| 9669 | 9704 | .child = self.typeOf(elem).toIntern(), |
| 9670 | 9705 | .flags = .{ |
| 9671 | .alignment = InternPool.Alignment.fromNonzeroByteUnits( | |
| 9672 | result_ty.structFieldAlign(i, mod), | |
| 9673 | ), | |
| 9706 | .alignment = result_ty.structFieldAlign(i, mod), | |
| 9674 | 9707 | }, |
| 9675 | 9708 | }); |
| 9676 | 9709 | try self.store(field_ptr, field_ptr_ty, llvm_elem, .none); |
| ... | ... | @@ -9694,7 +9727,7 @@ pub const FuncGen = struct { |
| 9694 | 9727 | |
| 9695 | 9728 | const llvm_usize = try o.lowerType(Type.usize); |
| 9696 | 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 | 9731 | const alloca_inst = try self.buildAlloca(llvm_result_ty, alignment); |
| 9699 | 9732 | |
| 9700 | 9733 | const array_info = result_ty.arrayInfo(mod); |
| ... | ... | @@ -9770,7 +9803,7 @@ pub const FuncGen = struct { |
| 9770 | 9803 | // necessarily match the format that we need, depending on which tag is active. |
| 9771 | 9804 | // We must construct the correct unnamed struct type here, in order to then set |
| 9772 | 9805 | // the fields appropriately. |
| 9773 | const alignment = Builder.Alignment.fromByteUnits(layout.abi_align); | |
| 9806 | const alignment = layout.abi_align.toLlvm(); | |
| 9774 | 9807 | const result_ptr = try self.buildAlloca(union_llvm_ty, alignment); |
| 9775 | 9808 | const llvm_payload = try self.resolveInst(extra.init); |
| 9776 | 9809 | const field_ty = union_obj.field_types.get(ip)[extra.field_index].toType(); |
| ... | ... | @@ -9799,7 +9832,7 @@ pub const FuncGen = struct { |
| 9799 | 9832 | const tag_ty = try o.lowerType(union_obj.enum_tag_ty.toType()); |
| 9800 | 9833 | var fields: [3]Builder.Type = undefined; |
| 9801 | 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 | 9836 | fields = .{ tag_ty, payload_ty, undefined }; |
| 9804 | 9837 | } else { |
| 9805 | 9838 | fields = .{ payload_ty, tag_ty, undefined }; |
| ... | ... | @@ -9815,7 +9848,7 @@ pub const FuncGen = struct { |
| 9815 | 9848 | // tag and the payload. |
| 9816 | 9849 | const field_ptr_ty = try mod.ptrType(.{ |
| 9817 | 9850 | .child = field_ty.toIntern(), |
| 9818 | .flags = .{ .alignment = InternPool.Alignment.fromNonzeroByteUnits(field_align) }, | |
| 9851 | .flags = .{ .alignment = field_align }, | |
| 9819 | 9852 | }); |
| 9820 | 9853 | if (layout.tag_size == 0) { |
| 9821 | 9854 | const indices = [3]Builder.Value{ usize_zero, i32_zero, i32_zero }; |
| ... | ... | @@ -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 | 9864 | const indices: [3]Builder.Value = |
| 9832 | 9865 | .{ usize_zero, try o.builder.intValue(.i32, payload_index), i32_zero }; |
| 9833 | 9866 | const len: usize = if (field_size == layout.payload_size) 2 else 3; |
| ... | ... | @@ -9836,12 +9869,12 @@ pub const FuncGen = struct { |
| 9836 | 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 | 9873 | const indices: [2]Builder.Value = .{ usize_zero, try o.builder.intValue(.i32, tag_index) }; |
| 9841 | 9874 | const field_ptr = try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, &indices, ""); |
| 9842 | 9875 | const tag_ty = try o.lowerType(union_obj.enum_tag_ty.toType()); |
| 9843 | 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 | 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 | 10011 | variable_index.setMutability(.constant, &o.builder); |
| 9979 | 10012 | variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); |
| 9980 | 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 | 10015 | &o.builder, |
| 9983 | 10016 | ); |
| 9984 | 10017 | |
| ... | ... | @@ -10023,7 +10056,7 @@ pub const FuncGen = struct { |
| 10023 | 10056 | // We have a pointer and we need to return a pointer to the first field. |
| 10024 | 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 | 10060 | if (isByRef(payload_ty, mod)) { |
| 10028 | 10061 | if (can_elide_load) |
| 10029 | 10062 | return payload_ptr; |
| ... | ... | @@ -10050,7 +10083,7 @@ pub const FuncGen = struct { |
| 10050 | 10083 | const mod = o.module; |
| 10051 | 10084 | |
| 10052 | 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 | 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 | 10156 | .Union => { |
| 10124 | 10157 | const layout = struct_ty.unionGetLayout(mod); |
| 10125 | 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 | 10160 | const union_llvm_ty = try o.lowerType(struct_ty); |
| 10128 | 10161 | return self.wip.gepStruct(union_llvm_ty, struct_ptr, payload_index, ""); |
| 10129 | 10162 | }, |
| ... | ... | @@ -10142,9 +10175,7 @@ pub const FuncGen = struct { |
| 10142 | 10175 | const o = fg.dg.object; |
| 10143 | 10176 | const mod = o.module; |
| 10144 | 10177 | const pointee_llvm_ty = try o.lowerType(pointee_type); |
| 10145 | const result_align = Builder.Alignment.fromByteUnits( | |
| 10146 | @max(ptr_alignment.toByteUnits() orelse 0, pointee_type.abiAlignment(mod)), | |
| 10147 | ); | |
| 10178 | const result_align = InternPool.Alignment.fromLlvm(ptr_alignment).max(pointee_type.abiAlignment(mod)).toLlvm(); | |
| 10148 | 10179 | const result_ptr = try fg.buildAlloca(pointee_llvm_ty, result_align); |
| 10149 | 10180 | const size_bytes = pointee_type.abiSize(mod); |
| 10150 | 10181 | _ = try fg.wip.callMemCpy( |
| ... | ... | @@ -10168,9 +10199,11 @@ pub const FuncGen = struct { |
| 10168 | 10199 | const elem_ty = info.child.toType(); |
| 10169 | 10200 | if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return .none; |
| 10170 | 10201 | |
| 10171 | const ptr_alignment = Builder.Alignment.fromByteUnits( | |
| 10172 | info.flags.alignment.toByteUnitsOptional() orelse elem_ty.abiAlignment(mod), | |
| 10173 | ); | |
| 10202 | const ptr_alignment = (if (info.flags.alignment != .none) | |
| 10203 | @as(InternPool.Alignment, info.flags.alignment) | |
| 10204 | else | |
| 10205 | elem_ty.abiAlignment(mod)).toLlvm(); | |
| 10206 | ||
| 10174 | 10207 | const access_kind: Builder.MemoryAccessKind = |
| 10175 | 10208 | if (info.flags.is_volatile) .@"volatile" else .normal; |
| 10176 | 10209 | |
| ... | ... | @@ -10201,7 +10234,7 @@ pub const FuncGen = struct { |
| 10201 | 10234 | const elem_llvm_ty = try o.lowerType(elem_ty); |
| 10202 | 10235 | |
| 10203 | 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 | 10238 | const result_ptr = try self.buildAlloca(elem_llvm_ty, result_align); |
| 10206 | 10239 | |
| 10207 | 10240 | const same_size_int = try o.builder.intType(@intCast(elem_bits)); |
| ... | ... | @@ -10239,7 +10272,7 @@ pub const FuncGen = struct { |
| 10239 | 10272 | if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) { |
| 10240 | 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 | 10276 | const access_kind: Builder.MemoryAccessKind = |
| 10244 | 10277 | if (info.flags.is_volatile) .@"volatile" else .normal; |
| 10245 | 10278 | |
| ... | ... | @@ -10305,7 +10338,7 @@ pub const FuncGen = struct { |
| 10305 | 10338 | ptr, |
| 10306 | 10339 | ptr_alignment, |
| 10307 | 10340 | elem, |
| 10308 | Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod)), | |
| 10341 | elem_ty.abiAlignment(mod).toLlvm(), | |
| 10309 | 10342 | try o.builder.intValue(try o.lowerType(Type.usize), elem_ty.abiSize(mod)), |
| 10310 | 10343 | access_kind, |
| 10311 | 10344 | ); |
| ... | ... | @@ -10337,7 +10370,7 @@ pub const FuncGen = struct { |
| 10337 | 10370 | if (!target_util.hasValgrindSupport(target)) return default_value; |
| 10338 | 10371 | |
| 10339 | 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 | 10375 | const array_llvm_ty = try o.builder.arrayType(6, llvm_usize); |
| 10343 | 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 | 10751 | |
| 10719 | 10752 | fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type { |
| 10720 | 10753 | const mod = o.module; |
| 10754 | const ip = &mod.intern_pool; | |
| 10721 | 10755 | const return_type = fn_info.return_type.toType(); |
| 10722 | 10756 | if (isScalar(mod, return_type)) { |
| 10723 | 10757 | return o.lowerType(return_type); |
| ... | ... | @@ -10761,12 +10795,16 @@ fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.E |
| 10761 | 10795 | const first_non_integer = std.mem.indexOfNone(x86_64_abi.Class, &classes, &.{.integer}); |
| 10762 | 10796 | if (first_non_integer == null or classes[first_non_integer.?] == .none) { |
| 10763 | 10797 | assert(first_non_integer orelse classes.len == types_index); |
| 10764 | if (mod.intern_pool.indexToKey(return_type.toIntern()) == .struct_type) { | |
| 10765 | var struct_it = return_type.iterateStructOffsets(mod); | |
| 10766 | while (struct_it.next()) |_| {} | |
| 10767 | assert((std.math.divCeil(u64, struct_it.offset, 8) catch unreachable) == types_index); | |
| 10768 | if (struct_it.offset % 8 > 0) types_buffer[types_index - 1] = | |
| 10769 | try o.builder.intType(@intCast(struct_it.offset % 8 * 8)); | |
| 10798 | switch (ip.indexToKey(return_type.toIntern())) { | |
| 10799 | .struct_type => |struct_type| { | |
| 10800 | assert(struct_type.haveLayout(ip)); | |
| 10801 | const size: u64 = struct_type.size(ip).*; | |
| 10802 | assert((std.math.divCeil(u64, size, 8) catch unreachable) == types_index); | |
| 10803 | if (size % 8 > 0) { | |
| 10804 | types_buffer[types_index - 1] = try o.builder.intType(@intCast(size % 8 * 8)); | |
| 10805 | } | |
| 10806 | }, | |
| 10807 | else => {}, | |
| 10770 | 10808 | } |
| 10771 | 10809 | if (types_index == 1) return types_buffer[0]; |
| 10772 | 10810 | } |
| ... | ... | @@ -10982,6 +11020,7 @@ const ParamTypeIterator = struct { |
| 10982 | 11020 | |
| 10983 | 11021 | fn nextSystemV(it: *ParamTypeIterator, ty: Type) Allocator.Error!?Lowering { |
| 10984 | 11022 | const mod = it.object.module; |
| 11023 | const ip = &mod.intern_pool; | |
| 10985 | 11024 | const classes = x86_64_abi.classifySystemV(ty, mod, .arg); |
| 10986 | 11025 | if (classes[0] == .memory) { |
| 10987 | 11026 | it.zig_index += 1; |
| ... | ... | @@ -11037,12 +11076,17 @@ const ParamTypeIterator = struct { |
| 11037 | 11076 | it.llvm_index += 1; |
| 11038 | 11077 | return .abi_sized_int; |
| 11039 | 11078 | } |
| 11040 | if (mod.intern_pool.indexToKey(ty.toIntern()) == .struct_type) { | |
| 11041 | var struct_it = ty.iterateStructOffsets(mod); | |
| 11042 | while (struct_it.next()) |_| {} | |
| 11043 | assert((std.math.divCeil(u64, struct_it.offset, 8) catch unreachable) == types_index); | |
| 11044 | if (struct_it.offset % 8 > 0) types_buffer[types_index - 1] = | |
| 11045 | try it.object.builder.intType(@intCast(struct_it.offset % 8 * 8)); | |
| 11079 | switch (ip.indexToKey(ty.toIntern())) { | |
| 11080 | .struct_type => |struct_type| { | |
| 11081 | assert(struct_type.haveLayout(ip)); | |
| 11082 | const size: u64 = struct_type.size(ip).*; | |
| 11083 | assert((std.math.divCeil(u64, size, 8) catch unreachable) == types_index); | |
| 11084 | if (size % 8 > 0) { | |
| 11085 | types_buffer[types_index - 1] = | |
| 11086 | try it.object.builder.intType(@intCast(size % 8 * 8)); | |
| 11087 | } | |
| 11088 | }, | |
| 11089 | else => {}, | |
| 11046 | 11090 | } |
| 11047 | 11091 | } |
| 11048 | 11092 | it.types_len = types_index; |
| ... | ... | @@ -11137,8 +11181,6 @@ fn isByRef(ty: Type, mod: *Module) bool { |
| 11137 | 11181 | |
| 11138 | 11182 | .Array, .Frame => return ty.hasRuntimeBits(mod), |
| 11139 | 11183 | .Struct => { |
| 11140 | // Packed structs are represented to LLVM as integers. | |
| 11141 | if (ty.containerLayout(mod) == .Packed) return false; | |
| 11142 | 11184 | const struct_type = switch (ip.indexToKey(ty.toIntern())) { |
| 11143 | 11185 | .anon_struct_type => |tuple| { |
| 11144 | 11186 | var count: usize = 0; |
| ... | ... | @@ -11154,14 +11196,18 @@ fn isByRef(ty: Type, mod: *Module) bool { |
| 11154 | 11196 | .struct_type => |s| s, |
| 11155 | 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 | 11207 | count += 1; |
| 11163 | 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 | 11212 | return false; |
| 11167 | 11213 | }, |
| ... | ... | @@ -11362,11 +11408,11 @@ fn buildAllocaInner( |
| 11362 | 11408 | } |
| 11363 | 11409 | |
| 11364 | 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 | 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 | 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 | 792 | }, |
| 793 | 793 | .vector_type => return dg.todo("indirect constant of type {}", .{ty.fmt(mod)}), |
| 794 | 794 | .struct_type => { |
| 795 | const struct_ty = mod.typeToStruct(ty).?; | |
| 796 | if (struct_ty.layout == .Packed) { | |
| 795 | const struct_type = mod.typeToStruct(ty).?; | |
| 796 | if (struct_type.layout == .Packed) { | |
| 797 | 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 | 802 | const struct_begin = self.size; |
| 801 | for (struct_ty.fields.values(), 0..) |field, i| { | |
| 802 | if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue; | |
| 803 | for (struct_type.field_types.get(ip), 0..) |field_ty, i_usize| { | |
| 804 | const i: u32 = @intCast(i_usize); | |
| 805 | if (struct_type.fieldIsComptime(ip, i)) continue; | |
| 806 | if (!field_ty.toType().hasRuntimeBits(mod)) continue; | |
| 803 | 807 | |
| 804 | 808 | const field_val = switch (aggregate.storage) { |
| 805 | 809 | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ |
| 806 | .ty = field.ty.toIntern(), | |
| 810 | .ty = field_ty, | |
| 807 | 811 | .storage = .{ .u64 = bytes[i] }, |
| 808 | 812 | } }), |
| 809 | 813 | .elems => |elems| elems[i], |
| 810 | 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 | 818 | // Add padding if required. |
| 815 | 819 | // TODO: Add to type generation as well? |
| ... | ... | @@ -838,7 +842,7 @@ pub const DeclGen = struct { |
| 838 | 842 | const active_field_ty = union_obj.field_types.get(ip)[active_field].toType(); |
| 839 | 843 | |
| 840 | 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 | 847 | if (has_tag and tag_first) { |
| 844 | 848 | try self.lower(ty.unionTagTypeSafety(mod).?, un.tag.toValue()); |
| ... | ... | @@ -1094,7 +1098,7 @@ pub const DeclGen = struct { |
| 1094 | 1098 | val, |
| 1095 | 1099 | .UniformConstant, |
| 1096 | 1100 | false, |
| 1097 | alignment, | |
| 1101 | @intCast(alignment.toByteUnits(0)), | |
| 1098 | 1102 | ); |
| 1099 | 1103 | log.debug("indirect constant: index = {}", .{@intFromEnum(spv_decl_index)}); |
| 1100 | 1104 | try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {}); |
| ... | ... | @@ -1180,7 +1184,7 @@ pub const DeclGen = struct { |
| 1180 | 1184 | var member_names = std.BoundedArray(CacheString, 4){}; |
| 1181 | 1185 | |
| 1182 | 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 | 1188 | const u8_ty_ref = try self.intType(.unsigned, 8); // TODO: What if Int8Type is not enabled? |
| 1185 | 1189 | |
| 1186 | 1190 | if (has_tag and tag_first) { |
| ... | ... | @@ -1333,7 +1337,7 @@ pub const DeclGen = struct { |
| 1333 | 1337 | } }); |
| 1334 | 1338 | }, |
| 1335 | 1339 | .Struct => { |
| 1336 | const struct_ty = switch (ip.indexToKey(ty.toIntern())) { | |
| 1340 | const struct_type = switch (ip.indexToKey(ty.toIntern())) { | |
| 1337 | 1341 | .anon_struct_type => |tuple| { |
| 1338 | 1342 | const member_types = try self.gpa.alloc(CacheRef, tuple.values.len); |
| 1339 | 1343 | defer self.gpa.free(member_types); |
| ... | ... | @@ -1350,13 +1354,12 @@ pub const DeclGen = struct { |
| 1350 | 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 | 1358 | else => unreachable, |
| 1355 | 1359 | }; |
| 1356 | 1360 | |
| 1357 | const struct_obj = mod.structPtrUnwrap(struct_ty.index).?; | |
| 1358 | if (struct_obj.layout == .Packed) { | |
| 1359 | return try self.resolveType(struct_obj.backing_int_ty, .direct); | |
| 1361 | if (struct_type.layout == .Packed) { | |
| 1362 | return try self.resolveType(struct_type.backingIntType(ip).toType(), .direct); | |
| 1360 | 1363 | } |
| 1361 | 1364 | |
| 1362 | 1365 | var member_types = std.ArrayList(CacheRef).init(self.gpa); |
| ... | ... | @@ -1365,16 +1368,15 @@ pub const DeclGen = struct { |
| 1365 | 1368 | var member_names = std.ArrayList(CacheString).init(self.gpa); |
| 1366 | 1369 | defer member_names.deinit(); |
| 1367 | 1370 | |
| 1368 | var it = struct_obj.runtimeFieldIterator(mod); | |
| 1369 | while (it.next()) |field_and_index| { | |
| 1370 | const field = field_and_index.field; | |
| 1371 | const index = field_and_index.index; | |
| 1372 | const field_name = ip.stringToSlice(struct_obj.fields.keys()[index]); | |
| 1373 | try member_types.append(try self.resolveType(field.ty, .indirect)); | |
| 1371 | var it = struct_type.iterateRuntimeOrder(ip); | |
| 1372 | while (it.next()) |field_index| { | |
| 1373 | const field_ty = struct_type.field_types.get(ip)[field_index]; | |
| 1374 | const field_name = ip.stringToSlice(struct_type.field_names.get(ip)[field_index]); | |
| 1375 | try member_types.append(try self.resolveType(field_ty.toType(), .indirect)); | |
| 1374 | 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 | 1381 | return try self.spv.resolve(.{ .struct_type = .{ |
| 1380 | 1382 | .name = try self.spv.resolveString(name), |
| ... | ... | @@ -1500,7 +1502,7 @@ pub const DeclGen = struct { |
| 1500 | 1502 | const error_align = Type.anyerror.abiAlignment(mod); |
| 1501 | 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 | 1506 | return .{ |
| 1505 | 1507 | .payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(mod), |
| 1506 | 1508 | .error_first = error_first, |
| ... | ... | @@ -1662,7 +1664,7 @@ pub const DeclGen = struct { |
| 1662 | 1664 | init_val, |
| 1663 | 1665 | actual_storage_class, |
| 1664 | 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 | 2605 | if (layout.payload_size == 0) return union_handle; |
| 2604 | 2606 | |
| 2605 | 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 | 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 | 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 | 1122 | const atom = self.getAtomPtr(atom_index); |
| 1123 | 1123 | atom.size = @as(u32, @intCast(code.len)); |
| 1124 | 1124 | atom.getSymbolPtr(self).value = try self.allocateAtom(atom_index, atom.size, required_alignment); |
| ... | ... | @@ -1196,7 +1196,7 @@ fn updateLazySymbolAtom( |
| 1196 | 1196 | const gpa = self.base.allocator; |
| 1197 | 1197 | const mod = self.base.options.module.?; |
| 1198 | 1198 | |
| 1199 | var required_alignment: u32 = undefined; | |
| 1199 | var required_alignment: InternPool.Alignment = .none; | |
| 1200 | 1200 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 1201 | 1201 | defer code_buffer.deinit(); |
| 1202 | 1202 | |
| ... | ... | @@ -1240,7 +1240,7 @@ fn updateLazySymbolAtom( |
| 1240 | 1240 | symbol.section_number = @as(coff.SectionNumber, @enumFromInt(section_index + 1)); |
| 1241 | 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 | 1244 | errdefer self.freeAtom(atom_index); |
| 1245 | 1245 | |
| 1246 | 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 | 1322 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| 1323 | 1323 | |
| 1324 | 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 | 1327 | const decl_metadata = self.decls.get(decl_index).?; |
| 1328 | 1328 | const atom_index = decl_metadata.atom; |
src/link/Dwarf.zig+42-28| ... | ... | @@ -341,37 +341,51 @@ pub const DeclState = struct { |
| 341 | 341 | try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); |
| 342 | 342 | } |
| 343 | 343 | }, |
| 344 | .struct_type => |struct_type| s: { | |
| 345 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :s; | |
| 344 | .struct_type => |struct_type| { | |
| 346 | 345 | // DW.AT.name, DW.FORM.string |
| 347 | 346 | try ty.print(dbg_info_buffer.writer(), mod); |
| 348 | 347 | try dbg_info_buffer.append(0); |
| 349 | 348 | |
| 350 | if (struct_obj.layout == .Packed) { | |
| 349 | if (struct_type.layout == .Packed) { | |
| 351 | 350 | log.debug("TODO implement .debug_info for packed structs", .{}); |
| 352 | 351 | break :blk; |
| 353 | 352 | } |
| 354 | 353 | |
| 355 | for ( | |
| 356 | struct_obj.fields.keys(), | |
| 357 | struct_obj.fields.values(), | |
| 358 | 0.., | |
| 359 | ) |field_name_ip, field, field_index| { | |
| 360 | if (!field.ty.hasRuntimeBits(mod)) continue; | |
| 361 | const field_name = ip.stringToSlice(field_name_ip); | |
| 362 | // DW.AT.member | |
| 363 | try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2); | |
| 364 | dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevKind.struct_member)); | |
| 365 | // DW.AT.name, DW.FORM.string | |
| 366 | dbg_info_buffer.appendSliceAssumeCapacity(field_name); | |
| 367 | dbg_info_buffer.appendAssumeCapacity(0); | |
| 368 | // DW.AT.type, DW.FORM.ref4 | |
| 369 | var index = dbg_info_buffer.items.len; | |
| 370 | try dbg_info_buffer.resize(index + 4); | |
| 371 | try self.addTypeRelocGlobal(atom_index, field.ty, @as(u32, @intCast(index))); | |
| 372 | // DW.AT.data_member_location, DW.FORM.udata | |
| 373 | const field_off = ty.structFieldOffset(field_index, mod); | |
| 374 | try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); | |
| 354 | if (struct_type.isTuple(ip)) { | |
| 355 | for (struct_type.field_types.get(ip), struct_type.offsets.get(ip), 0..) |field_ty, field_off, field_index| { | |
| 356 | if (!field_ty.toType().hasRuntimeBits(mod)) continue; | |
| 357 | // DW.AT.member | |
| 358 | try dbg_info_buffer.append(@intFromEnum(AbbrevKind.struct_member)); | |
| 359 | // DW.AT.name, DW.FORM.string | |
| 360 | try dbg_info_buffer.writer().print("{d}\x00", .{field_index}); | |
| 361 | // DW.AT.type, DW.FORM.ref4 | |
| 362 | var index = dbg_info_buffer.items.len; | |
| 363 | try dbg_info_buffer.resize(index + 4); | |
| 364 | try self.addTypeRelocGlobal(atom_index, field_ty.toType(), @as(u32, @intCast(index))); | |
| 365 | // DW.AT.data_member_location, DW.FORM.udata | |
| 366 | try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); | |
| 367 | } | |
| 368 | } else { | |
| 369 | for ( | |
| 370 | struct_type.field_names.get(ip), | |
| 371 | struct_type.field_types.get(ip), | |
| 372 | struct_type.offsets.get(ip), | |
| 373 | ) |field_name_ip, field_ty, field_off| { | |
| 374 | if (!field_ty.toType().hasRuntimeBits(mod)) continue; | |
| 375 | const field_name = ip.stringToSlice(field_name_ip); | |
| 376 | // DW.AT.member | |
| 377 | try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2); | |
| 378 | dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevKind.struct_member)); | |
| 379 | // DW.AT.name, DW.FORM.string | |
| 380 | dbg_info_buffer.appendSliceAssumeCapacity(field_name); | |
| 381 | dbg_info_buffer.appendAssumeCapacity(0); | |
| 382 | // DW.AT.type, DW.FORM.ref4 | |
| 383 | var index = dbg_info_buffer.items.len; | |
| 384 | try dbg_info_buffer.resize(index + 4); | |
| 385 | try self.addTypeRelocGlobal(atom_index, field_ty.toType(), @intCast(index)); | |
| 386 | // DW.AT.data_member_location, DW.FORM.udata | |
| 387 | try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); | |
| 388 | } | |
| 375 | 389 | } |
| 376 | 390 | }, |
| 377 | 391 | else => unreachable, |
| ... | ... | @@ -416,8 +430,8 @@ pub const DeclState = struct { |
| 416 | 430 | .Union => { |
| 417 | 431 | const union_obj = mod.typeToUnion(ty).?; |
| 418 | 432 | const layout = mod.getUnionLayout(union_obj); |
| 419 | const payload_offset = if (layout.tag_align >= layout.payload_align) layout.tag_size else 0; | |
| 420 | const tag_offset = if (layout.tag_align >= layout.payload_align) 0 else layout.payload_size; | |
| 433 | const payload_offset = if (layout.tag_align.compare(.gte, layout.payload_align)) layout.tag_size else 0; | |
| 434 | const tag_offset = if (layout.tag_align.compare(.gte, layout.payload_align)) 0 else layout.payload_size; | |
| 421 | 435 | // TODO this is temporary to match current state of unions in Zig - we don't yet have |
| 422 | 436 | // safety checks implemented meaning the implicit tag is not yet stored and generated |
| 423 | 437 | // for untagged unions. |
| ... | ... | @@ -496,11 +510,11 @@ pub const DeclState = struct { |
| 496 | 510 | .ErrorUnion => { |
| 497 | 511 | const error_ty = ty.errorUnionSet(mod); |
| 498 | 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 | 514 | const error_align = Type.anyerror.abiAlignment(mod); |
| 501 | 515 | const abi_size = ty.abiSize(mod); |
| 502 | const payload_off = if (error_align >= payload_align) Type.anyerror.abiSize(mod) else 0; | |
| 503 | const error_off = if (error_align >= payload_align) 0 else payload_ty.abiSize(mod); | |
| 516 | const payload_off = if (error_align.compare(.gte, payload_align)) Type.anyerror.abiSize(mod) else 0; | |
| 517 | const error_off = if (error_align.compare(.gte, payload_align)) 0 else payload_ty.abiSize(mod); | |
| 504 | 518 | |
| 505 | 519 | // DW.AT.structure_type |
| 506 | 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 | 409 | const image_base = self.calcImageBase(); |
| 410 | 410 | |
| 411 | 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 | 413 | const p_align: u16 = switch (self.ptr_width) { |
| 414 | 414 | .p32 => @alignOf(elf.Elf32_Phdr), |
| 415 | 415 | .p64 => @alignOf(elf.Elf64_Phdr), |
| ... | ... | @@ -428,7 +428,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 428 | 428 | } |
| 429 | 429 | |
| 430 | 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 | 432 | // TODO Same as for GOT |
| 433 | 433 | try self.phdrs.append(gpa, .{ |
| 434 | 434 | .p_type = elf.PT_LOAD, |
| ... | ... | @@ -444,7 +444,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 444 | 444 | } |
| 445 | 445 | |
| 446 | 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 | 448 | const file_size = self.base.options.program_code_size_hint; |
| 449 | 449 | const p_align = self.page_size; |
| 450 | 450 | const off = self.findFreeSpace(file_size, p_align); |
| ... | ... | @@ -465,7 +465,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 465 | 465 | } |
| 466 | 466 | |
| 467 | 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 | 469 | const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint; |
| 470 | 470 | // We really only need ptr alignment but since we are using PROGBITS, linux requires |
| 471 | 471 | // page align. |
| ... | ... | @@ -490,7 +490,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 490 | 490 | } |
| 491 | 491 | |
| 492 | 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 | 494 | // TODO Find a hint about how much data need to be in rodata ? |
| 495 | 495 | const file_size = 1024; |
| 496 | 496 | // Same reason as for GOT |
| ... | ... | @@ -513,7 +513,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 513 | 513 | } |
| 514 | 514 | |
| 515 | 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 | 517 | // TODO Find a hint about how much data need to be in data ? |
| 518 | 518 | const file_size = 1024; |
| 519 | 519 | // Same reason as for GOT |
| ... | ... | @@ -536,7 +536,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 536 | 536 | } |
| 537 | 537 | |
| 538 | 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 | 540 | const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size); |
| 541 | 541 | const off = self.phdrs.items[self.phdr_load_rw_index.?].p_offset; |
| 542 | 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 | 556 | } |
| 557 | 557 | |
| 558 | 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 | 560 | assert(self.shstrtab.buffer.items.len == 0); |
| 561 | 561 | try self.shstrtab.buffer.append(gpa, 0); // need a 0 at position 0 |
| 562 | 562 | const off = self.findFreeSpace(self.shstrtab.buffer.items.len, 1); |
| ... | ... | @@ -578,7 +578,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 578 | 578 | } |
| 579 | 579 | |
| 580 | 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 | 582 | assert(self.strtab.buffer.items.len == 0); |
| 583 | 583 | try self.strtab.buffer.append(gpa, 0); // need a 0 at position 0 |
| 584 | 584 | const off = self.findFreeSpace(self.strtab.buffer.items.len, 1); |
| ... | ... | @@ -600,7 +600,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 600 | 600 | } |
| 601 | 601 | |
| 602 | 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 | 604 | const phdr = &self.phdrs.items[self.phdr_load_re_index.?]; |
| 605 | 605 | try self.shdrs.append(gpa, .{ |
| 606 | 606 | .sh_name = try self.shstrtab.insert(gpa, ".text"), |
| ... | ... | @@ -620,7 +620,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 620 | 620 | } |
| 621 | 621 | |
| 622 | 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 | 624 | const phdr = &self.phdrs.items[self.phdr_got_index.?]; |
| 625 | 625 | try self.shdrs.append(gpa, .{ |
| 626 | 626 | .sh_name = try self.shstrtab.insert(gpa, ".got"), |
| ... | ... | @@ -639,7 +639,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 639 | 639 | } |
| 640 | 640 | |
| 641 | 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 | 643 | const phdr = &self.phdrs.items[self.phdr_load_ro_index.?]; |
| 644 | 644 | try self.shdrs.append(gpa, .{ |
| 645 | 645 | .sh_name = try self.shstrtab.insert(gpa, ".rodata"), |
| ... | ... | @@ -659,7 +659,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 659 | 659 | } |
| 660 | 660 | |
| 661 | 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 | 663 | const phdr = &self.phdrs.items[self.phdr_load_rw_index.?]; |
| 664 | 664 | try self.shdrs.append(gpa, .{ |
| 665 | 665 | .sh_name = try self.shstrtab.insert(gpa, ".data"), |
| ... | ... | @@ -679,7 +679,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 679 | 679 | } |
| 680 | 680 | |
| 681 | 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 | 683 | const phdr = &self.phdrs.items[self.phdr_load_zerofill_index.?]; |
| 684 | 684 | try self.shdrs.append(gpa, .{ |
| 685 | 685 | .sh_name = try self.shstrtab.insert(gpa, ".bss"), |
| ... | ... | @@ -699,7 +699,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 699 | 699 | } |
| 700 | 700 | |
| 701 | 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 | 703 | const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym); |
| 704 | 704 | const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym); |
| 705 | 705 | const file_size = self.base.options.symbol_count_hint * each_size; |
| ... | ... | @@ -714,7 +714,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 714 | 714 | .sh_size = file_size, |
| 715 | 715 | // The section header index of the associated string table. |
| 716 | 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 | 718 | .sh_addralign = min_align, |
| 719 | 719 | .sh_entsize = each_size, |
| 720 | 720 | }); |
| ... | ... | @@ -723,7 +723,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 723 | 723 | |
| 724 | 724 | if (self.dwarf) |*dw| { |
| 725 | 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 | 727 | assert(dw.strtab.buffer.items.len == 0); |
| 728 | 728 | try dw.strtab.buffer.append(gpa, 0); |
| 729 | 729 | try self.shdrs.append(gpa, .{ |
| ... | ... | @@ -743,7 +743,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 743 | 743 | } |
| 744 | 744 | |
| 745 | 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 | 747 | const file_size_hint = 200; |
| 748 | 748 | const p_align = 1; |
| 749 | 749 | const off = self.findFreeSpace(file_size_hint, p_align); |
| ... | ... | @@ -768,7 +768,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 768 | 768 | } |
| 769 | 769 | |
| 770 | 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 | 772 | const file_size_hint = 128; |
| 773 | 773 | const p_align = 1; |
| 774 | 774 | const off = self.findFreeSpace(file_size_hint, p_align); |
| ... | ... | @@ -793,7 +793,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 793 | 793 | } |
| 794 | 794 | |
| 795 | 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 | 797 | const file_size_hint = 160; |
| 798 | 798 | const p_align = 16; |
| 799 | 799 | const off = self.findFreeSpace(file_size_hint, p_align); |
| ... | ... | @@ -818,7 +818,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 818 | 818 | } |
| 819 | 819 | |
| 820 | 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 | 822 | const file_size_hint = 250; |
| 823 | 823 | const p_align = 1; |
| 824 | 824 | const off = self.findFreeSpace(file_size_hint, p_align); |
| ... | ... | @@ -2666,12 +2666,12 @@ fn updateDeclCode( |
| 2666 | 2666 | |
| 2667 | 2667 | const old_size = atom_ptr.size; |
| 2668 | 2668 | const old_vaddr = atom_ptr.value; |
| 2669 | atom_ptr.alignment = math.log2_int(u64, required_alignment); | |
| 2669 | atom_ptr.alignment = required_alignment; | |
| 2670 | 2670 | atom_ptr.size = code.len; |
| 2671 | 2671 | |
| 2672 | 2672 | if (old_size > 0 and self.base.child_pid == null) { |
| 2673 | 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 | 2675 | if (need_realloc) { |
| 2676 | 2676 | try atom_ptr.grow(self); |
| 2677 | 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 | 2869 | const mod = self.base.options.module.?; |
| 2870 | 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 | 2873 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 2874 | 2874 | defer code_buffer.deinit(); |
| 2875 | 2875 | |
| ... | ... | @@ -2918,7 +2918,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. |
| 2918 | 2918 | const atom_ptr = local_sym.atom(self).?; |
| 2919 | 2919 | atom_ptr.alive = true; |
| 2920 | 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 | 2922 | atom_ptr.size = code.len; |
| 2923 | 2923 | |
| 2924 | 2924 | try atom_ptr.allocate(self); |
| ... | ... | @@ -2995,7 +2995,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module |
| 2995 | 2995 | const atom_ptr = local_sym.atom(self).?; |
| 2996 | 2996 | atom_ptr.alive = true; |
| 2997 | 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 | 2999 | atom_ptr.size = code.len; |
| 3000 | 3000 | |
| 3001 | 3001 | try atom_ptr.allocate(self); |
src/link/Elf/Atom.zig+8-9| ... | ... | @@ -11,7 +11,7 @@ file_index: File.Index = 0, |
| 11 | 11 | size: u64 = 0, |
| 12 | 12 | |
| 13 | 13 | /// Alignment of this atom as a power of two. |
| 14 | alignment: u8 = 0, | |
| 14 | alignment: Alignment = .@"1", | |
| 15 | 15 | |
| 16 | 16 | /// Index of the input section. |
| 17 | 17 | input_section_index: Index = 0, |
| ... | ... | @@ -42,6 +42,8 @@ fde_end: u32 = 0, |
| 42 | 42 | prev_index: Index = 0, |
| 43 | 43 | next_index: Index = 0, |
| 44 | 44 | |
| 45 | pub const Alignment = @import("../../InternPool.zig").Alignment; | |
| 46 | ||
| 45 | 47 | pub fn name(self: Atom, elf_file: *Elf) []const u8 { |
| 46 | 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 | 114 | const free_list = &meta.free_list; |
| 113 | 115 | const last_atom_index = &meta.last_atom_index; |
| 114 | 116 | const new_atom_ideal_capacity = Elf.padToIdeal(self.size); |
| 115 | const alignment = try std.math.powi(u64, 2, self.alignment); | |
| 116 | 117 | |
| 117 | 118 | // We use these to indicate our intention to update metadata, placing the new atom, |
| 118 | 119 | // and possibly removing a free list node. |
| ... | ... | @@ -136,7 +137,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { |
| 136 | 137 | const ideal_capacity_end_vaddr = std.math.add(u64, big_atom.value, ideal_capacity) catch ideal_capacity; |
| 137 | 138 | const capacity_end_vaddr = big_atom.value + cap; |
| 138 | 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 | 141 | if (new_start_vaddr < ideal_capacity_end_vaddr) { |
| 141 | 142 | // Additional bookkeeping here to notice if this free list node |
| 142 | 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 | 164 | } else if (elf_file.atom(last_atom_index.*)) |last| { |
| 164 | 165 | const ideal_capacity = Elf.padToIdeal(last.size); |
| 165 | 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 | 168 | // Set up the metadata to be updated, after errors are no longer possible. |
| 168 | 169 | atom_placement = last.atom_index; |
| 169 | 170 | break :blk new_start_vaddr; |
| ... | ... | @@ -192,7 +193,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void { |
| 192 | 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 | 198 | // This function can also reallocate an atom. |
| 198 | 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 | 225 | } |
| 225 | 226 | |
| 226 | 227 | pub fn grow(self: *Atom, elf_file: *Elf) !void { |
| 227 | const alignment = try std.math.powi(u64, 2, self.alignment); | |
| 228 | const align_ok = std.mem.alignBackward(u64, self.value, alignment) == self.value; | |
| 229 | const need_realloc = !align_ok or self.size > self.capacity(elf_file); | |
| 230 | if (need_realloc) try self.allocate(elf_file); | |
| 228 | if (!self.alignment.check(self.value) or self.size > self.capacity(elf_file)) | |
| 229 | try self.allocate(elf_file); | |
| 231 | 230 | } |
| 232 | 231 | |
| 233 | 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 | 181 | const data = try self.shdrContents(shndx); |
| 182 | 182 | const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*; |
| 183 | 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 | 185 | } else { |
| 186 | 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 | 571 | atom.file = self.index; |
| 572 | 572 | atom.size = this_sym.st_size; |
| 573 | 573 | const alignment = this_sym.st_value; |
| 574 | atom.alignment = math.log2_int(u64, alignment); | |
| 574 | atom.alignment = Alignment.fromNonzeroByteUnits(alignment); | |
| 575 | 575 | |
| 576 | 576 | var sh_flags: u32 = elf.SHF_ALLOC | elf.SHF_WRITE; |
| 577 | 577 | if (is_tls) sh_flags |= elf.SHF_TLS; |
| ... | ... | @@ -870,3 +870,4 @@ const Fde = eh_frame.Fde; |
| 870 | 870 | const File = @import("file.zig").File; |
| 871 | 871 | const StringTable = @import("../strtab.zig").StringTable; |
| 872 | 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 | 1425 | |
| 1426 | 1426 | const CreateAtomOpts = struct { |
| 1427 | 1427 | size: u64 = 0, |
| 1428 | alignment: u32 = 0, | |
| 1428 | alignment: Alignment = .@"1", | |
| 1429 | 1429 | }; |
| 1430 | 1430 | |
| 1431 | 1431 | pub fn createAtom(self: *MachO, sym_index: u32, opts: CreateAtomOpts) !Atom.Index { |
| ... | ... | @@ -1473,7 +1473,7 @@ pub fn createTentativeDefAtoms(self: *MachO) !void { |
| 1473 | 1473 | |
| 1474 | 1474 | const atom_index = try self.createAtom(global.sym_index, .{ |
| 1475 | 1475 | .size = size, |
| 1476 | .alignment = alignment, | |
| 1476 | .alignment = @enumFromInt(alignment), | |
| 1477 | 1477 | }); |
| 1478 | 1478 | const atom = self.getAtomPtr(atom_index); |
| 1479 | 1479 | atom.file = global.file; |
| ... | ... | @@ -1493,7 +1493,7 @@ pub fn createDyldPrivateAtom(self: *MachO) !void { |
| 1493 | 1493 | const sym_index = try self.allocateSymbol(); |
| 1494 | 1494 | const atom_index = try self.createAtom(sym_index, .{ |
| 1495 | 1495 | .size = @sizeOf(u64), |
| 1496 | .alignment = 3, | |
| 1496 | .alignment = .@"8", | |
| 1497 | 1497 | }); |
| 1498 | 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 | 1510 | switch (self.mode) { |
| 1511 | 1511 | .zld => self.addAtomToSection(atom_index), |
| 1512 | 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 | 1514 | log.debug("allocated dyld_private atom at 0x{x}", .{sym.n_value}); |
| 1515 | 1515 | var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64); |
| 1516 | 1516 | try self.writeAtom(atom_index, &buffer); |
| ... | ... | @@ -1521,7 +1521,7 @@ pub fn createDyldPrivateAtom(self: *MachO) !void { |
| 1521 | 1521 | fn createThreadLocalDescriptorAtom(self: *MachO, sym_name: []const u8, target: SymbolWithLoc) !Atom.Index { |
| 1522 | 1522 | const gpa = self.base.allocator; |
| 1523 | 1523 | const size = 3 * @sizeOf(u64); |
| 1524 | const required_alignment: u32 = 1; | |
| 1524 | const required_alignment: Alignment = .@"1"; | |
| 1525 | 1525 | const sym_index = try self.allocateSymbol(); |
| 1526 | 1526 | const atom_index = try self.createAtom(sym_index, .{}); |
| 1527 | 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 | 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 | 2034 | const atom = self.getAtom(atom_index); |
| 2035 | 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 | 2037 | const need_realloc = !align_ok or new_atom_size > atom.capacity(self); |
| 2038 | 2038 | if (!need_realloc) return sym.n_value; |
| 2039 | 2039 | return self.allocateAtom(atom_index, new_atom_size, alignment); |
| ... | ... | @@ -2350,7 +2350,7 @@ fn updateLazySymbolAtom( |
| 2350 | 2350 | const gpa = self.base.allocator; |
| 2351 | 2351 | const mod = self.base.options.module.?; |
| 2352 | 2352 | |
| 2353 | var required_alignment: u32 = undefined; | |
| 2353 | var required_alignment: Alignment = .none; | |
| 2354 | 2354 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 2355 | 2355 | defer code_buffer.deinit(); |
| 2356 | 2356 | |
| ... | ... | @@ -2617,7 +2617,7 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64 |
| 2617 | 2617 | sym.n_desc = 0; |
| 2618 | 2618 | |
| 2619 | 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 | 2622 | if (need_realloc) { |
| 2623 | 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 | 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 | 3208 | const tracy = trace(@src()); |
| 3209 | 3209 | defer tracy.end(); |
| 3210 | 3210 | |
| ... | ... | @@ -3247,7 +3247,7 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm |
| 3247 | 3247 | const ideal_capacity_end_vaddr = math.add(u64, sym.n_value, ideal_capacity) catch ideal_capacity; |
| 3248 | 3248 | const capacity_end_vaddr = sym.n_value + capacity; |
| 3249 | 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 | 3251 | if (new_start_vaddr < ideal_capacity_end_vaddr) { |
| 3252 | 3252 | // Additional bookkeeping here to notice if this free list node |
| 3253 | 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 | 3276 | const last_symbol = last.getSymbol(self); |
| 3277 | 3277 | const ideal_capacity = if (requires_padding) padToIdeal(last.size) else last.size; |
| 3278 | 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 | 3280 | atom_placement = last_index; |
| 3281 | 3281 | break :blk new_start_vaddr; |
| 3282 | 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 | 3295 | self.segment_table_dirty = true; |
| 3296 | 3296 | } |
| 3297 | 3297 | |
| 3298 | const align_pow = @as(u32, @intCast(math.log2(alignment))); | |
| 3299 | if (header.@"align" < align_pow) { | |
| 3300 | header.@"align" = align_pow; | |
| 3301 | } | |
| 3298 | assert(alignment != .none); | |
| 3299 | header.@"align" = @min(header.@"align", @intFromEnum(alignment)); | |
| 3302 | 3300 | self.getAtomPtr(atom_index).size = new_atom_size; |
| 3303 | 3301 | |
| 3304 | 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 | 3336 | |
| 3339 | 3337 | pub fn writeSegmentHeaders(self: *MachO, writer: anytype) !void { |
| 3340 | 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 | 3340 | var out_seg = seg; |
| 3343 | 3341 | out_seg.cmdsize = @sizeOf(macho.segment_command_64); |
| 3344 | 3342 | out_seg.nsects = 0; |
| ... | ... | @@ -5526,6 +5524,7 @@ const Trie = @import("MachO/Trie.zig"); |
| 5526 | 5524 | const Type = @import("../type.zig").Type; |
| 5527 | 5525 | const TypedValue = @import("../TypedValue.zig"); |
| 5528 | 5526 | const Value = @import("../value.zig").Value; |
| 5527 | const Alignment = Atom.Alignment; | |
| 5529 | 5528 | |
| 5530 | 5529 | pub const DebugSymbols = @import("MachO/DebugSymbols.zig"); |
| 5531 | 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 | 28 | |
| 29 | 29 | /// Alignment of this atom as a power of 2. |
| 30 | 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 | 33 | /// Points to the previous and next neighbours |
| 34 | 34 | /// TODO use the same trick as with symbols: reserve index 0 as null atom |
| 35 | 35 | next_index: ?Index = null, |
| 36 | 36 | prev_index: ?Index = null, |
| 37 | 37 | |
| 38 | pub const Alignment = @import("../../InternPool.zig").Alignment; | |
| 39 | ||
| 38 | 40 | pub const Index = u32; |
| 39 | 41 | |
| 40 | 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 | 382 | const out_sect_id = (try Atom.getOutputSection(macho_file, sect)) orelse continue; |
| 383 | 383 | if (sect.size == 0) continue; |
| 384 | 384 | |
| 385 | const sect_id = @as(u8, @intCast(id)); | |
| 385 | const sect_id: u8 = @intCast(id); | |
| 386 | 386 | const sym_index = self.getSectionAliasSymbolIndex(sect_id); |
| 387 | 387 | const atom_index = try self.createAtomFromSubsection( |
| 388 | 388 | macho_file, |
| ... | ... | @@ -391,7 +391,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) ! |
| 391 | 391 | sym_index, |
| 392 | 392 | 1, |
| 393 | 393 | sect.size, |
| 394 | sect.@"align", | |
| 394 | Alignment.fromLog2Units(sect.@"align"), | |
| 395 | 395 | out_sect_id, |
| 396 | 396 | ); |
| 397 | 397 | macho_file.addAtomToSection(atom_index); |
| ... | ... | @@ -470,7 +470,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) ! |
| 470 | 470 | sym_index, |
| 471 | 471 | 1, |
| 472 | 472 | atom_size, |
| 473 | sect.@"align", | |
| 473 | Alignment.fromLog2Units(sect.@"align"), | |
| 474 | 474 | out_sect_id, |
| 475 | 475 | ); |
| 476 | 476 | if (!sect.isZerofill()) { |
| ... | ... | @@ -494,10 +494,10 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) ! |
| 494 | 494 | else |
| 495 | 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 | 498 | @min(@ctz(addr), sect.@"align") |
| 499 | 499 | else |
| 500 | sect.@"align"; | |
| 500 | sect.@"align"); | |
| 501 | 501 | |
| 502 | 502 | const atom_index = try self.createAtomFromSubsection( |
| 503 | 503 | macho_file, |
| ... | ... | @@ -532,7 +532,7 @@ pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) ! |
| 532 | 532 | sect_start_index, |
| 533 | 533 | sect_loc.len, |
| 534 | 534 | sect.size, |
| 535 | sect.@"align", | |
| 535 | Alignment.fromLog2Units(sect.@"align"), | |
| 536 | 536 | out_sect_id, |
| 537 | 537 | ); |
| 538 | 538 | if (!sect.isZerofill()) { |
| ... | ... | @@ -551,11 +551,14 @@ fn createAtomFromSubsection( |
| 551 | 551 | inner_sym_index: u32, |
| 552 | 552 | inner_nsyms_trailing: u32, |
| 553 | 553 | size: u64, |
| 554 | alignment: u32, | |
| 554 | alignment: Alignment, | |
| 555 | 555 | out_sect_id: u8, |
| 556 | 556 | ) !Atom.Index { |
| 557 | 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 | 562 | const atom = macho_file.getAtomPtr(atom_index); |
| 560 | 563 | atom.inner_sym_index = inner_sym_index; |
| 561 | 564 | atom.inner_nsyms_trailing = inner_nsyms_trailing; |
| ... | ... | @@ -1115,3 +1118,4 @@ const MachO = @import("../MachO.zig"); |
| 1115 | 1118 | const Platform = @import("load_commands.zig").Platform; |
| 1116 | 1119 | const SymbolWithLoc = MachO.SymbolWithLoc; |
| 1117 | 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 | 104 | |
| 105 | 105 | while (true) { |
| 106 | 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 | 109 | const sym = macho_file.getSymbolPtr(atom.getSymbolWithLoc()); |
| 110 | 110 | sym.n_value = offset; |
| ... | ... | @@ -112,7 +112,7 @@ pub fn createThunks(macho_file: *MachO, sect_id: u8) !void { |
| 112 | 112 | |
| 113 | 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 | 117 | allocated.putAssumeCapacityNoClobber(group_end, {}); |
| 118 | 118 | |
| ... | ... | @@ -196,7 +196,7 @@ fn allocateThunk( |
| 196 | 196 | |
| 197 | 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 | 201 | if (end_atom_index == atom_index) break; |
| 202 | 202 | |
| ... | ... | @@ -326,7 +326,10 @@ fn isReachable( |
| 326 | 326 | |
| 327 | 327 | fn createThunkAtom(macho_file: *MachO) !Atom.Index { |
| 328 | 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 | 333 | const sym = macho_file.getSymbolPtr(.{ .sym_index = sym_index }); |
| 331 | 334 | sym.n_type = macho.N_SECT; |
| 332 | 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 | 985 | |
| 986 | 986 | while (true) { |
| 987 | 987 | const atom = macho_file.getAtom(atom_index); |
| 988 | const atom_alignment = try math.powi(u32, 2, atom.alignment); | |
| 989 | const atom_offset = mem.alignForward(u64, header.size, atom_alignment); | |
| 988 | const atom_offset = atom.alignment.forward(header.size); | |
| 990 | 989 | const padding = atom_offset - header.size; |
| 991 | 990 | |
| 992 | 991 | const sym = macho_file.getSymbolPtr(atom.getSymbolWithLoc()); |
| 993 | 992 | sym.n_value = atom_offset; |
| 994 | 993 | |
| 995 | 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| { | |
| 999 | atom_index = next_index; | |
| 1000 | } else break; | |
| 997 | atom_index = atom.next_index orelse 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 | 1106 | const gpa = self.base.allocator; |
| 1107 | 1107 | const mod = self.base.options.module.?; |
| 1108 | 1108 | |
| 1109 | var required_alignment: u32 = undefined; | |
| 1109 | var required_alignment: InternPool.Alignment = .none; | |
| 1110 | 1110 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 1111 | 1111 | defer code_buffer.deinit(); |
| 1112 | 1112 |
src/link/Wasm.zig+23-21| ... | ... | @@ -187,8 +187,10 @@ debug_pubtypes_atom: ?Atom.Index = null, |
| 187 | 187 | /// rather than by the linker. |
| 188 | 188 | synthetic_functions: std.ArrayListUnmanaged(Atom.Index) = .{}, |
| 189 | 189 | |
| 190 | pub const Alignment = types.Alignment; | |
| 191 | ||
| 190 | 192 | pub const Segment = struct { |
| 191 | alignment: u32, | |
| 193 | alignment: Alignment, | |
| 192 | 194 | size: u32, |
| 193 | 195 | offset: u32, |
| 194 | 196 | flags: u32, |
| ... | ... | @@ -1490,7 +1492,7 @@ fn finishUpdateDecl(wasm: *Wasm, decl_index: Module.Decl.Index, code: []const u8 |
| 1490 | 1492 | try atom.code.appendSlice(wasm.base.allocator, code); |
| 1491 | 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 | 1496 | if (code.len == 0) return; |
| 1495 | 1497 | atom.alignment = decl.getAlignment(mod); |
| 1496 | 1498 | } |
| ... | ... | @@ -2050,7 +2052,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { |
| 2050 | 2052 | }; |
| 2051 | 2053 | |
| 2052 | 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 | 2057 | try wasm.appendAtomAtIndex(final_index, atom_index); |
| 2056 | 2058 | } |
| ... | ... | @@ -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 | 2127 | atom.offset = offset; |
| 2126 | 2128 | log.debug("Atom '{s}' allocated from 0x{x:0>8} to 0x{x:0>8} size={d}", .{ |
| 2127 | 2129 | symbol_loc.getName(wasm), |
| ... | ... | @@ -2132,7 +2134,7 @@ fn allocateAtoms(wasm: *Wasm) !void { |
| 2132 | 2134 | offset += atom.size; |
| 2133 | 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 | 2353 | .offset = 0, |
| 2352 | 2354 | .sym_index = loc.index, |
| 2353 | 2355 | .file = null, |
| 2354 | .alignment = 1, | |
| 2356 | .alignment = .@"1", | |
| 2355 | 2357 | .next = null, |
| 2356 | 2358 | .prev = null, |
| 2357 | 2359 | .code = function_body.moveToUnmanaged(), |
| ... | ... | @@ -2382,11 +2384,11 @@ pub fn createFunction( |
| 2382 | 2384 | const atom_index = @as(Atom.Index, @intCast(wasm.managed_atoms.items.len)); |
| 2383 | 2385 | const atom = try wasm.managed_atoms.addOne(wasm.base.allocator); |
| 2384 | 2386 | atom.* = .{ |
| 2385 | .size = @as(u32, @intCast(function_body.items.len)), | |
| 2387 | .size = @intCast(function_body.items.len), | |
| 2386 | 2388 | .offset = 0, |
| 2387 | 2389 | .sym_index = loc.index, |
| 2388 | 2390 | .file = null, |
| 2389 | .alignment = 1, | |
| 2391 | .alignment = .@"1", | |
| 2390 | 2392 | .next = null, |
| 2391 | 2393 | .prev = null, |
| 2392 | 2394 | .code = function_body.moveToUnmanaged(), |
| ... | ... | @@ -2734,8 +2736,8 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2734 | 2736 | const page_size = std.wasm.page_size; // 64kb |
| 2735 | 2737 | // Use the user-provided stack size or else we use 1MB by default |
| 2736 | 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 | |
| 2738 | const heap_alignment = 16; // wasm's heap alignment as specified by tool-convention | |
| 2739 | const stack_alignment: Alignment = .@"16"; // wasm's stack alignment as specified by tool-convention | |
| 2740 | const heap_alignment: Alignment = .@"16"; // wasm's heap alignment as specified by tool-convention | |
| 2739 | 2741 | |
| 2740 | 2742 | // Always place the stack at the start by default |
| 2741 | 2743 | // unless the user specified the global-base flag |
| ... | ... | @@ -2748,7 +2750,7 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2748 | 2750 | const is_obj = wasm.base.options.output_mode == .Obj; |
| 2749 | 2751 | |
| 2750 | 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 | 2754 | memory_ptr += stack_size; |
| 2753 | 2755 | // We always put the stack pointer global at index 0 |
| 2754 | 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 | 2760 | var data_seg_it = wasm.data_segments.iterator(); |
| 2759 | 2761 | while (data_seg_it.next()) |entry| { |
| 2760 | 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 | 2765 | // set TLS-related symbols |
| 2764 | 2766 | if (mem.eql(u8, entry.key_ptr.*, ".tdata")) { |
| ... | ... | @@ -2768,7 +2770,7 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2768 | 2770 | } |
| 2769 | 2771 | if (wasm.findGlobalSymbol("__tls_align")) |loc| { |
| 2770 | 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 | 2775 | if (wasm.findGlobalSymbol("__tls_base")) |loc| { |
| 2774 | 2776 | const sym = loc.getSymbol(wasm); |
| ... | ... | @@ -2795,7 +2797,7 @@ fn setupMemory(wasm: *Wasm) !void { |
| 2795 | 2797 | } |
| 2796 | 2798 | |
| 2797 | 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 | 2801 | memory_ptr += stack_size; |
| 2800 | 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 | 2806 | // We must set its virtual address so it can be used in relocations. |
| 2805 | 2807 | if (wasm.findGlobalSymbol("__heap_base")) |loc| { |
| 2806 | 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 | 2812 | // Setup the max amount of pages |
| ... | ... | @@ -2879,7 +2881,7 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32 |
| 2879 | 2881 | flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE); |
| 2880 | 2882 | } |
| 2881 | 2883 | try wasm.segments.append(wasm.base.allocator, .{ |
| 2882 | .alignment = 1, | |
| 2884 | .alignment = .@"1", | |
| 2883 | 2885 | .size = 0, |
| 2884 | 2886 | .offset = 0, |
| 2885 | 2887 | .flags = flags, |
| ... | ... | @@ -2954,7 +2956,7 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32 |
| 2954 | 2956 | /// Appends a new segment with default field values |
| 2955 | 2957 | fn appendDummySegment(wasm: *Wasm) !void { |
| 2956 | 2958 | try wasm.segments.append(wasm.base.allocator, .{ |
| 2957 | .alignment = 1, | |
| 2959 | .alignment = .@"1", | |
| 2958 | 2960 | .size = 0, |
| 2959 | 2961 | .offset = 0, |
| 2960 | 2962 | .flags = 0, |
| ... | ... | @@ -3011,7 +3013,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void { |
| 3011 | 3013 | // the pointers into the list using addends which are appended to the relocation. |
| 3012 | 3014 | const names_atom_index = try wasm.createAtom(); |
| 3013 | 3015 | const names_atom = wasm.getAtomPtr(names_atom_index); |
| 3014 | names_atom.alignment = 1; | |
| 3016 | names_atom.alignment = .@"1"; | |
| 3015 | 3017 | const sym_name = try wasm.string_table.put(wasm.base.allocator, "__zig_err_names"); |
| 3016 | 3018 | const names_symbol = &wasm.symbols.items[names_atom.sym_index]; |
| 3017 | 3019 | names_symbol.* = .{ |
| ... | ... | @@ -3085,7 +3087,7 @@ pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) ! |
| 3085 | 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 | 3091 | return atom_index; |
| 3090 | 3092 | } |
| 3091 | 3093 | |
| ... | ... | @@ -4724,12 +4726,12 @@ fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.ArrayList(u8)) !void { |
| 4724 | 4726 | for (wasm.segment_info.values()) |segment_info| { |
| 4725 | 4727 | log.debug("Emit segment: {s} align({d}) flags({b})", .{ |
| 4726 | 4728 | segment_info.name, |
| 4727 | @ctz(segment_info.alignment), | |
| 4729 | segment_info.alignment, | |
| 4728 | 4730 | segment_info.flags, |
| 4729 | 4731 | }); |
| 4730 | 4732 | try leb.writeULEB128(writer, @as(u32, @intCast(segment_info.name.len))); |
| 4731 | 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 | 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 | 19 | /// Contains the binary data of an atom, which can be non-relocated |
| 20 | 20 | code: std.ArrayListUnmanaged(u8) = .{}, |
| 21 | 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 | 23 | /// Offset into the section where the atom lives, this already accounts |
| 24 | 24 | /// for alignment. |
| 25 | 25 | offset: u32, |
| ... | ... | @@ -43,7 +43,7 @@ pub const Index = u32; |
| 43 | 43 | |
| 44 | 44 | /// Represents a default empty wasm `Atom` |
| 45 | 45 | pub const empty: Atom = .{ |
| 46 | .alignment = 1, | |
| 46 | .alignment = .@"1", | |
| 47 | 47 | .file = null, |
| 48 | 48 | .next = null, |
| 49 | 49 | .offset = 0, |
src/link/Wasm/Object.zig+7-9| ... | ... | @@ -8,6 +8,7 @@ const types = @import("types.zig"); |
| 8 | 8 | const std = @import("std"); |
| 9 | 9 | const Wasm = @import("../Wasm.zig"); |
| 10 | 10 | const Symbol = @import("Symbol.zig"); |
| 11 | const Alignment = types.Alignment; | |
| 11 | 12 | |
| 12 | 13 | const Allocator = std.mem.Allocator; |
| 13 | 14 | const leb = std.leb; |
| ... | ... | @@ -88,12 +89,9 @@ const RelocatableData = struct { |
| 88 | 89 | /// meta data of the given object file. |
| 89 | 90 | /// NOTE: Alignment is encoded as a power of 2, so we shift the symbol's |
| 90 | 91 | /// alignment to retrieve the natural alignment. |
| 91 | pub fn getAlignment(relocatable_data: RelocatableData, object: *const Object) u32 { | |
| 92 | if (relocatable_data.type != .data) return 1; | |
| 93 | const data_alignment = object.segment_info[relocatable_data.index].alignment; | |
| 94 | if (data_alignment == 0) return 1; | |
| 95 | // Decode from power of 2 to natural alignment | |
| 96 | return @as(u32, 1) << @as(u5, @intCast(data_alignment)); | |
| 92 | pub fn getAlignment(relocatable_data: RelocatableData, object: *const Object) Alignment { | |
| 93 | if (relocatable_data.type != .data) return .@"1"; | |
| 94 | return object.segment_info[relocatable_data.index].alignment; | |
| 97 | 95 | } |
| 98 | 96 | |
| 99 | 97 | /// Returns the symbol kind that corresponds to the relocatable section |
| ... | ... | @@ -671,7 +669,7 @@ fn Parser(comptime ReaderType: type) type { |
| 671 | 669 | try reader.readNoEof(name); |
| 672 | 670 | segment.* = .{ |
| 673 | 671 | .name = name, |
| 674 | .alignment = try leb.readULEB128(u32, reader), | |
| 672 | .alignment = @enumFromInt(try leb.readULEB128(u32, reader)), | |
| 675 | 673 | .flags = try leb.readULEB128(u32, reader), |
| 676 | 674 | }; |
| 677 | 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 | 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 | 921 | const atom = try wasm_bin.managed_atoms.addOne(gpa); |
| 924 | 922 | atom.* = Atom.empty; |
| 925 | 923 | atom.file = object_index; |
| ... | ... | @@ -984,7 +982,7 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b |
| 984 | 982 | |
| 985 | 983 | const segment: *Wasm.Segment = &wasm_bin.segments.items[final_index]; |
| 986 | 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 | 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 | 109 | WASM_SYMBOL_TABLE = 8, |
| 110 | 110 | }; |
| 111 | 111 | |
| 112 | pub const Alignment = @import("../../InternPool.zig").Alignment; | |
| 113 | ||
| 112 | 114 | pub const Segment = struct { |
| 113 | 115 | /// Segment's name, encoded as UTF-8 bytes. |
| 114 | 116 | name: []const u8, |
| 115 | 117 | /// The required alignment of the segment, encoded as a power of 2 |
| 116 | alignment: u32, | |
| 118 | alignment: Alignment, | |
| 117 | 119 | /// Bitfield containing flags for a segment |
| 118 | 120 | flags: u32, |
| 119 | 121 |
src/target.zig+7-6| ... | ... | @@ -1,6 +1,7 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const Type = @import("type.zig").Type; |
| 3 | 3 | const AddressSpace = std.builtin.AddressSpace; |
| 4 | const Alignment = @import("InternPool.zig").Alignment; | |
| 4 | 5 | |
| 5 | 6 | pub const ArchOsAbi = struct { |
| 6 | 7 | arch: std.Target.Cpu.Arch, |
| ... | ... | @@ -595,13 +596,13 @@ pub fn llvmMachineAbi(target: std.Target) ?[:0]const u8 { |
| 595 | 596 | } |
| 596 | 597 | |
| 597 | 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 | 600 | return switch (target.cpu.arch) { |
| 600 | .arm, .armeb => 4, | |
| 601 | .aarch64, .aarch64_32, .aarch64_be => 4, | |
| 602 | .sparc, .sparcel, .sparc64 => 4, | |
| 603 | .riscv64 => 2, | |
| 604 | else => 1, | |
| 601 | .arm, .armeb => .@"4", | |
| 602 | .aarch64, .aarch64_32, .aarch64_be => .@"4", | |
| 603 | .sparc, .sparcel, .sparc64 => .@"4", | |
| 604 | .riscv64 => .@"2", | |
| 605 | else => .@"1", | |
| 605 | 606 | }; |
| 606 | 607 | } |
| 607 | 608 |
src/type.zig+265-402| ... | ... | @@ -9,6 +9,7 @@ const target_util = @import("target.zig"); |
| 9 | 9 | const TypedValue = @import("TypedValue.zig"); |
| 10 | 10 | const Sema = @import("Sema.zig"); |
| 11 | 11 | const InternPool = @import("InternPool.zig"); |
| 12 | const Alignment = InternPool.Alignment; | |
| 12 | 13 | |
| 13 | 14 | /// Both types and values are canonically represented by a single 32-bit integer |
| 14 | 15 | /// which is an index into an `InternPool` data structure. |
| ... | ... | @@ -196,9 +197,11 @@ pub const Type = struct { |
| 196 | 197 | info.packed_offset.host_size != 0 or |
| 197 | 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 | 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 | 206 | if (info.packed_offset.bit_offset != 0 or info.packed_offset.host_size != 0) { |
| 204 | 207 | try writer.print(":{d}:{d}", .{ |
| ... | ... | @@ -315,8 +318,8 @@ pub const Type = struct { |
| 315 | 318 | .generic_poison => unreachable, |
| 316 | 319 | }, |
| 317 | 320 | .struct_type => |struct_type| { |
| 318 | if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| { | |
| 319 | const decl = mod.declPtr(struct_obj.owner_decl); | |
| 321 | if (struct_type.decl.unwrap()) |decl_index| { | |
| 322 | const decl = mod.declPtr(decl_index); | |
| 320 | 323 | try decl.renderFullyQualifiedName(mod, writer); |
| 321 | 324 | } else if (struct_type.namespace.unwrap()) |namespace_index| { |
| 322 | 325 | const namespace = mod.namespacePtr(namespace_index); |
| ... | ... | @@ -561,24 +564,20 @@ pub const Type = struct { |
| 561 | 564 | .generic_poison => unreachable, |
| 562 | 565 | }, |
| 563 | 566 | .struct_type => |struct_type| { |
| 564 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse { | |
| 565 | // This struct has no fields. | |
| 566 | return false; | |
| 567 | }; | |
| 568 | if (struct_obj.status == .field_types_wip) { | |
| 567 | if (struct_type.assumeRuntimeBitsIfFieldTypesWip(ip)) { | |
| 569 | 568 | // In this case, we guess that hasRuntimeBits() for this type is true, |
| 570 | 569 | // and then later if our guess was incorrect, we emit a compile error. |
| 571 | struct_obj.assumed_runtime_bits = true; | |
| 572 | 570 | return true; |
| 573 | 571 | } |
| 574 | 572 | switch (strat) { |
| 575 | 573 | .sema => |sema| _ = try sema.resolveTypeFields(ty), |
| 576 | .eager => assert(struct_obj.haveFieldTypes()), | |
| 577 | .lazy => if (!struct_obj.haveFieldTypes()) return error.NeedLazy, | |
| 574 | .eager => assert(struct_type.haveFieldTypes(ip)), | |
| 575 | .lazy => if (!struct_type.haveFieldTypes(ip)) return error.NeedLazy, | |
| 578 | 576 | } |
| 579 | for (struct_obj.fields.values()) |field| { | |
| 580 | if (field.is_comptime) continue; | |
| 581 | if (try field.ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) | |
| 577 | for (0..struct_type.field_types.len) |i| { | |
| 578 | if (struct_type.comptime_bits.getBit(ip, i)) continue; | |
| 579 | const field_ty = struct_type.field_types.get(ip)[i].toType(); | |
| 580 | if (try field_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) | |
| 582 | 581 | return true; |
| 583 | 582 | } else { |
| 584 | 583 | return false; |
| ... | ... | @@ -728,11 +727,8 @@ pub const Type = struct { |
| 728 | 727 | => false, |
| 729 | 728 | }, |
| 730 | 729 | .struct_type => |struct_type| { |
| 731 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse { | |
| 732 | // Struct with no fields has a well-defined layout of no bits. | |
| 733 | return true; | |
| 734 | }; | |
| 735 | return struct_obj.layout != .Auto; | |
| 730 | // Struct with no fields have a well-defined layout of no bits. | |
| 731 | return struct_type.layout != .Auto or struct_type.field_types.len == 0; | |
| 736 | 732 | }, |
| 737 | 733 | .union_type => |union_type| switch (union_type.flagsPtr(ip).runtime_tag) { |
| 738 | 734 | .none, .safety => union_type.flagsPtr(ip).layout != .Auto, |
| ... | ... | @@ -806,22 +802,23 @@ pub const Type = struct { |
| 806 | 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. | |
| 810 | pub fn ptrAlignment(ty: Type, mod: *Module) u32 { | |
| 805 | /// Returns `none` if the pointer is naturally aligned and the element type is 0-bit. | |
| 806 | pub fn ptrAlignment(ty: Type, mod: *Module) Alignment { | |
| 811 | 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 | 811 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 816 | 812 | .ptr_type => |ptr_type| { |
| 817 | if (ptr_type.flags.alignment.toByteUnitsOptional()) |a| { | |
| 818 | return @as(u32, @intCast(a)); | |
| 819 | } else if (opt_sema) |sema| { | |
| 813 | if (ptr_type.flags.alignment != .none) | |
| 814 | return ptr_type.flags.alignment; | |
| 815 | ||
| 816 | if (opt_sema) |sema| { | |
| 820 | 817 | const res = try ptr_type.child.toType().abiAlignmentAdvanced(mod, .{ .sema = sema }); |
| 821 | 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 | 823 | .opt_type => |child| child.toType().ptrAlignmentAdvanced(mod, opt_sema), |
| 827 | 824 | else => unreachable, |
| ... | ... | @@ -836,8 +833,8 @@ pub const Type = struct { |
| 836 | 833 | }; |
| 837 | 834 | } |
| 838 | 835 | |
| 839 | /// Returns 0 for 0-bit types. | |
| 840 | pub fn abiAlignment(ty: Type, mod: *Module) u32 { | |
| 836 | /// Never returns `none`. Asserts that all necessary type resolution is already done. | |
| 837 | pub fn abiAlignment(ty: Type, mod: *Module) Alignment { | |
| 841 | 838 | return (ty.abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar; |
| 842 | 839 | } |
| 843 | 840 | |
| ... | ... | @@ -846,12 +843,12 @@ pub const Type = struct { |
| 846 | 843 | pub fn lazyAbiAlignment(ty: Type, mod: *Module) !Value { |
| 847 | 844 | switch (try ty.abiAlignmentAdvanced(mod, .lazy)) { |
| 848 | 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 | 850 | pub const AbiAlignmentAdvanced = union(enum) { |
| 854 | scalar: u32, | |
| 851 | scalar: Alignment, | |
| 855 | 852 | val: Value, |
| 856 | 853 | }; |
| 857 | 854 | |
| ... | ... | @@ -881,36 +878,36 @@ pub const Type = struct { |
| 881 | 878 | }; |
| 882 | 879 | |
| 883 | 880 | switch (ty.toIntern()) { |
| 884 | .empty_struct_type => return AbiAlignmentAdvanced{ .scalar = 0 }, | |
| 881 | .empty_struct_type => return AbiAlignmentAdvanced{ .scalar = .@"1" }, | |
| 885 | 882 | else => switch (ip.indexToKey(ty.toIntern())) { |
| 886 | 883 | .int_type => |int_type| { |
| 887 | if (int_type.bits == 0) return AbiAlignmentAdvanced{ .scalar = 0 }; | |
| 888 | return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(int_type.bits, target) }; | |
| 884 | if (int_type.bits == 0) return AbiAlignmentAdvanced{ .scalar = .@"1" }; | |
| 885 | return .{ .scalar = intAbiAlignment(int_type.bits, target) }; | |
| 889 | 886 | }, |
| 890 | 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 | 890 | .array_type => |array_type| { |
| 894 | 891 | return array_type.child.toType().abiAlignmentAdvanced(mod, strat); |
| 895 | 892 | }, |
| 896 | 893 | .vector_type => |vector_type| { |
| 897 | 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 | 896 | const bytes = ((bits * vector_type.len) + 7) / 8; |
| 900 | 897 | const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes); |
| 901 | return AbiAlignmentAdvanced{ .scalar = alignment }; | |
| 898 | return .{ .scalar = Alignment.fromByteUnits(alignment) }; | |
| 902 | 899 | }, |
| 903 | 900 | |
| 904 | 901 | .opt_type => return abiAlignmentAdvancedOptional(ty, mod, strat), |
| 905 | 902 | .error_union_type => |info| return abiAlignmentAdvancedErrorUnion(ty, mod, strat, info.payload_type.toType()), |
| 906 | 903 | |
| 907 | 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 | 907 | // represents machine code; not a pointer |
| 911 | .func_type => |func_type| return AbiAlignmentAdvanced{ | |
| 912 | .scalar = if (func_type.alignment.toByteUnitsOptional()) |a| | |
| 913 | @as(u32, @intCast(a)) | |
| 908 | .func_type => |func_type| return .{ | |
| 909 | .scalar = if (func_type.alignment != .none) | |
| 910 | func_type.alignment | |
| 914 | 911 | else |
| 915 | 912 | target_util.defaultFunctionAlignment(target), |
| 916 | 913 | }, |
| ... | ... | @@ -926,47 +923,50 @@ pub const Type = struct { |
| 926 | 923 | .call_modifier, |
| 927 | 924 | .prefetch_options, |
| 928 | 925 | .anyopaque, |
| 929 | => return AbiAlignmentAdvanced{ .scalar = 1 }, | |
| 926 | => return .{ .scalar = .@"1" }, | |
| 930 | 927 | |
| 931 | 928 | .usize, |
| 932 | 929 | .isize, |
| 933 | 930 | .export_options, |
| 934 | 931 | .extern_options, |
| 935 | => return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, | |
| 936 | ||
| 937 | .c_char => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.char) }, | |
| 938 | .c_short => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.short) }, | |
| 939 | .c_ushort => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ushort) }, | |
| 940 | .c_int => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.int) }, | |
| 941 | .c_uint => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.uint) }, | |
| 942 | .c_long => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.long) }, | |
| 943 | .c_ulong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ulong) }, | |
| 944 | .c_longlong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longlong) }, | |
| 945 | .c_ulonglong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ulonglong) }, | |
| 946 | .c_longdouble => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) }, | |
| 947 | ||
| 948 | .f16 => return AbiAlignmentAdvanced{ .scalar = 2 }, | |
| 949 | .f32 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.float) }, | |
| 932 | .type_info, | |
| 933 | => return .{ | |
| 934 | .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)), | |
| 935 | }, | |
| 936 | ||
| 937 | .c_char => return .{ .scalar = cTypeAlign(target, .char) }, | |
| 938 | .c_short => return .{ .scalar = cTypeAlign(target, .short) }, | |
| 939 | .c_ushort => return .{ .scalar = cTypeAlign(target, .ushort) }, | |
| 940 | .c_int => return .{ .scalar = cTypeAlign(target, .int) }, | |
| 941 | .c_uint => return .{ .scalar = cTypeAlign(target, .uint) }, | |
| 942 | .c_long => return .{ .scalar = cTypeAlign(target, .long) }, | |
| 943 | .c_ulong => return .{ .scalar = cTypeAlign(target, .ulong) }, | |
| 944 | .c_longlong => return .{ .scalar = cTypeAlign(target, .longlong) }, | |
| 945 | .c_ulonglong => return .{ .scalar = cTypeAlign(target, .ulonglong) }, | |
| 946 | .c_longdouble => return .{ .scalar = cTypeAlign(target, .longdouble) }, | |
| 947 | ||
| 948 | .f16 => return .{ .scalar = .@"2" }, | |
| 949 | .f32 => return .{ .scalar = cTypeAlign(target, .float) }, | |
| 950 | 950 | .f64 => switch (target.c_type_bit_size(.double)) { |
| 951 | 64 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.double) }, | |
| 952 | else => return AbiAlignmentAdvanced{ .scalar = 8 }, | |
| 951 | 64 => return .{ .scalar = cTypeAlign(target, .double) }, | |
| 952 | else => return .{ .scalar = .@"8" }, | |
| 953 | 953 | }, |
| 954 | 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 | 956 | else => { |
| 957 | 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 | 961 | .f128 => switch (target.c_type_bit_size(.longdouble)) { |
| 962 | 128 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) }, | |
| 963 | else => return AbiAlignmentAdvanced{ .scalar = 16 }, | |
| 962 | 128 => return .{ .scalar = cTypeAlign(target, .longdouble) }, | |
| 963 | else => return .{ .scalar = .@"16" }, | |
| 964 | 964 | }, |
| 965 | 965 | |
| 966 | 966 | // TODO revisit this when we have the concept of the error tag type |
| 967 | 967 | .anyerror, |
| 968 | 968 | .adhoc_inferred_error_set, |
| 969 | => return AbiAlignmentAdvanced{ .scalar = 2 }, | |
| 969 | => return .{ .scalar = .@"2" }, | |
| 970 | 970 | |
| 971 | 971 | .void, |
| 972 | 972 | .type, |
| ... | ... | @@ -975,90 +975,46 @@ pub const Type = struct { |
| 975 | 975 | .null, |
| 976 | 976 | .undefined, |
| 977 | 977 | .enum_literal, |
| 978 | .type_info, | |
| 979 | => return AbiAlignmentAdvanced{ .scalar = 0 }, | |
| 978 | => return .{ .scalar = .@"1" }, | |
| 980 | 979 | |
| 981 | 980 | .noreturn => unreachable, |
| 982 | 981 | .generic_poison => unreachable, |
| 983 | 982 | }, |
| 984 | 983 | .struct_type => |struct_type| { |
| 985 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse | |
| 986 | return AbiAlignmentAdvanced{ .scalar = 0 }; | |
| 987 | ||
| 988 | if (opt_sema) |sema| { | |
| 989 | if (struct_obj.status == .field_types_wip) { | |
| 990 | // We'll guess "pointer-aligned", if the struct has an | |
| 991 | // underaligned pointer field then some allocations | |
| 992 | // might require explicit alignment. | |
| 993 | return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }; | |
| 994 | } | |
| 995 | _ = try sema.resolveTypeFields(ty); | |
| 996 | } | |
| 997 | if (!struct_obj.haveFieldTypes()) switch (strat) { | |
| 998 | .eager => unreachable, // struct layout not resolved | |
| 999 | .sema => unreachable, // handled above | |
| 1000 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1001 | .ty = .comptime_int_type, | |
| 1002 | .storage = .{ .lazy_align = ty.toIntern() }, | |
| 1003 | } })).toValue() }, | |
| 1004 | }; | |
| 1005 | if (struct_obj.layout == .Packed) { | |
| 984 | if (struct_type.layout == .Packed) { | |
| 1006 | 985 | switch (strat) { |
| 1007 | 986 | .sema => |sema| try sema.resolveTypeLayout(ty), |
| 1008 | .lazy => if (!struct_obj.haveLayout()) return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1009 | .ty = .comptime_int_type, | |
| 1010 | .storage = .{ .lazy_align = ty.toIntern() }, | |
| 1011 | } })).toValue() }, | |
| 1012 | .eager => {}, | |
| 1013 | } | |
| 1014 | assert(struct_obj.haveLayout()); | |
| 1015 | return AbiAlignmentAdvanced{ .scalar = struct_obj.backing_int_ty.abiAlignment(mod) }; | |
| 1016 | } | |
| 1017 | ||
| 1018 | const fields = ty.structFields(mod); | |
| 1019 | var big_align: u32 = 0; | |
| 1020 | for (fields.values()) |field| { | |
| 1021 | if (!(field.ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { | |
| 1022 | error.NeedLazy => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1023 | .ty = .comptime_int_type, | |
| 1024 | .storage = .{ .lazy_align = ty.toIntern() }, | |
| 1025 | } })).toValue() }, | |
| 1026 | else => |e| return e, | |
| 1027 | })) continue; | |
| 1028 | ||
| 1029 | const field_align = @as(u32, @intCast(field.abi_align.toByteUnitsOptional() orelse | |
| 1030 | switch (try field.ty.abiAlignmentAdvanced(mod, strat)) { | |
| 1031 | .scalar => |a| a, | |
| 1032 | .val => switch (strat) { | |
| 1033 | .eager => unreachable, // struct layout not resolved | |
| 1034 | .sema => unreachable, // handled above | |
| 1035 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 987 | .lazy => if (struct_type.backingIntType(ip).* == .none) return .{ | |
| 988 | .val = (try mod.intern(.{ .int = .{ | |
| 1036 | 989 | .ty = .comptime_int_type, |
| 1037 | 990 | .storage = .{ .lazy_align = ty.toIntern() }, |
| 1038 | } })).toValue() }, | |
| 991 | } })).toValue(), | |
| 1039 | 992 | }, |
| 1040 | })); | |
| 1041 | big_align = @max(big_align, field_align); | |
| 1042 | ||
| 1043 | // This logic is duplicated in Module.Struct.Field.alignment. | |
| 1044 | if (struct_obj.layout == .Extern or target.ofmt == .c) { | |
| 1045 | if (field.ty.isAbiInt(mod) and field.ty.intInfo(mod).bits >= 128) { | |
| 1046 | // The C ABI requires 128 bit integer fields of structs | |
| 1047 | // to be 16-bytes aligned. | |
| 1048 | big_align = @max(big_align, 16); | |
| 1049 | } | |
| 993 | .eager => {}, | |
| 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 | 1012 | .anon_struct_type => |tuple| { |
| 1055 | var big_align: u32 = 0; | |
| 1013 | var big_align: Alignment = .@"1"; | |
| 1056 | 1014 | for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| { |
| 1057 | 1015 | if (val != .none) continue; // comptime field |
| 1058 | if (!(field_ty.toType().hasRuntimeBits(mod))) continue; | |
| 1059 | ||
| 1060 | 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 | 1018 | .val => switch (strat) { |
| 1063 | 1019 | .eager => unreachable, // field type alignment not resolved |
| 1064 | 1020 | .sema => unreachable, // passed to abiAlignmentAdvanced above |
| ... | ... | @@ -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 | 1031 | .union_type => |union_type| { |
| ... | ... | @@ -1078,7 +1034,7 @@ pub const Type = struct { |
| 1078 | 1034 | // We'll guess "pointer-aligned", if the union has an |
| 1079 | 1035 | // underaligned pointer field then some allocations |
| 1080 | 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 | 1039 | _ = try sema.resolveTypeFields(ty); |
| 1084 | 1040 | } |
| ... | ... | @@ -1095,13 +1051,11 @@ pub const Type = struct { |
| 1095 | 1051 | if (union_obj.hasTag(ip)) { |
| 1096 | 1052 | return abiAlignmentAdvanced(union_obj.enum_tag_ty.toType(), mod, strat); |
| 1097 | 1053 | } else { |
| 1098 | return AbiAlignmentAdvanced{ | |
| 1099 | .scalar = @intFromBool(union_obj.flagsPtr(ip).layout == .Extern), | |
| 1100 | }; | |
| 1054 | return .{ .scalar = .@"1" }; | |
| 1101 | 1055 | } |
| 1102 | 1056 | } |
| 1103 | 1057 | |
| 1104 | var max_align: u32 = 0; | |
| 1058 | var max_align: Alignment = .@"1"; | |
| 1105 | 1059 | if (union_obj.hasTag(ip)) max_align = union_obj.enum_tag_ty.toType().abiAlignment(mod); |
| 1106 | 1060 | for (0..union_obj.field_names.len) |field_index| { |
| 1107 | 1061 | const field_ty = union_obj.field_types.get(ip)[field_index].toType(); |
| ... | ... | @@ -1117,8 +1071,9 @@ pub const Type = struct { |
| 1117 | 1071 | else => |e| return e, |
| 1118 | 1072 | })) continue; |
| 1119 | 1073 | |
| 1120 | const field_align_bytes: u32 = @intCast(field_align.toByteUnitsOptional() orelse | |
| 1121 | switch (try field_ty.abiAlignmentAdvanced(mod, strat)) { | |
| 1074 | const field_align_bytes: Alignment = if (field_align != .none) | |
| 1075 | field_align | |
| 1076 | else switch (try field_ty.abiAlignmentAdvanced(mod, strat)) { | |
| 1122 | 1077 | .scalar => |a| a, |
| 1123 | 1078 | .val => switch (strat) { |
| 1124 | 1079 | .eager => unreachable, // struct layout not resolved |
| ... | ... | @@ -1128,13 +1083,15 @@ pub const Type = struct { |
| 1128 | 1083 | .storage = .{ .lazy_align = ty.toIntern() }, |
| 1129 | 1084 | } })).toValue() }, |
| 1130 | 1085 | }, |
| 1131 | }); | |
| 1132 | max_align = @max(max_align, field_align_bytes); | |
| 1086 | }; | |
| 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 | 1096 | // values, not types |
| 1140 | 1097 | .undef, |
| ... | ... | @@ -1179,20 +1136,15 @@ pub const Type = struct { |
| 1179 | 1136 | } })).toValue() }, |
| 1180 | 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( | |
| 1185 | code_align, | |
| 1141 | return .{ .scalar = code_align.max( | |
| 1186 | 1142 | (try payload_ty.abiAlignmentAdvanced(mod, strat)).scalar, |
| 1187 | 1143 | ) }; |
| 1188 | 1144 | }, |
| 1189 | 1145 | .lazy => { |
| 1190 | 1146 | switch (try payload_ty.abiAlignmentAdvanced(mod, strat)) { |
| 1191 | .scalar => |payload_align| { | |
| 1192 | return AbiAlignmentAdvanced{ | |
| 1193 | .scalar = @max(code_align, payload_align), | |
| 1194 | }; | |
| 1195 | }, | |
| 1147 | .scalar => |payload_align| return .{ .scalar = code_align.max(payload_align) }, | |
| 1196 | 1148 | .val => {}, |
| 1197 | 1149 | } |
| 1198 | 1150 | return .{ .val = (try mod.intern(.{ .int = .{ |
| ... | ... | @@ -1212,9 +1164,11 @@ pub const Type = struct { |
| 1212 | 1164 | const child_type = ty.optionalChild(mod); |
| 1213 | 1165 | |
| 1214 | 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 | 1170 | .ErrorSet => return abiAlignmentAdvanced(Type.anyerror, mod, strat), |
| 1217 | .NoReturn => return AbiAlignmentAdvanced{ .scalar = 0 }, | |
| 1171 | .NoReturn => return .{ .scalar = .@"1" }, | |
| 1218 | 1172 | else => {}, |
| 1219 | 1173 | } |
| 1220 | 1174 | |
| ... | ... | @@ -1227,12 +1181,12 @@ pub const Type = struct { |
| 1227 | 1181 | } })).toValue() }, |
| 1228 | 1182 | else => |e| return e, |
| 1229 | 1183 | })) { |
| 1230 | return AbiAlignmentAdvanced{ .scalar = 1 }; | |
| 1184 | return .{ .scalar = .@"1" }; | |
| 1231 | 1185 | } |
| 1232 | 1186 | return child_type.abiAlignmentAdvanced(mod, strat); |
| 1233 | 1187 | }, |
| 1234 | 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 | 1190 | .val => return .{ .val = (try mod.intern(.{ .int = .{ |
| 1237 | 1191 | .ty = .comptime_int_type, |
| 1238 | 1192 | .storage = .{ .lazy_align = ty.toIntern() }, |
| ... | ... | @@ -1310,8 +1264,7 @@ pub const Type = struct { |
| 1310 | 1264 | .storage = .{ .lazy_size = ty.toIntern() }, |
| 1311 | 1265 | } })).toValue() }, |
| 1312 | 1266 | }; |
| 1313 | const elem_bits_u64 = try vector_type.child.toType().bitSizeAdvanced(mod, opt_sema); | |
| 1314 | const elem_bits = @as(u32, @intCast(elem_bits_u64)); | |
| 1267 | const elem_bits = try vector_type.child.toType().bitSizeAdvanced(mod, opt_sema); | |
| 1315 | 1268 | const total_bits = elem_bits * vector_type.len; |
| 1316 | 1269 | const total_bytes = (total_bits + 7) / 8; |
| 1317 | 1270 | const alignment = switch (try ty.abiAlignmentAdvanced(mod, strat)) { |
| ... | ... | @@ -1321,8 +1274,7 @@ pub const Type = struct { |
| 1321 | 1274 | .storage = .{ .lazy_size = ty.toIntern() }, |
| 1322 | 1275 | } })).toValue() }, |
| 1323 | 1276 | }; |
| 1324 | const result = std.mem.alignForward(u32, total_bytes, alignment); | |
| 1325 | return AbiSizeAdvanced{ .scalar = result }; | |
| 1277 | return AbiSizeAdvanced{ .scalar = alignment.forward(total_bytes) }; | |
| 1326 | 1278 | }, |
| 1327 | 1279 | |
| 1328 | 1280 | .opt_type => return ty.abiSizeAdvancedOptional(mod, strat), |
| ... | ... | @@ -1360,16 +1312,16 @@ pub const Type = struct { |
| 1360 | 1312 | }; |
| 1361 | 1313 | |
| 1362 | 1314 | var size: u64 = 0; |
| 1363 | if (code_align > payload_align) { | |
| 1315 | if (code_align.compare(.gt, payload_align)) { | |
| 1364 | 1316 | size += code_size; |
| 1365 | size = std.mem.alignForward(u64, size, payload_align); | |
| 1317 | size = payload_align.forward(size); | |
| 1366 | 1318 | size += payload_size; |
| 1367 | size = std.mem.alignForward(u64, size, code_align); | |
| 1319 | size = code_align.forward(size); | |
| 1368 | 1320 | } else { |
| 1369 | 1321 | size += payload_size; |
| 1370 | size = std.mem.alignForward(u64, size, code_align); | |
| 1322 | size = code_align.forward(size); | |
| 1371 | 1323 | size += code_size; |
| 1372 | size = std.mem.alignForward(u64, size, payload_align); | |
| 1324 | size = payload_align.forward(size); | |
| 1373 | 1325 | } |
| 1374 | 1326 | return AbiSizeAdvanced{ .scalar = size }; |
| 1375 | 1327 | }, |
| ... | ... | @@ -1435,41 +1387,35 @@ pub const Type = struct { |
| 1435 | 1387 | .noreturn => unreachable, |
| 1436 | 1388 | .generic_poison => unreachable, |
| 1437 | 1389 | }, |
| 1438 | .struct_type => |struct_type| switch (ty.containerLayout(mod)) { | |
| 1439 | .Packed => { | |
| 1440 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse | |
| 1441 | return AbiSizeAdvanced{ .scalar = 0 }; | |
| 1442 | ||
| 1443 | switch (strat) { | |
| 1444 | .sema => |sema| try sema.resolveTypeLayout(ty), | |
| 1445 | .lazy => if (!struct_obj.haveLayout()) return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1446 | .ty = .comptime_int_type, | |
| 1447 | .storage = .{ .lazy_size = ty.toIntern() }, | |
| 1448 | } })).toValue() }, | |
| 1449 | .eager => {}, | |
| 1450 | } | |
| 1451 | assert(struct_obj.haveLayout()); | |
| 1452 | return AbiSizeAdvanced{ .scalar = struct_obj.backing_int_ty.abiSize(mod) }; | |
| 1453 | }, | |
| 1454 | else => { | |
| 1455 | switch (strat) { | |
| 1456 | .sema => |sema| try sema.resolveTypeLayout(ty), | |
| 1457 | .lazy => { | |
| 1458 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse | |
| 1459 | return AbiSizeAdvanced{ .scalar = 0 }; | |
| 1460 | if (!struct_obj.haveLayout()) return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1461 | .ty = .comptime_int_type, | |
| 1462 | .storage = .{ .lazy_size = ty.toIntern() }, | |
| 1463 | } })).toValue() }; | |
| 1390 | .struct_type => |struct_type| { | |
| 1391 | switch (strat) { | |
| 1392 | .sema => |sema| try sema.resolveTypeLayout(ty), | |
| 1393 | .lazy => switch (struct_type.layout) { | |
| 1394 | .Packed => { | |
| 1395 | if (struct_type.backingIntType(ip).* == .none) return .{ | |
| 1396 | .val = (try mod.intern(.{ .int = .{ | |
| 1397 | .ty = .comptime_int_type, | |
| 1398 | .storage = .{ .lazy_size = ty.toIntern() }, | |
| 1399 | } })).toValue(), | |
| 1400 | }; | |
| 1464 | 1401 | }, |
| 1465 | .eager => {}, | |
| 1466 | } | |
| 1467 | const field_count = ty.structFieldCount(mod); | |
| 1468 | if (field_count == 0) { | |
| 1469 | return AbiSizeAdvanced{ .scalar = 0 }; | |
| 1470 | } | |
| 1471 | return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, mod) }; | |
| 1472 | }, | |
| 1402 | .Auto, .Extern => { | |
| 1403 | if (!struct_type.haveLayout(ip)) return .{ | |
| 1404 | .val = (try mod.intern(.{ .int = .{ | |
| 1405 | .ty = .comptime_int_type, | |
| 1406 | .storage = .{ .lazy_size = ty.toIntern() }, | |
| 1407 | } })).toValue(), | |
| 1408 | }; | |
| 1409 | }, | |
| 1410 | }, | |
| 1411 | .eager => {}, | |
| 1412 | } | |
| 1413 | return switch (struct_type.layout) { | |
| 1414 | .Packed => .{ | |
| 1415 | .scalar = struct_type.backingIntType(ip).toType().abiSize(mod), | |
| 1416 | }, | |
| 1417 | .Auto, .Extern => .{ .scalar = struct_type.size(ip).* }, | |
| 1418 | }; | |
| 1473 | 1419 | }, |
| 1474 | 1420 | .anon_struct_type => |tuple| { |
| 1475 | 1421 | switch (strat) { |
| ... | ... | @@ -1565,20 +1511,19 @@ pub const Type = struct { |
| 1565 | 1511 | // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal |
| 1566 | 1512 | // to the child type's ABI alignment. |
| 1567 | 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 | 1518 | fn intAbiSize(bits: u16, target: Target) u64 { |
| 1573 | const alignment = intAbiAlignment(bits, target); | |
| 1574 | return std.mem.alignForward(u64, @as(u16, @intCast((@as(u17, bits) + 7) / 8)), alignment); | |
| 1519 | return intAbiAlignment(bits, target).forward(@as(u16, @intCast((@as(u17, bits) + 7) / 8))); | |
| 1575 | 1520 | } |
| 1576 | 1521 | |
| 1577 | fn intAbiAlignment(bits: u16, target: Target) u32 { | |
| 1578 | return @min( | |
| 1522 | fn intAbiAlignment(bits: u16, target: Target) Alignment { | |
| 1523 | return Alignment.fromByteUnits(@min( | |
| 1579 | 1524 | std.math.ceilPowerOfTwoPromote(u16, @as(u16, @intCast((@as(u17, bits) + 7) / 8))), |
| 1580 | 1525 | target.maxIntAlignment(), |
| 1581 | ); | |
| 1526 | )); | |
| 1582 | 1527 | } |
| 1583 | 1528 | |
| 1584 | 1529 | pub fn bitSize(ty: Type, mod: *Module) u64 { |
| ... | ... | @@ -1610,7 +1555,7 @@ pub const Type = struct { |
| 1610 | 1555 | const len = array_type.len + @intFromBool(array_type.sentinel != .none); |
| 1611 | 1556 | if (len == 0) return 0; |
| 1612 | 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 | 1559 | if (elem_size == 0) return 0; |
| 1615 | 1560 | const elem_bit_size = try bitSizeAdvanced(elem_ty, mod, opt_sema); |
| 1616 | 1561 | return (len - 1) * 8 * elem_size + elem_bit_size; |
| ... | ... | @@ -1675,35 +1620,33 @@ pub const Type = struct { |
| 1675 | 1620 | .enum_literal => unreachable, |
| 1676 | 1621 | .generic_poison => unreachable, |
| 1677 | 1622 | |
| 1678 | .atomic_order => unreachable, // missing call to resolveTypeFields | |
| 1679 | .atomic_rmw_op => unreachable, // missing call to resolveTypeFields | |
| 1680 | .calling_convention => unreachable, // missing call to resolveTypeFields | |
| 1681 | .address_space => unreachable, // missing call to resolveTypeFields | |
| 1682 | .float_mode => unreachable, // missing call to resolveTypeFields | |
| 1683 | .reduce_op => unreachable, // missing call to resolveTypeFields | |
| 1684 | .call_modifier => unreachable, // missing call to resolveTypeFields | |
| 1685 | .prefetch_options => unreachable, // missing call to resolveTypeFields | |
| 1686 | .export_options => unreachable, // missing call to resolveTypeFields | |
| 1687 | .extern_options => unreachable, // missing call to resolveTypeFields | |
| 1688 | .type_info => unreachable, // missing call to resolveTypeFields | |
| 1623 | .atomic_order => unreachable, | |
| 1624 | .atomic_rmw_op => unreachable, | |
| 1625 | .calling_convention => unreachable, | |
| 1626 | .address_space => unreachable, | |
| 1627 | .float_mode => unreachable, | |
| 1628 | .reduce_op => unreachable, | |
| 1629 | .call_modifier => unreachable, | |
| 1630 | .prefetch_options => unreachable, | |
| 1631 | .export_options => unreachable, | |
| 1632 | .extern_options => unreachable, | |
| 1633 | .type_info => unreachable, | |
| 1689 | 1634 | }, |
| 1690 | 1635 | .struct_type => |struct_type| { |
| 1691 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return 0; | |
| 1692 | if (struct_obj.layout != .Packed) { | |
| 1693 | return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8; | |
| 1636 | if (struct_type.layout == .Packed) { | |
| 1637 | if (opt_sema) |sema| try sema.resolveTypeLayout(ty); | |
| 1638 | return try struct_type.backingIntType(ip).*.toType().bitSizeAdvanced(mod, opt_sema); | |
| 1694 | 1639 | } |
| 1695 | if (opt_sema) |sema| _ = try sema.resolveTypeLayout(ty); | |
| 1696 | assert(struct_obj.haveLayout()); | |
| 1697 | return try struct_obj.backing_int_ty.bitSizeAdvanced(mod, opt_sema); | |
| 1640 | return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8; | |
| 1698 | 1641 | }, |
| 1699 | 1642 | |
| 1700 | 1643 | .anon_struct_type => { |
| 1701 | if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty); | |
| 1644 | if (opt_sema) |sema| try sema.resolveTypeFields(ty); | |
| 1702 | 1645 | return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8; |
| 1703 | 1646 | }, |
| 1704 | 1647 | |
| 1705 | 1648 | .union_type => |union_type| { |
| 1706 | if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty); | |
| 1649 | if (opt_sema) |sema| try sema.resolveTypeFields(ty); | |
| 1707 | 1650 | if (ty.containerLayout(mod) != .Packed) { |
| 1708 | 1651 | return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8; |
| 1709 | 1652 | } |
| ... | ... | @@ -1749,13 +1692,7 @@ pub const Type = struct { |
| 1749 | 1692 | pub fn layoutIsResolved(ty: Type, mod: *Module) bool { |
| 1750 | 1693 | const ip = &mod.intern_pool; |
| 1751 | 1694 | return switch (ip.indexToKey(ty.toIntern())) { |
| 1752 | .struct_type => |struct_type| { | |
| 1753 | if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| { | |
| 1754 | return struct_obj.haveLayout(); | |
| 1755 | } else { | |
| 1756 | return true; | |
| 1757 | } | |
| 1758 | }, | |
| 1695 | .struct_type => |struct_type| struct_type.haveLayout(ip), | |
| 1759 | 1696 | .union_type => |union_type| union_type.haveLayout(ip), |
| 1760 | 1697 | .array_type => |array_type| { |
| 1761 | 1698 | if ((array_type.len + @intFromBool(array_type.sentinel != .none)) == 0) return true; |
| ... | ... | @@ -2020,10 +1957,7 @@ pub const Type = struct { |
| 2020 | 1957 | pub fn containerLayout(ty: Type, mod: *Module) std.builtin.Type.ContainerLayout { |
| 2021 | 1958 | const ip = &mod.intern_pool; |
| 2022 | 1959 | return switch (ip.indexToKey(ty.toIntern())) { |
| 2023 | .struct_type => |struct_type| { | |
| 2024 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return .Auto; | |
| 2025 | return struct_obj.layout; | |
| 2026 | }, | |
| 1960 | .struct_type => |struct_type| struct_type.layout, | |
| 2027 | 1961 | .anon_struct_type => .Auto, |
| 2028 | 1962 | .union_type => |union_type| union_type.flagsPtr(ip).layout, |
| 2029 | 1963 | else => unreachable, |
| ... | ... | @@ -2136,10 +2070,7 @@ pub const Type = struct { |
| 2136 | 2070 | return switch (ip.indexToKey(ty.toIntern())) { |
| 2137 | 2071 | .vector_type => |vector_type| vector_type.len, |
| 2138 | 2072 | .array_type => |array_type| array_type.len, |
| 2139 | .struct_type => |struct_type| { | |
| 2140 | const struct_obj = ip.structPtrUnwrapConst(struct_type.index) orelse return 0; | |
| 2141 | return struct_obj.fields.count(); | |
| 2142 | }, | |
| 2073 | .struct_type => |struct_type| struct_type.field_types.len, | |
| 2143 | 2074 | .anon_struct_type => |tuple| tuple.types.len, |
| 2144 | 2075 | |
| 2145 | 2076 | else => unreachable, |
| ... | ... | @@ -2214,6 +2145,7 @@ pub const Type = struct { |
| 2214 | 2145 | |
| 2215 | 2146 | /// Asserts the type is an integer, enum, error set, or vector of one of them. |
| 2216 | 2147 | pub fn intInfo(starting_ty: Type, mod: *Module) InternPool.Key.IntType { |
| 2148 | const ip = &mod.intern_pool; | |
| 2217 | 2149 | const target = mod.getTarget(); |
| 2218 | 2150 | var ty = starting_ty; |
| 2219 | 2151 | |
| ... | ... | @@ -2233,13 +2165,9 @@ pub const Type = struct { |
| 2233 | 2165 | .c_ulong_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulong) }, |
| 2234 | 2166 | .c_longlong_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.longlong) }, |
| 2235 | 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 | 2169 | .int_type => |int_type| return int_type, |
| 2238 | .struct_type => |struct_type| { | |
| 2239 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 2240 | assert(struct_obj.layout == .Packed); | |
| 2241 | ty = struct_obj.backing_int_ty; | |
| 2242 | }, | |
| 2170 | .struct_type => |t| ty = t.backingIntType(ip).*.toType(), | |
| 2243 | 2171 | .enum_type => |enum_type| ty = enum_type.tag_ty.toType(), |
| 2244 | 2172 | .vector_type => |vector_type| ty = vector_type.child.toType(), |
| 2245 | 2173 | |
| ... | ... | @@ -2503,33 +2431,28 @@ pub const Type = struct { |
| 2503 | 2431 | .generic_poison => unreachable, |
| 2504 | 2432 | }, |
| 2505 | 2433 | .struct_type => |struct_type| { |
| 2506 | if (mod.structPtrUnwrap(struct_type.index)) |s| { | |
| 2507 | assert(s.haveFieldTypes()); | |
| 2508 | const field_vals = try mod.gpa.alloc(InternPool.Index, s.fields.count()); | |
| 2509 | defer mod.gpa.free(field_vals); | |
| 2510 | for (field_vals, s.fields.values()) |*field_val, field| { | |
| 2511 | if (field.is_comptime) { | |
| 2512 | field_val.* = field.default_val; | |
| 2513 | continue; | |
| 2514 | } | |
| 2515 | if (try field.ty.onePossibleValue(mod)) |field_opv| { | |
| 2516 | field_val.* = try field_opv.intern(field.ty, mod); | |
| 2517 | } else return null; | |
| 2434 | assert(struct_type.haveFieldTypes(ip)); | |
| 2435 | if (struct_type.knownNonOpv(ip)) | |
| 2436 | return null; | |
| 2437 | const field_vals = try mod.gpa.alloc(InternPool.Index, struct_type.field_types.len); | |
| 2438 | defer mod.gpa.free(field_vals); | |
| 2439 | for (field_vals, 0..) |*field_val, i_usize| { | |
| 2440 | const i: u32 = @intCast(i_usize); | |
| 2441 | if (struct_type.fieldIsComptime(ip, i)) { | |
| 2442 | field_val.* = struct_type.field_inits.get(ip)[i]; | |
| 2443 | continue; | |
| 2518 | 2444 | } |
| 2519 | ||
| 2520 | // In this case the struct has no runtime-known fields and | |
| 2521 | // therefore has one possible value. | |
| 2522 | return (try mod.intern(.{ .aggregate = .{ | |
| 2523 | .ty = ty.toIntern(), | |
| 2524 | .storage = .{ .elems = field_vals }, | |
| 2525 | } })).toValue(); | |
| 2445 | const field_ty = struct_type.field_types.get(ip)[i].toType(); | |
| 2446 | if (try field_ty.onePossibleValue(mod)) |field_opv| { | |
| 2447 | field_val.* = try field_opv.intern(field_ty, mod); | |
| 2448 | } else return null; | |
| 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 | 2452 | // therefore has one possible value. |
| 2530 | 2453 | return (try mod.intern(.{ .aggregate = .{ |
| 2531 | 2454 | .ty = ty.toIntern(), |
| 2532 | .storage = .{ .elems = &.{} }, | |
| 2455 | .storage = .{ .elems = field_vals }, | |
| 2533 | 2456 | } })).toValue(); |
| 2534 | 2457 | }, |
| 2535 | 2458 | |
| ... | ... | @@ -2715,18 +2638,20 @@ pub const Type = struct { |
| 2715 | 2638 | => true, |
| 2716 | 2639 | }, |
| 2717 | 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 | 2646 | // A struct with no fields is not comptime-only. |
| 2719 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false; | |
| 2720 | switch (struct_obj.requires_comptime) { | |
| 2721 | .wip, .unknown => { | |
| 2722 | // Return false to avoid incorrect dependency loops. | |
| 2723 | // This will be handled correctly once merged with | |
| 2724 | // `Sema.typeRequiresComptime`. | |
| 2725 | return false; | |
| 2726 | }, | |
| 2727 | .no => return false, | |
| 2728 | .yes => return true, | |
| 2729 | } | |
| 2647 | return switch (struct_type.flagsPtr(ip).requires_comptime) { | |
| 2648 | // Return false to avoid incorrect dependency loops. | |
| 2649 | // This will be handled correctly once merged with | |
| 2650 | // `Sema.typeRequiresComptime`. | |
| 2651 | .wip, .unknown => false, | |
| 2652 | .no => false, | |
| 2653 | .yes => true, | |
| 2654 | }; | |
| 2730 | 2655 | }, |
| 2731 | 2656 | |
| 2732 | 2657 | .anon_struct_type => |tuple| { |
| ... | ... | @@ -2982,37 +2907,31 @@ pub const Type = struct { |
| 2982 | 2907 | return enum_type.tagValueIndex(ip, int_tag); |
| 2983 | 2908 | } |
| 2984 | 2909 | |
| 2985 | pub fn structFields(ty: Type, mod: *Module) Module.Struct.Fields { | |
| 2986 | switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 2987 | .struct_type => |struct_type| { | |
| 2988 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return .{}; | |
| 2989 | assert(struct_obj.haveFieldTypes()); | |
| 2990 | return struct_obj.fields; | |
| 2991 | }, | |
| 2992 | else => unreachable, | |
| 2993 | } | |
| 2994 | } | |
| 2995 | ||
| 2996 | pub fn structFieldName(ty: Type, field_index: usize, mod: *Module) InternPool.NullTerminatedString { | |
| 2910 | /// Returns none in the case of a tuple which uses the integer index as the field name. | |
| 2911 | pub fn structFieldName(ty: Type, field_index: u32, mod: *Module) InternPool.OptionalNullTerminatedString { | |
| 2997 | 2912 | const ip = &mod.intern_pool; |
| 2998 | 2913 | return switch (ip.indexToKey(ty.toIntern())) { |
| 2999 | .struct_type => |struct_type| { | |
| 3000 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 3001 | assert(struct_obj.haveFieldTypes()); | |
| 3002 | return struct_obj.fields.keys()[field_index]; | |
| 3003 | }, | |
| 3004 | .anon_struct_type => |anon_struct| anon_struct.names.get(ip)[field_index], | |
| 2914 | .struct_type => |struct_type| struct_type.fieldName(ip, field_index), | |
| 2915 | .anon_struct_type => |anon_struct| anon_struct.fieldName(ip, field_index), | |
| 3005 | 2916 | else => unreachable, |
| 3006 | 2917 | }; |
| 3007 | 2918 | } |
| 3008 | 2919 | |
| 3009 | pub fn structFieldCount(ty: Type, mod: *Module) usize { | |
| 3010 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { | |
| 3011 | .struct_type => |struct_type| { | |
| 3012 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return 0; | |
| 3013 | assert(struct_obj.haveFieldTypes()); | |
| 3014 | return struct_obj.fields.count(); | |
| 3015 | }, | |
| 2920 | /// When struct types have no field names, the names are implicitly understood to be | |
| 2921 | /// strings corresponding to the field indexes in declaration order. It used to be the | |
| 2922 | /// case that a NullTerminatedString would be stored for each field in this case, however, | |
| 2923 | /// now, callers must handle the possibility that there are no names stored at all. | |
| 2924 | /// Here we fake the previous behavior. Probably something better could be done by examining | |
| 2925 | /// all the callsites of this function. | |
| 2926 | pub fn legacyStructFieldName(ty: Type, i: u32, mod: *Module) InternPool.NullTerminatedString { | |
| 2927 | return ty.structFieldName(i, mod).unwrap() orelse | |
| 2928 | mod.intern_pool.getOrPutStringFmt(mod.gpa, "{d}", .{i}) catch @panic("OOM"); | |
| 2929 | } | |
| 2930 | ||
| 2931 | pub fn structFieldCount(ty: Type, mod: *Module) u32 { | |
| 2932 | const ip = &mod.intern_pool; | |
| 2933 | return switch (ip.indexToKey(ty.toIntern())) { | |
| 2934 | .struct_type => |struct_type| struct_type.field_types.len, | |
| 3016 | 2935 | .anon_struct_type => |anon_struct| anon_struct.types.len, |
| 3017 | 2936 | else => unreachable, |
| 3018 | 2937 | }; |
| ... | ... | @@ -3022,11 +2941,7 @@ pub const Type = struct { |
| 3022 | 2941 | pub fn structFieldType(ty: Type, index: usize, mod: *Module) Type { |
| 3023 | 2942 | const ip = &mod.intern_pool; |
| 3024 | 2943 | return switch (ip.indexToKey(ty.toIntern())) { |
| 3025 | .struct_type => |struct_type| { | |
| 3026 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 3027 | assert(struct_obj.haveFieldTypes()); | |
| 3028 | return struct_obj.fields.values()[index].ty; | |
| 3029 | }, | |
| 2944 | .struct_type => |struct_type| struct_type.field_types.get(ip)[index].toType(), | |
| 3030 | 2945 | .union_type => |union_type| { |
| 3031 | 2946 | const union_obj = ip.loadUnionType(union_type); |
| 3032 | 2947 | return union_obj.field_types.get(ip)[index].toType(); |
| ... | ... | @@ -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 | 2955 | const ip = &mod.intern_pool; |
| 3041 | 2956 | switch (ip.indexToKey(ty.toIntern())) { |
| 3042 | 2957 | .struct_type => |struct_type| { |
| 3043 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 3044 | assert(struct_obj.layout != .Packed); | |
| 3045 | return struct_obj.fields.values()[index].alignment(mod, struct_obj.layout); | |
| 2958 | assert(struct_type.layout != .Packed); | |
| 2959 | const explicit_align = struct_type.fieldAlign(ip, index); | |
| 2960 | const field_ty = struct_type.field_types.get(ip)[index].toType(); | |
| 2961 | return mod.structFieldAlignment(explicit_align, field_ty, struct_type.layout); | |
| 3046 | 2962 | }, |
| 3047 | 2963 | .anon_struct_type => |anon_struct| { |
| 3048 | 2964 | return anon_struct.types.get(ip)[index].toType().abiAlignment(mod); |
| ... | ... | @@ -3059,8 +2975,7 @@ pub const Type = struct { |
| 3059 | 2975 | const ip = &mod.intern_pool; |
| 3060 | 2976 | switch (ip.indexToKey(ty.toIntern())) { |
| 3061 | 2977 | .struct_type => |struct_type| { |
| 3062 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 3063 | const val = struct_obj.fields.values()[index].default_val; | |
| 2978 | const val = struct_type.fieldInit(ip, index); | |
| 3064 | 2979 | // TODO: avoid using `unreachable` to indicate this. |
| 3065 | 2980 | if (val == .none) return Value.@"unreachable"; |
| 3066 | 2981 | return val.toValue(); |
| ... | ... | @@ -3079,12 +2994,10 @@ pub const Type = struct { |
| 3079 | 2994 | const ip = &mod.intern_pool; |
| 3080 | 2995 | switch (ip.indexToKey(ty.toIntern())) { |
| 3081 | 2996 | .struct_type => |struct_type| { |
| 3082 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 3083 | const field = struct_obj.fields.values()[index]; | |
| 3084 | if (field.is_comptime) { | |
| 3085 | return field.default_val.toValue(); | |
| 2997 | if (struct_type.fieldIsComptime(ip, index)) { | |
| 2998 | return struct_type.field_inits.get(ip)[index].toValue(); | |
| 3086 | 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 | 3003 | .anon_struct_type => |tuple| { |
| ... | ... | @@ -3102,30 +3015,25 @@ pub const Type = struct { |
| 3102 | 3015 | pub fn structFieldIsComptime(ty: Type, index: usize, mod: *Module) bool { |
| 3103 | 3016 | const ip = &mod.intern_pool; |
| 3104 | 3017 | return switch (ip.indexToKey(ty.toIntern())) { |
| 3105 | .struct_type => |struct_type| { | |
| 3106 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 3107 | if (struct_obj.layout == .Packed) return false; | |
| 3108 | const field = struct_obj.fields.values()[index]; | |
| 3109 | return field.is_comptime; | |
| 3110 | }, | |
| 3018 | .struct_type => |struct_type| struct_type.fieldIsComptime(ip, index), | |
| 3111 | 3019 | .anon_struct_type => |anon_struct| anon_struct.values.get(ip)[index] != .none, |
| 3112 | 3020 | else => unreachable, |
| 3113 | 3021 | }; |
| 3114 | 3022 | } |
| 3115 | 3023 | |
| 3116 | 3024 | pub fn packedStructFieldByteOffset(ty: Type, field_index: usize, mod: *Module) u32 { |
| 3117 | const struct_type = mod.intern_pool.indexToKey(ty.toIntern()).struct_type; | |
| 3118 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 3119 | assert(struct_obj.layout == .Packed); | |
| 3025 | const ip = &mod.intern_pool; | |
| 3026 | const struct_type = ip.indexToKey(ty.toIntern()).struct_type; | |
| 3027 | assert(struct_type.layout == .Packed); | |
| 3120 | 3028 | comptime assert(Type.packed_struct_layout_version == 2); |
| 3121 | 3029 | |
| 3122 | 3030 | var bit_offset: u16 = undefined; |
| 3123 | 3031 | var elem_size_bits: u16 = undefined; |
| 3124 | 3032 | var running_bits: u16 = 0; |
| 3125 | for (struct_obj.fields.values(), 0..) |f, i| { | |
| 3126 | if (!f.ty.hasRuntimeBits(mod)) continue; | |
| 3033 | for (struct_type.field_types.get(ip), 0..) |field_ty, i| { | |
| 3034 | if (!field_ty.toType().hasRuntimeBits(mod)) continue; | |
| 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 | 3037 | if (i == field_index) { |
| 3130 | 3038 | bit_offset = running_bits; |
| 3131 | 3039 | elem_size_bits = field_bits; |
| ... | ... | @@ -3141,68 +3049,19 @@ pub const Type = struct { |
| 3141 | 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 | 3052 | /// Supports structs and unions. |
| 3187 | 3053 | pub fn structFieldOffset(ty: Type, index: usize, mod: *Module) u64 { |
| 3188 | 3054 | const ip = &mod.intern_pool; |
| 3189 | 3055 | switch (ip.indexToKey(ty.toIntern())) { |
| 3190 | 3056 | .struct_type => |struct_type| { |
| 3191 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 3192 | assert(struct_obj.haveLayout()); | |
| 3193 | assert(struct_obj.layout != .Packed); | |
| 3194 | var it = ty.iterateStructOffsets(mod); | |
| 3195 | while (it.next()) |field_offset| { | |
| 3196 | if (index == field_offset.field) | |
| 3197 | return field_offset.offset; | |
| 3198 | } | |
| 3199 | ||
| 3200 | return std.mem.alignForward(u64, it.offset, @max(it.big_align, 1)); | |
| 3057 | assert(struct_type.haveLayout(ip)); | |
| 3058 | assert(struct_type.layout != .Packed); | |
| 3059 | return struct_type.offsets.get(ip)[index]; | |
| 3201 | 3060 | }, |
| 3202 | 3061 | |
| 3203 | 3062 | .anon_struct_type => |tuple| { |
| 3204 | 3063 | var offset: u64 = 0; |
| 3205 | var big_align: u32 = 0; | |
| 3064 | var big_align: Alignment = .none; | |
| 3206 | 3065 | |
| 3207 | 3066 | for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, field_val, i| { |
| 3208 | 3067 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) { |
| ... | ... | @@ -3212,12 +3071,12 @@ pub const Type = struct { |
| 3212 | 3071 | } |
| 3213 | 3072 | |
| 3214 | 3073 | const field_align = field_ty.toType().abiAlignment(mod); |
| 3215 | big_align = @max(big_align, field_align); | |
| 3216 | offset = std.mem.alignForward(u64, offset, field_align); | |
| 3074 | big_align = big_align.max(field_align); | |
| 3075 | offset = field_align.forward(offset); | |
| 3217 | 3076 | if (i == index) return offset; |
| 3218 | 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 | 3080 | return offset; |
| 3222 | 3081 | }, |
| 3223 | 3082 | |
| ... | ... | @@ -3226,9 +3085,9 @@ pub const Type = struct { |
| 3226 | 3085 | return 0; |
| 3227 | 3086 | const union_obj = ip.loadUnionType(union_type); |
| 3228 | 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 | 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 | 3091 | } else { |
| 3233 | 3092 | // {Payload, Tag} |
| 3234 | 3093 | return 0; |
| ... | ... | @@ -3246,8 +3105,7 @@ pub const Type = struct { |
| 3246 | 3105 | pub fn declSrcLocOrNull(ty: Type, mod: *Module) ?Module.SrcLoc { |
| 3247 | 3106 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 3248 | 3107 | .struct_type => |struct_type| { |
| 3249 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 3250 | return struct_obj.srcLoc(mod); | |
| 3108 | return mod.declPtr(struct_type.decl.unwrap() orelse return null).srcLoc(mod); | |
| 3251 | 3109 | }, |
| 3252 | 3110 | .union_type => |union_type| { |
| 3253 | 3111 | return mod.declPtr(union_type.decl).srcLoc(mod); |
| ... | ... | @@ -3264,10 +3122,7 @@ pub const Type = struct { |
| 3264 | 3122 | |
| 3265 | 3123 | pub fn getOwnerDeclOrNull(ty: Type, mod: *Module) ?Module.Decl.Index { |
| 3266 | 3124 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 3267 | .struct_type => |struct_type| { | |
| 3268 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return null; | |
| 3269 | return struct_obj.owner_decl; | |
| 3270 | }, | |
| 3125 | .struct_type => |struct_type| struct_type.decl.unwrap(), | |
| 3271 | 3126 | .union_type => |union_type| union_type.decl, |
| 3272 | 3127 | .opaque_type => |opaque_type| opaque_type.decl, |
| 3273 | 3128 | .enum_type => |enum_type| enum_type.decl, |
| ... | ... | @@ -3280,10 +3135,12 @@ pub const Type = struct { |
| 3280 | 3135 | } |
| 3281 | 3136 | |
| 3282 | 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 | 3140 | .struct_type => |struct_type| { |
| 3285 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false; | |
| 3286 | return struct_obj.is_tuple; | |
| 3141 | if (struct_type.layout == .Packed) return false; | |
| 3142 | if (struct_type.decl == .none) return false; | |
| 3143 | return struct_type.flagsPtr(ip).is_tuple; | |
| 3287 | 3144 | }, |
| 3288 | 3145 | .anon_struct_type => |anon_struct| anon_struct.names.len == 0, |
| 3289 | 3146 | else => false, |
| ... | ... | @@ -3299,10 +3156,12 @@ pub const Type = struct { |
| 3299 | 3156 | } |
| 3300 | 3157 | |
| 3301 | 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 | 3161 | .struct_type => |struct_type| { |
| 3304 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false; | |
| 3305 | return struct_obj.is_tuple; | |
| 3162 | if (struct_type.layout == .Packed) return false; | |
| 3163 | if (struct_type.decl == .none) return false; | |
| 3164 | return struct_type.flagsPtr(ip).is_tuple; | |
| 3306 | 3165 | }, |
| 3307 | 3166 | .anon_struct_type => true, |
| 3308 | 3167 | else => false, |
| ... | ... | @@ -3391,3 +3250,7 @@ pub const Type = struct { |
| 3391 | 3250 | /// to packed struct layout to find out all the places in the codebase you need to edit! |
| 3392 | 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 | 462 | if (opt_sema) |sema| try sema.resolveTypeLayout(ty.toType()); |
| 463 | 463 | const x = switch (int.storage) { |
| 464 | 464 | else => unreachable, |
| 465 | .lazy_align => ty.toType().abiAlignment(mod), | |
| 465 | .lazy_align => ty.toType().abiAlignment(mod).toByteUnits(0), | |
| 466 | 466 | .lazy_size => ty.toType().abiSize(mod), |
| 467 | 467 | }; |
| 468 | 468 | return BigIntMutable.init(&space.limbs, x).toConst(); |
| ... | ... | @@ -523,9 +523,9 @@ pub const Value = struct { |
| 523 | 523 | .u64 => |x| x, |
| 524 | 524 | .i64 => |x| std.math.cast(u64, x), |
| 525 | 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 | 527 | else |
| 528 | ty.toType().abiAlignment(mod), | |
| 528 | ty.toType().abiAlignment(mod).toByteUnits(0), | |
| 529 | 529 | .lazy_size => |ty| if (opt_sema) |sema| |
| 530 | 530 | (try ty.toType().abiSizeAdvanced(mod, .{ .sema = sema })).scalar |
| 531 | 531 | else |
| ... | ... | @@ -569,9 +569,9 @@ pub const Value = struct { |
| 569 | 569 | .int => |int| switch (int.storage) { |
| 570 | 570 | .big_int => |big_int| big_int.to(i64) catch unreachable, |
| 571 | 571 | .i64 => |x| x, |
| 572 | .u64 => |x| @as(i64, @intCast(x)), | |
| 573 | .lazy_align => |ty| @as(i64, @intCast(ty.toType().abiAlignment(mod))), | |
| 574 | .lazy_size => |ty| @as(i64, @intCast(ty.toType().abiSize(mod))), | |
| 572 | .u64 => |x| @intCast(x), | |
| 573 | .lazy_align => |ty| @intCast(ty.toType().abiAlignment(mod).toByteUnits(0)), | |
| 574 | .lazy_size => |ty| @intCast(ty.toType().abiSize(mod)), | |
| 575 | 575 | }, |
| 576 | 576 | else => unreachable, |
| 577 | 577 | }, |
| ... | ... | @@ -612,10 +612,11 @@ pub const Value = struct { |
| 612 | 612 | const target = mod.getTarget(); |
| 613 | 613 | const endian = target.cpu.arch.endian(); |
| 614 | 614 | if (val.isUndef(mod)) { |
| 615 | const size = @as(usize, @intCast(ty.abiSize(mod))); | |
| 615 | const size: usize = @intCast(ty.abiSize(mod)); | |
| 616 | 616 | @memset(buffer[0..size], 0xaa); |
| 617 | 617 | return; |
| 618 | 618 | } |
| 619 | const ip = &mod.intern_pool; | |
| 619 | 620 | switch (ty.zigTypeTag(mod)) { |
| 620 | 621 | .Void => {}, |
| 621 | 622 | .Bool => { |
| ... | ... | @@ -656,40 +657,44 @@ pub const Value = struct { |
| 656 | 657 | const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; |
| 657 | 658 | return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0); |
| 658 | 659 | }, |
| 659 | .Struct => switch (ty.containerLayout(mod)) { | |
| 660 | .Auto => return error.IllDefinedMemoryLayout, | |
| 661 | .Extern => for (ty.structFields(mod).values(), 0..) |field, i| { | |
| 662 | const off = @as(usize, @intCast(ty.structFieldOffset(i, mod))); | |
| 663 | const field_val = switch (val.ip_index) { | |
| 664 | .none => switch (val.tag()) { | |
| 665 | .bytes => { | |
| 666 | buffer[off] = val.castTag(.bytes).?.data[i]; | |
| 667 | continue; | |
| 668 | }, | |
| 669 | .aggregate => val.castTag(.aggregate).?.data[i], | |
| 670 | .repeated => val.castTag(.repeated).?.data, | |
| 671 | else => unreachable, | |
| 672 | }, | |
| 673 | else => switch (mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage) { | |
| 674 | .bytes => |bytes| { | |
| 675 | buffer[off] = bytes[i]; | |
| 676 | continue; | |
| 660 | .Struct => { | |
| 661 | const struct_type = mod.typeToStruct(ty) orelse return error.IllDefinedMemoryLayout; | |
| 662 | switch (struct_type.layout) { | |
| 663 | .Auto => return error.IllDefinedMemoryLayout, | |
| 664 | .Extern => for (0..struct_type.field_types.len) |i| { | |
| 665 | const off: usize = @intCast(ty.structFieldOffset(i, mod)); | |
| 666 | const field_val = switch (val.ip_index) { | |
| 667 | .none => switch (val.tag()) { | |
| 668 | .bytes => { | |
| 669 | buffer[off] = val.castTag(.bytes).?.data[i]; | |
| 670 | continue; | |
| 671 | }, | |
| 672 | .aggregate => val.castTag(.aggregate).?.data[i], | |
| 673 | .repeated => val.castTag(.repeated).?.data, | |
| 674 | else => unreachable, | |
| 677 | 675 | }, |
| 678 | .elems => |elems| elems[i], | |
| 679 | .repeated_elem => |elem| elem, | |
| 680 | }.toValue(), | |
| 681 | }; | |
| 682 | try writeToMemory(field_val, field.ty, mod, buffer[off..]); | |
| 683 | }, | |
| 684 | .Packed => { | |
| 685 | const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; | |
| 686 | return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0); | |
| 687 | }, | |
| 676 | else => switch (ip.indexToKey(val.toIntern()).aggregate.storage) { | |
| 677 | .bytes => |bytes| { | |
| 678 | buffer[off] = bytes[i]; | |
| 679 | continue; | |
| 680 | }, | |
| 681 | .elems => |elems| elems[i], | |
| 682 | .repeated_elem => |elem| elem, | |
| 683 | }.toValue(), | |
| 684 | }; | |
| 685 | const field_ty = struct_type.field_types.get(ip)[i].toType(); | |
| 686 | try writeToMemory(field_val, field_ty, mod, buffer[off..]); | |
| 687 | }, | |
| 688 | .Packed => { | |
| 689 | const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; | |
| 690 | return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0); | |
| 691 | }, | |
| 692 | } | |
| 688 | 693 | }, |
| 689 | 694 | .ErrorSet => { |
| 690 | 695 | // TODO revisit this when we have the concept of the error tag type |
| 691 | 696 | const Int = u16; |
| 692 | const name = switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 697 | const name = switch (ip.indexToKey(val.toIntern())) { | |
| 693 | 698 | .err => |err| err.name, |
| 694 | 699 | .error_union => |error_union| error_union.val.err_name, |
| 695 | 700 | else => unreachable, |
| ... | ... | @@ -790,24 +795,24 @@ pub const Value = struct { |
| 790 | 795 | bits += elem_bit_size; |
| 791 | 796 | } |
| 792 | 797 | }, |
| 793 | .Struct => switch (ty.containerLayout(mod)) { | |
| 794 | .Auto => unreachable, // Sema is supposed to have emitted a compile error already | |
| 795 | .Extern => unreachable, // Handled in non-packed writeToMemory | |
| 796 | .Packed => { | |
| 797 | var bits: u16 = 0; | |
| 798 | const fields = ty.structFields(mod).values(); | |
| 799 | const storage = ip.indexToKey(val.toIntern()).aggregate.storage; | |
| 800 | for (fields, 0..) |field, i| { | |
| 801 | const field_bits = @as(u16, @intCast(field.ty.bitSize(mod))); | |
| 802 | const field_val = switch (storage) { | |
| 803 | .bytes => unreachable, | |
| 804 | .elems => |elems| elems[i], | |
| 805 | .repeated_elem => |elem| elem, | |
| 806 | }; | |
| 807 | try field_val.toValue().writeToPackedMemory(field.ty, mod, buffer, bit_offset + bits); | |
| 808 | bits += field_bits; | |
| 809 | } | |
| 810 | }, | |
| 798 | .Struct => { | |
| 799 | const struct_type = ip.indexToKey(ty.toIntern()).struct_type; | |
| 800 | // Sema is supposed to have emitted a compile error already in the case of Auto, | |
| 801 | // and Extern is handled in non-packed writeToMemory. | |
| 802 | assert(struct_type.layout == .Packed); | |
| 803 | var bits: u16 = 0; | |
| 804 | const storage = ip.indexToKey(val.toIntern()).aggregate.storage; | |
| 805 | for (0..struct_type.field_types.len) |i| { | |
| 806 | const field_ty = struct_type.field_types.get(ip)[i].toType(); | |
| 807 | const field_bits: u16 = @intCast(field_ty.bitSize(mod)); | |
| 808 | const field_val = switch (storage) { | |
| 809 | .bytes => unreachable, | |
| 810 | .elems => |elems| elems[i], | |
| 811 | .repeated_elem => |elem| elem, | |
| 812 | }; | |
| 813 | try field_val.toValue().writeToPackedMemory(field_ty, mod, buffer, bit_offset + bits); | |
| 814 | bits += field_bits; | |
| 815 | } | |
| 811 | 816 | }, |
| 812 | 817 | .Union => { |
| 813 | 818 | const union_obj = mod.typeToUnion(ty).?; |
| ... | ... | @@ -852,6 +857,7 @@ pub const Value = struct { |
| 852 | 857 | buffer: []const u8, |
| 853 | 858 | arena: Allocator, |
| 854 | 859 | ) Allocator.Error!Value { |
| 860 | const ip = &mod.intern_pool; | |
| 855 | 861 | const target = mod.getTarget(); |
| 856 | 862 | const endian = target.cpu.arch.endian(); |
| 857 | 863 | switch (ty.zigTypeTag(mod)) { |
| ... | ... | @@ -926,25 +932,29 @@ pub const Value = struct { |
| 926 | 932 | const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; |
| 927 | 933 | return readFromPackedMemory(ty, mod, buffer[0..byte_count], 0, arena); |
| 928 | 934 | }, |
| 929 | .Struct => switch (ty.containerLayout(mod)) { | |
| 930 | .Auto => unreachable, // Sema is supposed to have emitted a compile error already | |
| 931 | .Extern => { | |
| 932 | const fields = ty.structFields(mod).values(); | |
| 933 | const field_vals = try arena.alloc(InternPool.Index, fields.len); | |
| 934 | for (field_vals, fields, 0..) |*field_val, field, i| { | |
| 935 | const off = @as(usize, @intCast(ty.structFieldOffset(i, mod))); | |
| 936 | const sz = @as(usize, @intCast(field.ty.abiSize(mod))); | |
| 937 | field_val.* = try (try readFromMemory(field.ty, mod, buffer[off..(off + sz)], arena)).intern(field.ty, mod); | |
| 938 | } | |
| 939 | return (try mod.intern(.{ .aggregate = .{ | |
| 940 | .ty = ty.toIntern(), | |
| 941 | .storage = .{ .elems = field_vals }, | |
| 942 | } })).toValue(); | |
| 943 | }, | |
| 944 | .Packed => { | |
| 945 | const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; | |
| 946 | return readFromPackedMemory(ty, mod, buffer[0..byte_count], 0, arena); | |
| 947 | }, | |
| 935 | .Struct => { | |
| 936 | const struct_type = mod.typeToStruct(ty).?; | |
| 937 | switch (struct_type.layout) { | |
| 938 | .Auto => unreachable, // Sema is supposed to have emitted a compile error already | |
| 939 | .Extern => { | |
| 940 | const field_types = struct_type.field_types; | |
| 941 | const field_vals = try arena.alloc(InternPool.Index, field_types.len); | |
| 942 | for (field_vals, 0..) |*field_val, i| { | |
| 943 | const field_ty = field_types.get(ip)[i].toType(); | |
| 944 | const off: usize = @intCast(ty.structFieldOffset(i, mod)); | |
| 945 | const sz: usize = @intCast(field_ty.abiSize(mod)); | |
| 946 | field_val.* = try (try readFromMemory(field_ty, mod, buffer[off..(off + sz)], arena)).intern(field_ty, mod); | |
| 947 | } | |
| 948 | return (try mod.intern(.{ .aggregate = .{ | |
| 949 | .ty = ty.toIntern(), | |
| 950 | .storage = .{ .elems = field_vals }, | |
| 951 | } })).toValue(); | |
| 952 | }, | |
| 953 | .Packed => { | |
| 954 | const byte_count = (@as(usize, @intCast(ty.bitSize(mod))) + 7) / 8; | |
| 955 | return readFromPackedMemory(ty, mod, buffer[0..byte_count], 0, arena); | |
| 956 | }, | |
| 957 | } | |
| 948 | 958 | }, |
| 949 | 959 | .ErrorSet => { |
| 950 | 960 | // TODO revisit this when we have the concept of the error tag type |
| ... | ... | @@ -992,6 +1002,7 @@ pub const Value = struct { |
| 992 | 1002 | bit_offset: usize, |
| 993 | 1003 | arena: Allocator, |
| 994 | 1004 | ) Allocator.Error!Value { |
| 1005 | const ip = &mod.intern_pool; | |
| 995 | 1006 | const target = mod.getTarget(); |
| 996 | 1007 | const endian = target.cpu.arch.endian(); |
| 997 | 1008 | switch (ty.zigTypeTag(mod)) { |
| ... | ... | @@ -1070,23 +1081,22 @@ pub const Value = struct { |
| 1070 | 1081 | .storage = .{ .elems = elems }, |
| 1071 | 1082 | } })).toValue(); |
| 1072 | 1083 | }, |
| 1073 | .Struct => switch (ty.containerLayout(mod)) { | |
| 1074 | .Auto => unreachable, // Sema is supposed to have emitted a compile error already | |
| 1075 | .Extern => unreachable, // Handled by non-packed readFromMemory | |
| 1076 | .Packed => { | |
| 1077 | var bits: u16 = 0; | |
| 1078 | const fields = ty.structFields(mod).values(); | |
| 1079 | const field_vals = try arena.alloc(InternPool.Index, fields.len); | |
| 1080 | for (fields, 0..) |field, i| { | |
| 1081 | const field_bits = @as(u16, @intCast(field.ty.bitSize(mod))); | |
| 1082 | field_vals[i] = try (try readFromPackedMemory(field.ty, mod, buffer, bit_offset + bits, arena)).intern(field.ty, mod); | |
| 1083 | bits += field_bits; | |
| 1084 | } | |
| 1085 | return (try mod.intern(.{ .aggregate = .{ | |
| 1086 | .ty = ty.toIntern(), | |
| 1087 | .storage = .{ .elems = field_vals }, | |
| 1088 | } })).toValue(); | |
| 1089 | }, | |
| 1084 | .Struct => { | |
| 1085 | // Sema is supposed to have emitted a compile error already for Auto layout structs, | |
| 1086 | // and Extern is handled by non-packed readFromMemory. | |
| 1087 | const struct_type = mod.typeToPackedStruct(ty).?; | |
| 1088 | var bits: u16 = 0; | |
| 1089 | const field_vals = try arena.alloc(InternPool.Index, struct_type.field_types.len); | |
| 1090 | for (field_vals, 0..) |*field_val, i| { | |
| 1091 | const field_ty = struct_type.field_types.get(ip)[i].toType(); | |
| 1092 | const field_bits: u16 = @intCast(field_ty.bitSize(mod)); | |
| 1093 | field_val.* = try (try readFromPackedMemory(field_ty, mod, buffer, bit_offset + bits, arena)).intern(field_ty, mod); | |
| 1094 | bits += field_bits; | |
| 1095 | } | |
| 1096 | return (try mod.intern(.{ .aggregate = .{ | |
| 1097 | .ty = ty.toIntern(), | |
| 1098 | .storage = .{ .elems = field_vals }, | |
| 1099 | } })).toValue(); | |
| 1090 | 1100 | }, |
| 1091 | 1101 | .Pointer => { |
| 1092 | 1102 | assert(!ty.isSlice(mod)); // No well defined layout. |
| ... | ... | @@ -1105,18 +1115,18 @@ pub const Value = struct { |
| 1105 | 1115 | pub fn toFloat(val: Value, comptime T: type, mod: *Module) T { |
| 1106 | 1116 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 1107 | 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 | 1119 | inline .u64, .i64 => |x| { |
| 1110 | 1120 | if (T == f80) { |
| 1111 | 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))), | |
| 1116 | .lazy_size => |ty| @as(T, @floatFromInt(ty.toType().abiSize(mod))), | |
| 1125 | .lazy_align => |ty| @floatFromInt(ty.toType().abiAlignment(mod).toByteUnits(0)), | |
| 1126 | .lazy_size => |ty| @floatFromInt(ty.toType().abiSize(mod)), | |
| 1117 | 1127 | }, |
| 1118 | 1128 | .float => |float| switch (float.storage) { |
| 1119 | inline else => |x| @as(T, @floatCast(x)), | |
| 1129 | inline else => |x| @floatCast(x), | |
| 1120 | 1130 | }, |
| 1121 | 1131 | else => unreachable, |
| 1122 | 1132 | }; |
| ... | ... | @@ -1255,7 +1265,8 @@ pub const Value = struct { |
| 1255 | 1265 | .int => |int| switch (int.storage) { |
| 1256 | 1266 | .big_int => |big_int| big_int.orderAgainstScalar(0), |
| 1257 | 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 | 1270 | mod, |
| 1260 | 1271 | false, |
| 1261 | 1272 | if (opt_sema) |sema| .{ .sema = sema } else .eager, |
| ... | ... | @@ -1510,33 +1521,38 @@ pub const Value = struct { |
| 1510 | 1521 | /// Asserts the value is a single-item pointer to an array, or an array, |
| 1511 | 1522 | /// or an unknown-length pointer, and returns the element value at the index. |
| 1512 | 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 | 1529 | return switch (val.ip_index) { |
| 1514 | 1530 | .none => switch (val.tag()) { |
| 1515 | 1531 | .bytes => try mod.intValue(Type.u8, val.castTag(.bytes).?.data[index]), |
| 1516 | 1532 | .repeated => val.castTag(.repeated).?.data, |
| 1517 | 1533 | .aggregate => val.castTag(.aggregate).?.data[index], |
| 1518 | .slice => val.castTag(.slice).?.data.ptr.elemValue(mod, index), | |
| 1519 | else => unreachable, | |
| 1534 | .slice => val.castTag(.slice).?.data.ptr.maybeElemValue(mod, index), | |
| 1535 | else => null, | |
| 1520 | 1536 | }, |
| 1521 | 1537 | else => switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 1522 | 1538 | .undef => |ty| (try mod.intern(.{ |
| 1523 | 1539 | .undef = ty.toType().elemType2(mod).toIntern(), |
| 1524 | 1540 | })).toValue(), |
| 1525 | 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 | 1543 | .mut_decl => |mut_decl| (try mod.declPtr(mut_decl.decl).internValue(mod)) |
| 1528 | .toValue().elemValue(mod, index), | |
| 1529 | .int, .eu_payload => unreachable, | |
| 1530 | .opt_payload => |base| base.toValue().elemValue(mod, index), | |
| 1531 | .comptime_field => |field_val| field_val.toValue().elemValue(mod, index), | |
| 1532 | .elem => |elem| elem.base.toValue().elemValue(mod, index + @as(usize, @intCast(elem.index))), | |
| 1544 | .toValue().maybeElemValue(mod, index), | |
| 1545 | .int, .eu_payload => null, | |
| 1546 | .opt_payload => |base| base.toValue().maybeElemValue(mod, index), | |
| 1547 | .comptime_field => |field_val| field_val.toValue().maybeElemValue(mod, index), | |
| 1548 | .elem => |elem| elem.base.toValue().maybeElemValue(mod, index + @as(usize, @intCast(elem.index))), | |
| 1533 | 1549 | .field => |field| if (field.base.toValue().pointerDecl(mod)) |decl_index| { |
| 1534 | 1550 | const base_decl = mod.declPtr(decl_index); |
| 1535 | 1551 | const field_val = try base_decl.val.fieldValue(mod, @as(usize, @intCast(field.index))); |
| 1536 | return field_val.elemValue(mod, index); | |
| 1537 | } else unreachable, | |
| 1552 | return field_val.maybeElemValue(mod, index); | |
| 1553 | } else null, | |
| 1538 | 1554 | }, |
| 1539 | .opt => |opt| opt.val.toValue().elemValue(mod, index), | |
| 1555 | .opt => |opt| opt.val.toValue().maybeElemValue(mod, index), | |
| 1540 | 1556 | .aggregate => |aggregate| { |
| 1541 | 1557 | const len = mod.intern_pool.aggregateTypeLen(aggregate.ty); |
| 1542 | 1558 | if (index < len) return switch (aggregate.storage) { |
| ... | ... | @@ -1550,7 +1566,7 @@ pub const Value = struct { |
| 1550 | 1566 | assert(index == len); |
| 1551 | 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 | 1891 | }, |
| 1876 | 1892 | inline .u64, .i64 => |x| floatFromIntInner(x, float_ty, mod), |
| 1877 | 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 | 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 | 1898 | .lazy_size => |ty| if (opt_sema) |sema| { |
| 1883 | 1899 | return floatFromIntInner((try ty.toType().abiSizeAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod); |
| ... | ... | @@ -1892,11 +1908,11 @@ pub const Value = struct { |
| 1892 | 1908 | fn floatFromIntInner(x: anytype, dest_ty: Type, mod: *Module) !Value { |
| 1893 | 1909 | const target = mod.getTarget(); |
| 1894 | 1910 | const storage: InternPool.Key.Float.Storage = switch (dest_ty.floatBits(target)) { |
| 1895 | 16 => .{ .f16 = @as(f16, @floatFromInt(x)) }, | |
| 1896 | 32 => .{ .f32 = @as(f32, @floatFromInt(x)) }, | |
| 1897 | 64 => .{ .f64 = @as(f64, @floatFromInt(x)) }, | |
| 1898 | 80 => .{ .f80 = @as(f80, @floatFromInt(x)) }, | |
| 1899 | 128 => .{ .f128 = @as(f128, @floatFromInt(x)) }, | |
| 1911 | 16 => .{ .f16 = @floatFromInt(x) }, | |
| 1912 | 32 => .{ .f32 = @floatFromInt(x) }, | |
| 1913 | 64 => .{ .f64 = @floatFromInt(x) }, | |
| 1914 | 80 => .{ .f80 = @floatFromInt(x) }, | |
| 1915 | 128 => .{ .f128 = @floatFromInt(x) }, | |
| 1900 | 1916 | else => unreachable, |
| 1901 | 1917 | }; |
| 1902 | 1918 | return (try mod.intern(.{ .float = .{ |
test/behavior/align.zig+55| ... | ... | @@ -619,3 +619,58 @@ test "sub-aligned pointer field access" { |
| 619 | 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 | 18 | } |
| 19 | 19 | |
| 20 | 20 | test "comparison of @alignOf(T) against zero" { |
| 21 | { | |
| 22 | const T = struct { x: u32 }; | |
| 23 | try expect(!(@alignOf(T) == 0)); | |
| 24 | try expect(@alignOf(T) != 0); | |
| 25 | try expect(!(@alignOf(T) < 0)); | |
| 26 | try expect(!(@alignOf(T) <= 0)); | |
| 27 | try expect(@alignOf(T) > 0); | |
| 28 | try expect(@alignOf(T) >= 0); | |
| 29 | } | |
| 30 | { | |
| 31 | const T = struct {}; | |
| 32 | try expect(@alignOf(T) == 0); | |
| 33 | try expect(!(@alignOf(T) != 0)); | |
| 34 | try expect(!(@alignOf(T) < 0)); | |
| 35 | try expect(@alignOf(T) <= 0); | |
| 36 | try expect(!(@alignOf(T) > 0)); | |
| 37 | try expect(@alignOf(T) >= 0); | |
| 38 | } | |
| 21 | const T = struct { x: u32 }; | |
| 22 | try expect(!(@alignOf(T) == 0)); | |
| 23 | try expect(@alignOf(T) != 0); | |
| 24 | try expect(!(@alignOf(T) < 0)); | |
| 25 | try expect(!(@alignOf(T) <= 0)); | |
| 26 | try expect(@alignOf(T) > 0); | |
| 27 | try expect(@alignOf(T) >= 0); | |
| 39 | 28 | } |
| 40 | 29 | |
| 41 | 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 | 37 | test "empty union" { |
| 38 | 38 | const U = union {}; |
| 39 | 39 | try expect(@sizeOf(U) == 0); |
| 40 | try expect(@alignOf(U) == 0); | |
| 40 | try expect(@alignOf(U) == 1); | |
| 41 | 41 | } |
| 42 | 42 | |
| 43 | 43 | test "empty extern union" { |