| author | |
| committer | |
| log | b19074d252e7eb833b653263acd20e64a7fe26ff |
| tree | cec720566242209acffeb94f5afff3ad582fee14 |
| parent | 911294116d5df0db3b431f9117f42bf8074a3b83 |
| signature |
Now that https://github.com/ziglang/zig/issues/24657 has been
implemented, the compiler can simplify its internal representation of
comptime-known `packed struct` and `packed union` values. Instead of
storing them field-wise, we can simply store their backing integer
value. This simplifies many operations and improves efficiency in some
cases.19 files changed, 530 insertions(+), 501 deletions(-)
src/Air/print.zig+17-27| ... | ... | @@ -692,33 +692,23 @@ const Writer = struct { |
| 692 | 692 | |
| 693 | 693 | const zcu = w.pt.zcu; |
| 694 | 694 | const ip = &zcu.intern_pool; |
| 695 | const aggregate = ip.indexToKey(unwrapped_asm.clobbers).aggregate; | |
| 696 | const struct_type: Type = .fromInterned(aggregate.ty); | |
| 697 | switch (aggregate.storage) { | |
| 698 | .elems => |elems| for (elems, 0..) |elem, i| { | |
| 699 | switch (elem) { | |
| 700 | .bool_true => { | |
| 701 | const clobber = struct_type.structFieldName(i, zcu).toSlice(ip).?; | |
| 702 | assert(clobber.len != 0); | |
| 703 | try s.writeAll(", ~{"); | |
| 704 | try s.writeAll(clobber); | |
| 705 | try s.writeAll("}"); | |
| 706 | }, | |
| 707 | .bool_false => continue, | |
| 708 | else => unreachable, | |
| 709 | } | |
| 710 | }, | |
| 711 | .repeated_elem => |elem| { | |
| 712 | try s.writeAll(", "); | |
| 713 | try s.writeAll(switch (elem) { | |
| 714 | .bool_true => "<all clobbers>", | |
| 715 | .bool_false => "<no clobbers>", | |
| 716 | else => unreachable, | |
| 717 | }); | |
| 718 | }, | |
| 719 | .bytes => |bytes| { | |
| 720 | try s.print(", {x}", .{bytes}); | |
| 721 | }, | |
| 695 | const clobbers_val: Value = .fromInterned(unwrapped_asm.clobbers); | |
| 696 | const clobbers_ty = clobbers_val.typeOf(zcu); | |
| 697 | var clobbers_bigint_buf: Value.BigIntSpace = undefined; | |
| 698 | const clobbers_bigint = clobbers_val.toBigInt(&clobbers_bigint_buf, zcu); | |
| 699 | for (0..clobbers_ty.structFieldCount(zcu)) |field_index| { | |
| 700 | assert(clobbers_ty.fieldType(field_index, zcu).toIntern() == .bool_type); | |
| 701 | const limb_bits = @bitSizeOf(std.math.big.Limb); | |
| 702 | if (field_index / limb_bits >= clobbers_bigint.limbs.len) continue; // field is false | |
| 703 | switch (@as(u1, @truncate(clobbers_bigint.limbs[field_index / limb_bits] >> @intCast(field_index % limb_bits)))) { | |
| 704 | 0 => continue, // field is false | |
| 705 | 1 => {}, // field is true | |
| 706 | } | |
| 707 | const clobber = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?; | |
| 708 | assert(clobber.len != 0); | |
| 709 | try s.writeAll(", ~{"); | |
| 710 | try s.writeAll(clobber); | |
| 711 | try s.writeAll("}"); | |
| 722 | 712 | } |
| 723 | 713 | const asm_source = unwrapped_asm.source; |
| 724 | 714 | try s.print(", \"{f}\"", .{std.zig.fmtString(asm_source)}); |
src/InternPool.zig+52-11| ... | ... | @@ -2130,6 +2130,8 @@ pub const Key = union(enum) { |
| 2130 | 2130 | aggregate: Aggregate, |
| 2131 | 2131 | /// An instance of a union. |
| 2132 | 2132 | un: Union, |
| 2133 | /// An instance of a `packed struct` or `packed union`. | |
| 2134 | bitpack: Bitpack, | |
| 2133 | 2135 | |
| 2134 | 2136 | /// A comptime function call with a memoized result. |
| 2135 | 2137 | memoized_call: Key.MemoizedCall, |
| ... | ... | @@ -2681,6 +2683,15 @@ pub const Key = union(enum) { |
| 2681 | 2683 | }; |
| 2682 | 2684 | }; |
| 2683 | 2685 | |
| 2686 | /// As well as a key, this type doubles as the payload in `extra` for `Tag.bitpack`. | |
| 2687 | pub const Bitpack = struct { | |
| 2688 | /// The `packed struct` or `packed union` type. | |
| 2689 | ty: Index, | |
| 2690 | /// The contents of the bitpack, represented as the backing integer value. The type of this | |
| 2691 | /// value is the same as the backing integer type of `ty`. | |
| 2692 | backing_int_val: Index, | |
| 2693 | }; | |
| 2694 | ||
| 2684 | 2695 | pub const MemoizedCall = struct { |
| 2685 | 2696 | func: Index, |
| 2686 | 2697 | arg_values: []const Index, |
| ... | ... | @@ -2919,6 +2930,8 @@ pub const Key = union(enum) { |
| 2919 | 2930 | asBytes(&e.relocation) ++ |
| 2920 | 2931 | asBytes(&e.is_const) ++ asBytes(&e.alignment) ++ asBytes(&e.@"addrspace") ++ |
| 2921 | 2932 | asBytes(&e.zir_index) ++ &[1]u8{@intFromEnum(e.source)}), |
| 2933 | ||
| 2934 | .bitpack => |bitpack| Hash.hash(seed, asBytes(&bitpack.ty) ++ asBytes(&bitpack.backing_int_val)), | |
| 2922 | 2935 | }; |
| 2923 | 2936 | } |
| 2924 | 2937 | |
| ... | ... | @@ -2996,6 +3009,10 @@ pub const Key = union(enum) { |
| 2996 | 3009 | const b_info = b.empty_enum_value; |
| 2997 | 3010 | return a_info == b_info; |
| 2998 | 3011 | }, |
| 3012 | .bitpack => |a_info| { | |
| 3013 | const b_info = b.bitpack; | |
| 3014 | return a_info.ty == b_info.ty and a_info.backing_int_val == b_info.backing_int_val; | |
| 3015 | }, | |
| 2999 | 3016 | |
| 3000 | 3017 | .variable => |a_info| { |
| 3001 | 3018 | const b_info = b.variable; |
| ... | ... | @@ -3271,6 +3288,7 @@ pub const Key = union(enum) { |
| 3271 | 3288 | .enum_tag, |
| 3272 | 3289 | .aggregate, |
| 3273 | 3290 | .un, |
| 3291 | .bitpack, | |
| 3274 | 3292 | => |x| x.ty, |
| 3275 | 3293 | |
| 3276 | 3294 | .enum_literal => .enum_literal_type, |
| ... | ... | @@ -4417,6 +4435,7 @@ pub const Index = enum(u32) { |
| 4417 | 4435 | trailing: struct { element_values: []Index }, |
| 4418 | 4436 | }, |
| 4419 | 4437 | repeated: struct { data: *Repeated }, |
| 4438 | bitpack: struct { data: *Key.Bitpack }, | |
| 4420 | 4439 | |
| 4421 | 4440 | memoized_call: struct { |
| 4422 | 4441 | const @"data.args_len" = opaque {}; |
| ... | ... | @@ -5152,6 +5171,9 @@ pub const Tag = enum(u8) { |
| 5152 | 5171 | /// An instance of an array or vector with every element being the same value. |
| 5153 | 5172 | /// data is extra index to `Repeated`. |
| 5154 | 5173 | repeated, |
| 5174 | /// An instance of a `packed struct` or `packed union`. | |
| 5175 | /// data is extra index to `Key.Bitpack`. | |
| 5176 | bitpack, | |
| 5155 | 5177 | |
| 5156 | 5178 | /// A memoized comptime function call result. |
| 5157 | 5179 | /// data is extra index to `MemoizedCall` |
| ... | ... | @@ -5485,6 +5507,7 @@ pub const Tag = enum(u8) { |
| 5485 | 5507 | .config = .{ .@"trailing.elements.len" = .@"payload.ty.payload.fields_len" }, |
| 5486 | 5508 | }, |
| 5487 | 5509 | .repeated = .{ .summary = .@"@as({.payload.ty%summary}, @splat({.payload.elem_val%summary}))", .payload = Repeated }, |
| 5510 | .bitpack = .{ .summary = .@"@as({.payload.ty%summary}, {})", .payload = Key.Bitpack }, | |
| 5488 | 5511 | |
| 5489 | 5512 | .memoized_call = .{ |
| 5490 | 5513 | .summary = .@"@memoize({.payload.func%summary})", |
| ... | ... | @@ -7043,6 +7066,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 7043 | 7066 | }, |
| 7044 | 7067 | .enum_literal => .{ .enum_literal = @enumFromInt(data) }, |
| 7045 | 7068 | .enum_tag => .{ .enum_tag = extraData(unwrapped_index.getExtra(ip), Tag.EnumTag, data) }, |
| 7069 | .bitpack => .{ .bitpack = extraData(unwrapped_index.getExtra(ip), Key.Bitpack, data) }, | |
| 7046 | 7070 | |
| 7047 | 7071 | .memoized_call => { |
| 7048 | 7072 | const extra_list = unwrapped_index.getExtra(ip); |
| ... | ... | @@ -7938,15 +7962,14 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key: |
| 7938 | 7962 | .aggregate => |aggregate| { |
| 7939 | 7963 | const ty_key = ip.indexToKey(aggregate.ty); |
| 7940 | 7964 | const len = ip.aggregateTypeLen(aggregate.ty); |
| 7941 | const child = switch (ty_key) { | |
| 7942 | .array_type => |array_type| array_type.child, | |
| 7943 | .vector_type => |vector_type| vector_type.child, | |
| 7944 | .tuple_type, .struct_type => .none, | |
| 7945 | else => unreachable, | |
| 7946 | }; | |
| 7947 | const sentinel = switch (ty_key) { | |
| 7948 | .array_type => |array_type| array_type.sentinel, | |
| 7949 | .vector_type, .tuple_type, .struct_type => .none, | |
| 7965 | const child: Index, const sentinel: Index = switch (ty_key) { | |
| 7966 | .array_type => |array_type| .{ array_type.child, array_type.sentinel }, | |
| 7967 | .vector_type => |vector_type| .{ vector_type.child, .none }, | |
| 7968 | .tuple_type => .{ .none, .none }, | |
| 7969 | .struct_type => child: { | |
| 7970 | assert(ip.loadStructType(aggregate.ty).layout != .@"packed"); | |
| 7971 | break :child .{ .none, .none }; | |
| 7972 | }, | |
| 7950 | 7973 | else => unreachable, |
| 7951 | 7974 | }; |
| 7952 | 7975 | const len_including_sentinel = len + @intFromBool(sentinel != .none); |
| ... | ... | @@ -8128,6 +8151,18 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key: |
| 8128 | 8151 | extra.appendSliceAssumeCapacity(.{@ptrCast(aggregate.storage.elems)}); |
| 8129 | 8152 | if (sentinel != .none) extra.appendAssumeCapacity(.{@intFromEnum(sentinel)}); |
| 8130 | 8153 | }, |
| 8154 | .bitpack => |bitpack| { | |
| 8155 | switch (ip.zigTypeTag(bitpack.ty)) { | |
| 8156 | .@"struct" => assert(ip.typeOf(bitpack.backing_int_val) == ip.loadStructType(bitpack.ty).packed_backing_int_type), | |
| 8157 | .@"union" => assert(ip.typeOf(bitpack.backing_int_val) == ip.loadUnionType(bitpack.ty).packed_backing_int_type), | |
| 8158 | else => unreachable, | |
| 8159 | } | |
| 8160 | assert(!ip.isUndef(bitpack.backing_int_val)); | |
| 8161 | items.appendAssumeCapacity(.{ | |
| 8162 | .tag = .bitpack, | |
| 8163 | .data = try addExtra(extra, bitpack), | |
| 8164 | }); | |
| 8165 | }, | |
| 8131 | 8166 | |
| 8132 | 8167 | .memoized_call => |memoized_call| { |
| 8133 | 8168 | for (memoized_call.arg_values) |arg| assert(arg != .none); |
| ... | ... | @@ -9095,6 +9130,10 @@ pub fn getUnion( |
| 9095 | 9130 | tid: Zcu.PerThread.Id, |
| 9096 | 9131 | un: Key.Union, |
| 9097 | 9132 | ) Allocator.Error!Index { |
| 9133 | assert(un.ty != .none); | |
| 9134 | assert(un.val != .none); | |
| 9135 | assert(ip.loadUnionType(un.ty).layout != .@"packed"); | |
| 9136 | ||
| 9098 | 9137 | var gop = try ip.getOrPutKey(gpa, io, tid, .{ .un = un }); |
| 9099 | 9138 | defer gop.deinit(); |
| 9100 | 9139 | if (gop == .existing) return gop.existing; |
| ... | ... | @@ -9103,8 +9142,6 @@ pub fn getUnion( |
| 9103 | 9142 | const extra = local.getMutableExtra(gpa, io); |
| 9104 | 9143 | try items.ensureUnusedCapacity(1); |
| 9105 | 9144 | |
| 9106 | assert(un.ty != .none); | |
| 9107 | assert(un.val != .none); | |
| 9108 | 9145 | items.appendAssumeCapacity(.{ |
| 9109 | 9146 | .tag = .union_value, |
| 9110 | 9147 | .data = try addExtra(extra, un), |
| ... | ... | @@ -11003,6 +11040,7 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo |
| 11003 | 11040 | .func_coerced => @sizeOf(Tag.FuncCoerced), |
| 11004 | 11041 | .only_possible_value => 0, |
| 11005 | 11042 | .union_value => @sizeOf(Key.Union), |
| 11043 | .bitpack => 2 * @sizeOf(u32), | |
| 11006 | 11044 | |
| 11007 | 11045 | .memoized_call => b: { |
| 11008 | 11046 | const info = extraData(extra_list, MemoizedCall, data); |
| ... | ... | @@ -11117,6 +11155,7 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void { |
| 11117 | 11155 | .func_instance, |
| 11118 | 11156 | .func_coerced, |
| 11119 | 11157 | .union_value, |
| 11158 | .bitpack, | |
| 11120 | 11159 | .memoized_call, |
| 11121 | 11160 | => try w.print("{d}", .{data}), |
| 11122 | 11161 | |
| ... | ... | @@ -11871,6 +11910,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index { |
| 11871 | 11910 | .bytes, |
| 11872 | 11911 | .aggregate, |
| 11873 | 11912 | .repeated, |
| 11913 | .bitpack, | |
| 11874 | 11914 | => |t| { |
| 11875 | 11915 | const extra_list = unwrapped_index.getExtra(ip); |
| 11876 | 11916 | return @enumFromInt(extra_list.view().items(.@"0")[item.data + std.meta.fieldIndex(t.Payload(), "ty").?]); |
| ... | ... | @@ -12264,6 +12304,7 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId { |
| 12264 | 12304 | .bytes, |
| 12265 | 12305 | .aggregate, |
| 12266 | 12306 | .repeated, |
| 12307 | .bitpack, | |
| 12267 | 12308 | // memoization, not types |
| 12268 | 12309 | .memoized_call, |
| 12269 | 12310 | => unreachable, |
src/Sema.zig+39-11| ... | ... | @@ -3583,7 +3583,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref, |
| 3583 | 3583 | }, |
| 3584 | 3584 | .field => |idx| ptr: { |
| 3585 | 3585 | const maybe_union_ty = Value.fromInterned(decl_parent_ptr).typeOf(zcu).childType(zcu); |
| 3586 | if (zcu.typeToUnion(maybe_union_ty)) |union_obj| { | |
| 3586 | if (zcu.typeToUnion(maybe_union_ty)) |union_obj| if (union_obj.layout == .auto) { | |
| 3587 | 3587 | // As this is a union field, we must store to the pointer now to set the tag. |
| 3588 | 3588 | // The payload value will be stored later, so undef is a sufficent payload for now. |
| 3589 | 3589 | const payload_ty: Type = .fromInterned(union_obj.field_types.get(&zcu.intern_pool)[idx]); |
| ... | ... | @@ -3591,7 +3591,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref, |
| 3591 | 3591 | const tag_val = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_type), idx); |
| 3592 | 3592 | const store_val = try pt.unionValue(maybe_union_ty, tag_val, payload_val); |
| 3593 | 3593 | try sema.storePtrVal(block, .unneeded, .fromInterned(decl_parent_ptr), store_val, maybe_union_ty); |
| 3594 | } | |
| 3594 | }; | |
| 3595 | 3595 | break :ptr (try Value.fromInterned(decl_parent_ptr).ptrField(idx, pt)).toIntern(); |
| 3596 | 3596 | }, |
| 3597 | 3597 | .elem => |idx| (try Value.fromInterned(decl_parent_ptr).ptrElem(idx, pt)).toIntern(), |
| ... | ... | @@ -18510,6 +18510,10 @@ fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 18510 | 18510 | |
| 18511 | 18511 | const payload = try sema.coerce(block, field_ty, sema.resolveInst(extra.init), payload_src); |
| 18512 | 18512 | |
| 18513 | if (union_ty.containerLayout(zcu) == .@"packed") { | |
| 18514 | return sema.bitCast(block, union_ty, payload, block.nodeOffset(inst_data.src_node), payload_src); | |
| 18515 | } | |
| 18516 | ||
| 18513 | 18517 | if (sema.resolveValue(payload)) |payload_val| { |
| 18514 | 18518 | const tag_ty = union_ty.unionTagTypeHypothetical(zcu); |
| 18515 | 18519 | const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index); |
| ... | ... | @@ -18643,6 +18647,10 @@ fn zirStructInit( |
| 18643 | 18647 | const uncoerced_init_inst = sema.resolveInst(item.data.init); |
| 18644 | 18648 | const init_inst = try sema.coerce(block, field_ty, uncoerced_init_inst, field_src); |
| 18645 | 18649 | |
| 18650 | if (resolved_ty.containerLayout(zcu) == .@"packed") { | |
| 18651 | return sema.bitCast(block, resolved_ty, init_inst, src, field_src); | |
| 18652 | } | |
| 18653 | ||
| 18646 | 18654 | if (sema.resolveValue(init_inst)) |val| { |
| 18647 | 18655 | const struct_val = Value.fromInterned(try pt.internUnion(.{ |
| 18648 | 18656 | .ty = resolved_ty.toIntern(), |
| ... | ... | @@ -18789,15 +18797,35 @@ fn finishStructInit( |
| 18789 | 18797 | } |
| 18790 | 18798 | } else null; |
| 18791 | 18799 | |
| 18792 | const runtime_index = opt_runtime_index orelse { | |
| 18793 | const elems = try sema.arena.alloc(InternPool.Index, field_inits.len); | |
| 18794 | for (elems, field_inits) |*elem, field_init| { | |
| 18795 | elem.* = sema.resolveValue(field_init).?.toIntern(); | |
| 18796 | } | |
| 18797 | const struct_val = try pt.aggregateValue(struct_ty, elems); | |
| 18798 | const final_val_inst = try sema.coerce(block, result_ty, Air.internedToRef(struct_val.toIntern()), init_src); | |
| 18799 | const final_val = sema.resolveValue(final_val_inst).?; | |
| 18800 | return sema.addConstantMaybeRef(final_val.toIntern(), is_ref); | |
| 18800 | const runtime_index = opt_runtime_index orelse switch (struct_ty.containerLayout(zcu)) { | |
| 18801 | .auto, .@"extern" => { | |
| 18802 | const elems = try sema.arena.alloc(InternPool.Index, field_inits.len); | |
| 18803 | for (elems, field_inits) |*elem, field_init| { | |
| 18804 | elem.* = sema.resolveValue(field_init).?.toIntern(); | |
| 18805 | } | |
| 18806 | const struct_val = try pt.aggregateValue(struct_ty, elems); | |
| 18807 | const final_val_ref = try sema.coerce(block, result_ty, .fromValue(struct_val), init_src); | |
| 18808 | return sema.addConstantMaybeRef(final_val_ref.toInterned().?, is_ref); | |
| 18809 | }, | |
| 18810 | .@"packed" => { | |
| 18811 | const buf = try sema.arena.alloc(u8, (struct_ty.bitSize(zcu) + 7) / 8); | |
| 18812 | var bit_offset: u16 = 0; | |
| 18813 | for (field_inits) |field_init| { | |
| 18814 | const field_val = sema.resolveValue(field_init).?; | |
| 18815 | field_val.writeToPackedMemory(pt, buf, bit_offset) catch |err| switch (err) { | |
| 18816 | error.ReinterpretDeclRef => unreachable, // bitpack fields cannot be pointers | |
| 18817 | error.OutOfMemory => |e| return e, | |
| 18818 | }; | |
| 18819 | bit_offset += @intCast(field_val.typeOf(zcu).bitSize(zcu)); | |
| 18820 | } | |
| 18821 | assert(bit_offset == struct_ty.bitSize(zcu)); | |
| 18822 | const struct_val = Value.readFromPackedMemory(struct_ty, pt, buf, 0, sema.arena) catch |err| switch (err) { | |
| 18823 | error.IllDefinedMemoryLayout => unreachable, // bitpacks have well-defined layout | |
| 18824 | error.OutOfMemory => |e| return e, | |
| 18825 | }; | |
| 18826 | const final_val_ref = try sema.coerce(block, result_ty, .fromValue(struct_val), init_src); | |
| 18827 | return sema.addConstantMaybeRef(final_val_ref.toInterned().?, is_ref); | |
| 18828 | }, | |
| 18801 | 18829 | }; |
| 18802 | 18830 | |
| 18803 | 18831 | if (struct_ty.comptimeOnly(zcu)) { |
src/Sema/bitcast.zig+87-84| ... | ... | @@ -273,6 +273,8 @@ const UnpackValueBits = struct { |
| 273 | 273 | .opt, |
| 274 | 274 | => try unpack.primitive(val), |
| 275 | 275 | |
| 276 | .bitpack => |bitpack| try unpack.primitive(.fromInterned(bitpack.backing_int_val)), | |
| 277 | ||
| 276 | 278 | .aggregate => switch (ty.zigTypeTag(zcu)) { |
| 277 | 279 | .vector => { |
| 278 | 280 | const len: usize = @intCast(ty.arrayLen(zcu)); |
| ... | ... | @@ -443,7 +445,7 @@ const UnpackValueBits = struct { |
| 443 | 445 | // This @intCast is okay because no primitive can exceed the size of a u16. |
| 444 | 446 | const int_ty = try unpack.pt.intType(.unsigned, @intCast(bit_count)); |
| 445 | 447 | const buf = try unpack.arena.alloc(u8, @intCast((val_bits + 7) / 8)); |
| 446 | try val.writeToPackedMemory(ty, unpack.pt, buf, 0); | |
| 448 | try val.writeToPackedMemory(unpack.pt, buf, 0); | |
| 447 | 449 | const sub_val = try Value.readFromPackedMemory(int_ty, unpack.pt, buf, @intCast(bit_offset), unpack.arena); |
| 448 | 450 | try unpack.primitive(sub_val); |
| 449 | 451 | }, |
| ... | ... | @@ -565,102 +567,103 @@ const PackValueBits = struct { |
| 565 | 567 | return pt.aggregateValue(ty, elems); |
| 566 | 568 | }, |
| 567 | 569 | .@"packed" => { |
| 568 | // All fields are in order with no padding. | |
| 569 | // This is identical between LE and BE targets. | |
| 570 | const elems = try arena.alloc(InternPool.Index, ty.structFieldCount(zcu)); | |
| 571 | for (elems, 0..) |*elem, i| { | |
| 572 | const field_ty = ty.fieldType(i, zcu); | |
| 573 | elem.* = (try pack.get(field_ty)).toIntern(); | |
| 574 | } | |
| 575 | return pt.aggregateValue(ty, elems); | |
| 570 | const backing_int_val = try pack.primitive(ty.bitpackBackingInt(zcu)); | |
| 571 | return pt.bitpackValue(ty, backing_int_val); | |
| 576 | 572 | }, |
| 577 | 573 | }, |
| 578 | .@"union" => { | |
| 579 | // We will attempt to read as the backing representation. If this emits | |
| 580 | // `error.ReinterpretDeclRef`, we will try each union field, preferring larger ones. | |
| 581 | // We will also attempt smaller fields when we get `undefined`, as if some bits are | |
| 582 | // defined we want to include them. | |
| 583 | // TODO: this is very very bad. We need a more sophisticated union representation. | |
| 584 | ||
| 585 | const prev_unpacked = pack.unpacked; | |
| 586 | const prev_bit_offset = pack.bit_offset; | |
| 587 | ||
| 588 | const backing_ty = try ty.unionBackingType(pt); | |
| 589 | ||
| 590 | backing: { | |
| 591 | const backing_val = pack.get(backing_ty) catch |err| switch (err) { | |
| 592 | error.ReinterpretDeclRef => { | |
| 574 | .@"union" => switch (ty.containerLayout(zcu)) { | |
| 575 | .auto => unreachable, // ill-defined layout | |
| 576 | .@"extern" => { | |
| 577 | // We will attempt to read as the backing representation. If this emits | |
| 578 | // `error.ReinterpretDeclRef`, we will try each union field, preferring larger ones. | |
| 579 | // We will also attempt smaller fields when we get `undefined`, as if some bits are | |
| 580 | // defined we want to include them. | |
| 581 | // TODO: this is very very bad. We need a more sophisticated union representation. | |
| 582 | ||
| 583 | const prev_unpacked = pack.unpacked; | |
| 584 | const prev_bit_offset = pack.bit_offset; | |
| 585 | ||
| 586 | const backing_ty = try ty.externUnionBackingType(pt); | |
| 587 | ||
| 588 | backing: { | |
| 589 | const backing_val = pack.get(backing_ty) catch |err| switch (err) { | |
| 590 | error.ReinterpretDeclRef => { | |
| 591 | pack.unpacked = prev_unpacked; | |
| 592 | pack.bit_offset = prev_bit_offset; | |
| 593 | break :backing; | |
| 594 | }, | |
| 595 | else => |e| return e, | |
| 596 | }; | |
| 597 | if (backing_val.isUndef(zcu)) { | |
| 593 | 598 | pack.unpacked = prev_unpacked; |
| 594 | 599 | pack.bit_offset = prev_bit_offset; |
| 595 | 600 | break :backing; |
| 596 | }, | |
| 597 | else => |e| return e, | |
| 598 | }; | |
| 599 | if (backing_val.isUndef(zcu)) { | |
| 600 | pack.unpacked = prev_unpacked; | |
| 601 | pack.bit_offset = prev_bit_offset; | |
| 602 | break :backing; | |
| 601 | } | |
| 602 | return Value.fromInterned(try pt.internUnion(.{ | |
| 603 | .ty = ty.toIntern(), | |
| 604 | .tag = .none, | |
| 605 | .val = backing_val.toIntern(), | |
| 606 | })); | |
| 603 | 607 | } |
| 604 | return Value.fromInterned(try pt.internUnion(.{ | |
| 605 | .ty = ty.toIntern(), | |
| 606 | .tag = .none, | |
| 607 | .val = backing_val.toIntern(), | |
| 608 | })); | |
| 609 | } | |
| 610 | 608 | |
| 611 | const field_order = try pack.arena.alloc(u32, ty.unionTagTypeHypothetical(zcu).enumFieldCount(zcu)); | |
| 612 | for (field_order, 0..) |*f, i| f.* = @intCast(i); | |
| 613 | // Sort `field_order` to put the fields with the largest bit sizes first. | |
| 614 | const SizeSortCtx = struct { | |
| 615 | zcu: *Zcu, | |
| 616 | field_types: []const InternPool.Index, | |
| 617 | fn lessThan(ctx: @This(), a_idx: u32, b_idx: u32) bool { | |
| 618 | const a_ty = Type.fromInterned(ctx.field_types[a_idx]); | |
| 619 | const b_ty = Type.fromInterned(ctx.field_types[b_idx]); | |
| 620 | return a_ty.bitSize(ctx.zcu) > b_ty.bitSize(ctx.zcu); | |
| 621 | } | |
| 622 | }; | |
| 623 | std.mem.sortUnstable(u32, field_order, SizeSortCtx{ | |
| 624 | .zcu = zcu, | |
| 625 | .field_types = zcu.typeToUnion(ty).?.field_types.get(ip), | |
| 626 | }, SizeSortCtx.lessThan); | |
| 627 | ||
| 628 | const padding_after = endian == .little or ty.containerLayout(zcu) == .@"packed"; | |
| 629 | ||
| 630 | for (field_order) |field_idx| { | |
| 631 | const field_ty = Type.fromInterned(zcu.typeToUnion(ty).?.field_types.get(ip)[field_idx]); | |
| 632 | const pad_bits = ty.bitSize(zcu) - field_ty.bitSize(zcu); | |
| 633 | if (!padding_after) try pack.padding(pad_bits); | |
| 634 | const field_val = pack.get(field_ty) catch |err| switch (err) { | |
| 635 | error.ReinterpretDeclRef => { | |
| 609 | const field_order = try pack.arena.alloc(u32, ty.unionTagTypeHypothetical(zcu).enumFieldCount(zcu)); | |
| 610 | for (field_order, 0..) |*f, i| f.* = @intCast(i); | |
| 611 | // Sort `field_order` to put the fields with the largest bit sizes first. | |
| 612 | const SizeSortCtx = struct { | |
| 613 | zcu: *Zcu, | |
| 614 | field_types: []const InternPool.Index, | |
| 615 | fn lessThan(ctx: @This(), a_idx: u32, b_idx: u32) bool { | |
| 616 | const a_ty = Type.fromInterned(ctx.field_types[a_idx]); | |
| 617 | const b_ty = Type.fromInterned(ctx.field_types[b_idx]); | |
| 618 | return a_ty.bitSize(ctx.zcu) > b_ty.bitSize(ctx.zcu); | |
| 619 | } | |
| 620 | }; | |
| 621 | std.mem.sortUnstable(u32, field_order, SizeSortCtx{ | |
| 622 | .zcu = zcu, | |
| 623 | .field_types = zcu.typeToUnion(ty).?.field_types.get(ip), | |
| 624 | }, SizeSortCtx.lessThan); | |
| 625 | ||
| 626 | const padding_after = endian == .little or ty.containerLayout(zcu) == .@"packed"; | |
| 627 | ||
| 628 | for (field_order) |field_idx| { | |
| 629 | const field_ty = Type.fromInterned(zcu.typeToUnion(ty).?.field_types.get(ip)[field_idx]); | |
| 630 | const pad_bits = ty.bitSize(zcu) - field_ty.bitSize(zcu); | |
| 631 | if (!padding_after) try pack.padding(pad_bits); | |
| 632 | const field_val = pack.get(field_ty) catch |err| switch (err) { | |
| 633 | error.ReinterpretDeclRef => { | |
| 634 | pack.unpacked = prev_unpacked; | |
| 635 | pack.bit_offset = prev_bit_offset; | |
| 636 | continue; | |
| 637 | }, | |
| 638 | else => |e| return e, | |
| 639 | }; | |
| 640 | if (padding_after) try pack.padding(pad_bits); | |
| 641 | if (field_val.isUndef(zcu)) { | |
| 636 | 642 | pack.unpacked = prev_unpacked; |
| 637 | 643 | pack.bit_offset = prev_bit_offset; |
| 638 | 644 | continue; |
| 639 | }, | |
| 640 | else => |e| return e, | |
| 641 | }; | |
| 642 | if (padding_after) try pack.padding(pad_bits); | |
| 643 | if (field_val.isUndef(zcu)) { | |
| 644 | pack.unpacked = prev_unpacked; | |
| 645 | pack.bit_offset = prev_bit_offset; | |
| 646 | continue; | |
| 645 | } | |
| 646 | const tag_val = try pt.enumValueFieldIndex(ty.unionTagTypeHypothetical(zcu), field_idx); | |
| 647 | return Value.fromInterned(try pt.internUnion(.{ | |
| 648 | .ty = ty.toIntern(), | |
| 649 | .tag = tag_val.toIntern(), | |
| 650 | .val = field_val.toIntern(), | |
| 651 | })); | |
| 647 | 652 | } |
| 648 | const tag_val = try pt.enumValueFieldIndex(ty.unionTagTypeHypothetical(zcu), field_idx); | |
| 653 | ||
| 654 | // No field could represent the value. Just do whatever happens when we try to read | |
| 655 | // the backing type - either `undefined` or `error.ReinterpretDeclRef`. | |
| 656 | const backing_val = try pack.get(backing_ty); | |
| 649 | 657 | return Value.fromInterned(try pt.internUnion(.{ |
| 650 | 658 | .ty = ty.toIntern(), |
| 651 | .tag = tag_val.toIntern(), | |
| 652 | .val = field_val.toIntern(), | |
| 659 | .tag = .none, | |
| 660 | .val = backing_val.toIntern(), | |
| 653 | 661 | })); |
| 654 | } | |
| 655 | ||
| 656 | // No field could represent the value. Just do whatever happens when we try to read | |
| 657 | // the backing type - either `undefined` or `error.ReinterpretDeclRef`. | |
| 658 | const backing_val = try pack.get(backing_ty); | |
| 659 | return Value.fromInterned(try pt.internUnion(.{ | |
| 660 | .ty = ty.toIntern(), | |
| 661 | .tag = .none, | |
| 662 | .val = backing_val.toIntern(), | |
| 663 | })); | |
| 662 | }, | |
| 663 | .@"packed" => { | |
| 664 | const backing_int_val = try pack.primitive(ty.bitpackBackingInt(zcu)); | |
| 665 | return pt.bitpackValue(ty, backing_int_val); | |
| 666 | }, | |
| 664 | 667 | }, |
| 665 | 668 | else => return pack.primitive(ty), |
| 666 | 669 | } |
| ... | ... | @@ -722,7 +725,7 @@ const PackValueBits = struct { |
| 722 | 725 | const val = Value.fromInterned(ip_val); |
| 723 | 726 | const ty = val.typeOf(zcu); |
| 724 | 727 | if (!val.isUndef(zcu)) { |
| 725 | try val.writeToPackedMemory(ty, pt, buf, cur_bit_off); | |
| 728 | try val.writeToPackedMemory(pt, buf, cur_bit_off); | |
| 726 | 729 | } |
| 727 | 730 | cur_bit_off += @intCast(ty.bitSize(zcu)); |
| 728 | 731 | } |
src/Sema/type_resolution.zig+1| ... | ... | @@ -79,6 +79,7 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type, src: LazySrcLoc) SemaError!vo |
| 79 | 79 | .opt, |
| 80 | 80 | .aggregate, |
| 81 | 81 | .un, |
| 82 | .bitpack, | |
| 82 | 83 | // memoization, not types |
| 83 | 84 | .memoized_call, |
| 84 | 85 | => unreachable, |
src/Type.zig+33-8| ... | ... | @@ -407,6 +407,7 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread, ctx: ?*Compari |
| 407 | 407 | .opt, |
| 408 | 408 | .aggregate, |
| 409 | 409 | .un, |
| 410 | .bitpack, | |
| 410 | 411 | // memoization, not types |
| 411 | 412 | .memoized_call, |
| 412 | 413 | => unreachable, |
| ... | ... | @@ -543,6 +544,7 @@ pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool { |
| 543 | 544 | .opt, |
| 544 | 545 | .aggregate, |
| 545 | 546 | .un, |
| 547 | .bitpack, | |
| 546 | 548 | // memoization, not types |
| 547 | 549 | .memoized_call, |
| 548 | 550 | => unreachable, |
| ... | ... | @@ -639,6 +641,7 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool { |
| 639 | 641 | .opt, |
| 640 | 642 | .aggregate, |
| 641 | 643 | .un, |
| 644 | .bitpack, | |
| 642 | 645 | // memoization, not types |
| 643 | 646 | .memoized_call, |
| 644 | 647 | => unreachable, |
| ... | ... | @@ -846,6 +849,7 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment { |
| 846 | 849 | .opt, |
| 847 | 850 | .aggregate, |
| 848 | 851 | .un, |
| 852 | .bitpack, | |
| 849 | 853 | // memoization, not types |
| 850 | 854 | .memoized_call, |
| 851 | 855 | => unreachable, |
| ... | ... | @@ -978,6 +982,7 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 { |
| 978 | 982 | .opt, |
| 979 | 983 | .aggregate, |
| 980 | 984 | .un, |
| 985 | .bitpack, | |
| 981 | 986 | // memoization, not types |
| 982 | 987 | .memoized_call, |
| 983 | 988 | => unreachable, |
| ... | ... | @@ -1102,6 +1107,7 @@ pub fn bitSize(ty: Type, zcu: *const Zcu) u64 { |
| 1102 | 1107 | .opt, |
| 1103 | 1108 | .aggregate, |
| 1104 | 1109 | .un, |
| 1110 | .bitpack, | |
| 1105 | 1111 | // memoization, not types |
| 1106 | 1112 | .memoized_call, |
| 1107 | 1113 | => unreachable, |
| ... | ... | @@ -1393,16 +1399,16 @@ pub fn unionHasAllZeroBitFieldTypes(ty: Type, zcu: *Zcu) bool { |
| 1393 | 1399 | } |
| 1394 | 1400 | |
| 1395 | 1401 | /// Returns the type used for backing storage of this union during comptime operations. |
| 1396 | /// Asserts the type is either an extern or packed union. | |
| 1397 | pub fn unionBackingType(ty: Type, pt: Zcu.PerThread) !Type { | |
| 1402 | /// Asserts the type is an extern union. | |
| 1403 | pub fn externUnionBackingType(ty: Type, pt: Zcu.PerThread) !Type { | |
| 1398 | 1404 | const zcu = pt.zcu; |
| 1399 | 1405 | assertHasLayout(ty, zcu); |
| 1400 | 1406 | const loaded_union = zcu.intern_pool.loadUnionType(ty.toIntern()); |
| 1401 | return switch (loaded_union.layout) { | |
| 1402 | .@"extern" => try pt.arrayType(.{ .len = ty.abiSize(zcu), .child = .u8_type }), | |
| 1403 | .@"packed" => .fromInterned(loaded_union.packed_backing_int_type), | |
| 1407 | switch (loaded_union.layout) { | |
| 1408 | .@"extern" => return pt.arrayType(.{ .len = ty.abiSize(zcu), .child = .u8_type }), | |
| 1409 | .@"packed" => unreachable, | |
| 1404 | 1410 | .auto => unreachable, |
| 1405 | }; | |
| 1411 | } | |
| 1406 | 1412 | } |
| 1407 | 1413 | |
| 1408 | 1414 | pub fn unionGetLayout(ty: Type, zcu: *const Zcu) Zcu.UnionLayout { |
| ... | ... | @@ -1421,6 +1427,15 @@ pub fn containerLayout(ty: Type, zcu: *const Zcu) std.builtin.Type.ContainerLayo |
| 1421 | 1427 | }; |
| 1422 | 1428 | } |
| 1423 | 1429 | |
| 1430 | pub fn bitpackBackingInt(ty: Type, zcu: *const Zcu) Type { | |
| 1431 | const ip = &zcu.intern_pool; | |
| 1432 | return switch (ip.indexToKey(ty.toIntern())) { | |
| 1433 | .struct_type => .fromInterned(ip.loadStructType(ty.toIntern()).packed_backing_int_type), | |
| 1434 | .union_type => .fromInterned(ip.loadUnionType(ty.toIntern()).packed_backing_int_type), | |
| 1435 | else => unreachable, | |
| 1436 | }; | |
| 1437 | } | |
| 1438 | ||
| 1424 | 1439 | /// Asserts that the type is an error union. |
| 1425 | 1440 | pub fn errorUnionPayload(ty: Type, zcu: *const Zcu) Type { |
| 1426 | 1441 | return Type.fromInterned(zcu.intern_pool.indexToKey(ty.toIntern()).error_union_type.payload_type); |
| ... | ... | @@ -1635,6 +1650,7 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType { |
| 1635 | 1650 | .opt, |
| 1636 | 1651 | .aggregate, |
| 1637 | 1652 | .un, |
| 1653 | .bitpack, | |
| 1638 | 1654 | // memoization, not types |
| 1639 | 1655 | .memoized_call, |
| 1640 | 1656 | => unreachable, |
| ... | ... | @@ -1842,7 +1858,7 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value { |
| 1842 | 1858 | if (struct_obj.layout == .@"packed") { |
| 1843 | 1859 | const backing_ty: Type = .fromInterned(struct_obj.packed_backing_int_type); |
| 1844 | 1860 | const backing_val = try backing_ty.onePossibleValue(pt) orelse return null; |
| 1845 | _ = backing_val; // MLUGG TODO: represent unions as their bits! | |
| 1861 | return try pt.bitpackValue(ty, backing_val); | |
| 1846 | 1862 | } else { |
| 1847 | 1863 | if (!struct_obj.has_one_possible_value) return null; |
| 1848 | 1864 | } |
| ... | ... | @@ -1893,8 +1909,13 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value { |
| 1893 | 1909 | }, |
| 1894 | 1910 | |
| 1895 | 1911 | .union_type => { |
| 1896 | // MLUGG TODO: is this nonsensical or what!!!!!! | |
| 1897 | 1912 | const union_obj = ip.loadUnionType(ty.toIntern()); |
| 1913 | if (union_obj.layout == .@"packed") { | |
| 1914 | const backing_ty: Type = .fromInterned(union_obj.packed_backing_int_type); | |
| 1915 | const backing_val = try backing_ty.onePossibleValue(pt) orelse return null; | |
| 1916 | return try pt.bitpackValue(ty, backing_val); | |
| 1917 | } | |
| 1918 | // MLUGG TODO: is this nonsensical or what!!!!!! | |
| 1898 | 1919 | const tag_val = (try Type.fromInterned(union_obj.enum_tag_type).onePossibleValue(pt)) orelse |
| 1899 | 1920 | return null; |
| 1900 | 1921 | if (union_obj.field_types.len == 0) { |
| ... | ... | @@ -1957,6 +1978,7 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value { |
| 1957 | 1978 | .opt, |
| 1958 | 1979 | .aggregate, |
| 1959 | 1980 | .un, |
| 1981 | .bitpack, | |
| 1960 | 1982 | // memoization, not types |
| 1961 | 1983 | .memoized_call, |
| 1962 | 1984 | => unreachable, |
| ... | ... | @@ -2061,6 +2083,7 @@ pub fn comptimeOnly(ty: Type, zcu: *const Zcu) bool { |
| 2061 | 2083 | .opt, |
| 2062 | 2084 | .aggregate, |
| 2063 | 2085 | .un, |
| 2086 | .bitpack, | |
| 2064 | 2087 | // memoization, not types |
| 2065 | 2088 | .memoized_call, |
| 2066 | 2089 | => unreachable, |
| ... | ... | @@ -3080,6 +3103,7 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void { |
| 3080 | 3103 | .opt, |
| 3081 | 3104 | .aggregate, |
| 3082 | 3105 | .un, |
| 3106 | .bitpack, | |
| 3083 | 3107 | .undef, |
| 3084 | 3108 | // memoization, not types |
| 3085 | 3109 | .memoized_call, |
| ... | ... | @@ -3158,6 +3182,7 @@ fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUn |
| 3158 | 3182 | .opt, |
| 3159 | 3183 | .aggregate, |
| 3160 | 3184 | .un, |
| 3185 | .bitpack, | |
| 3161 | 3186 | // memoization, not types |
| 3162 | 3187 | .memoized_call, |
| 3163 | 3188 | => unreachable, |
src/Value.zig+75-85| ... | ... | @@ -158,6 +158,7 @@ pub fn toBigInt(val: Value, space: *BigIntSpace, zcu: *Zcu) BigIntConst { |
| 158 | 158 | const ip = &zcu.intern_pool; |
| 159 | 159 | const int_key = switch (ip.indexToKey(val.toIntern())) { |
| 160 | 160 | .enum_tag => |enum_tag| ip.indexToKey(enum_tag.int).int, |
| 161 | .bitpack => |bitpack| ip.indexToKey(bitpack.backing_int_val).int, | |
| 161 | 162 | .int => |int| int, |
| 162 | 163 | else => unreachable, |
| 163 | 164 | }; |
| ... | ... | @@ -216,6 +217,7 @@ pub fn getUnsignedInt(val: Value, zcu: *const Zcu) ?u64 { |
| 216 | 217 | else => |payload| Value.fromInterned(payload).getUnsignedInt(zcu), |
| 217 | 218 | }, |
| 218 | 219 | .enum_tag => |enum_tag| Value.fromInterned(enum_tag.int).getUnsignedInt(zcu), |
| 220 | .bitpack => |bitpack| Value.fromInterned(bitpack.backing_int_val).getUnsignedInt(zcu), | |
| 219 | 221 | .err => |err| zcu.intern_pool.getErrorValueIfExists(err.name).?, |
| 220 | 222 | else => null, |
| 221 | 223 | }, |
| ... | ... | @@ -309,7 +311,7 @@ pub fn writeToMemory(val: Value, pt: Zcu.PerThread, buffer: []u8) error{ |
| 309 | 311 | // We use byte_count instead of abi_size here, so that any padding bytes |
| 310 | 312 | // follow the data bytes, on both big- and little-endian systems. |
| 311 | 313 | const byte_count = (@as(usize, @intCast(ty.bitSize(zcu))) + 7) / 8; |
| 312 | return writeToPackedMemory(val, ty, pt, buffer[0..byte_count], 0); | |
| 314 | return writeToPackedMemory(val, pt, buffer[0..byte_count], 0); | |
| 313 | 315 | }, |
| 314 | 316 | .@"struct" => { |
| 315 | 317 | const struct_type = zcu.typeToStruct(ty) orelse return error.IllDefinedMemoryLayout; |
| ... | ... | @@ -328,8 +330,8 @@ pub fn writeToMemory(val: Value, pt: Zcu.PerThread, buffer: []u8) error{ |
| 328 | 330 | try writeToMemory(field_val, pt, buffer[off..]); |
| 329 | 331 | }, |
| 330 | 332 | .@"packed" => { |
| 331 | const byte_count = (@as(usize, @intCast(ty.bitSize(zcu))) + 7) / 8; | |
| 332 | return writeToPackedMemory(val, ty, pt, buffer[0..byte_count], 0); | |
| 333 | const int_index = ip.indexToKey(val.toIntern()).bitpack.backing_int_val; | |
| 334 | return Value.fromInterned(int_index).writeToMemory(pt, buffer); | |
| 333 | 335 | }, |
| 334 | 336 | } |
| 335 | 337 | }, |
| ... | ... | @@ -344,15 +346,14 @@ pub fn writeToMemory(val: Value, pt: Zcu.PerThread, buffer: []u8) error{ |
| 344 | 346 | const byte_count: usize = @intCast(field_type.abiSize(zcu)); |
| 345 | 347 | return writeToMemory(field_val, pt, buffer[0..byte_count]); |
| 346 | 348 | } else { |
| 347 | const backing_ty = try ty.unionBackingType(pt); | |
| 349 | const backing_ty = try ty.externUnionBackingType(pt); | |
| 348 | 350 | const byte_count: usize = @intCast(backing_ty.abiSize(zcu)); |
| 349 | 351 | return writeToMemory(val.unionValue(zcu), pt, buffer[0..byte_count]); |
| 350 | 352 | } |
| 351 | 353 | }, |
| 352 | 354 | .@"packed" => { |
| 353 | const backing_ty = try ty.unionBackingType(pt); | |
| 354 | const byte_count: usize = @intCast(backing_ty.abiSize(zcu)); | |
| 355 | return writeToPackedMemory(val, ty, pt, buffer[0..byte_count], 0); | |
| 355 | const int_val: Value = .fromInterned(ip.indexToKey(val.toIntern()).bitpack.backing_int_val); | |
| 356 | return writeToMemory(int_val, pt, buffer); | |
| 356 | 357 | }, |
| 357 | 358 | }, |
| 358 | 359 | .optional => { |
| ... | ... | @@ -374,7 +375,6 @@ pub fn writeToMemory(val: Value, pt: Zcu.PerThread, buffer: []u8) error{ |
| 374 | 375 | /// big-endian packed memory layouts start at the end of the buffer. |
| 375 | 376 | pub fn writeToPackedMemory( |
| 376 | 377 | val: Value, |
| 377 | ty: Type, | |
| 378 | 378 | pt: Zcu.PerThread, |
| 379 | 379 | buffer: []u8, |
| 380 | 380 | bit_offset: usize, |
| ... | ... | @@ -383,6 +383,7 @@ pub fn writeToPackedMemory( |
| 383 | 383 | const ip = &zcu.intern_pool; |
| 384 | 384 | const target = zcu.getTarget(); |
| 385 | 385 | const endian = target.cpu.arch.endian(); |
| 386 | const ty = val.typeOf(zcu); | |
| 386 | 387 | if (val.isUndef(zcu)) { |
| 387 | 388 | const bit_size: usize = @intCast(ty.bitSize(zcu)); |
| 388 | 389 | if (bit_size != 0) { |
| ... | ... | @@ -405,7 +406,13 @@ pub fn writeToPackedMemory( |
| 405 | 406 | }, |
| 406 | 407 | .@"enum" => { |
| 407 | 408 | const int_val = val.intFromEnum(zcu); |
| 408 | return int_val.writeToPackedMemory(int_val.typeOf(zcu), pt, buffer, bit_offset); | |
| 409 | return int_val.writeToPackedMemory(pt, buffer, bit_offset); | |
| 410 | }, | |
| 411 | .pointer => { | |
| 412 | assert(!ty.isSlice(zcu)); // No well defined layout. | |
| 413 | if (ip.getBackingAddrTag(val.toIntern()).? != .int) return error.ReinterpretDeclRef; | |
| 414 | const addr = val.toUnsignedInt(zcu); | |
| 415 | std.mem.writeVarPackedInt(buffer, bit_offset, zcu.getTarget().ptrBitWidth(), addr, endian); | |
| 409 | 416 | }, |
| 410 | 417 | .int => { |
| 411 | 418 | const bits = ty.intInfo(zcu).bits; |
| ... | ... | @@ -434,54 +441,21 @@ pub fn writeToPackedMemory( |
| 434 | 441 | // On big-endian systems, LLVM reverses the element order of vectors by default |
| 435 | 442 | const tgt_elem_i = if (endian == .big) len - elem_i - 1 else elem_i; |
| 436 | 443 | const elem_val = try val.elemValue(pt, tgt_elem_i); |
| 437 | try elem_val.writeToPackedMemory(elem_ty, pt, buffer, bit_offset + bits); | |
| 444 | try elem_val.writeToPackedMemory(pt, buffer, bit_offset + bits); | |
| 438 | 445 | bits += elem_bit_size; |
| 439 | 446 | } |
| 440 | 447 | }, |
| 441 | .@"struct" => { | |
| 442 | const struct_type = ip.loadStructType(ty.toIntern()); | |
| 443 | // Sema is supposed to have emitted a compile error already in the case of Auto, | |
| 444 | // and Extern is handled in non-packed writeToMemory. | |
| 445 | assert(struct_type.layout == .@"packed"); | |
| 446 | var bits: u16 = 0; | |
| 447 | for (0..struct_type.field_types.len) |i| { | |
| 448 | const field_val = Value.fromInterned(switch (ip.indexToKey(val.toIntern()).aggregate.storage) { | |
| 449 | .bytes => unreachable, | |
| 450 | .elems => |elems| elems[i], | |
| 451 | .repeated_elem => |elem| elem, | |
| 452 | }); | |
| 453 | const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]); | |
| 454 | const field_bits: u16 = @intCast(field_ty.bitSize(zcu)); | |
| 455 | try field_val.writeToPackedMemory(field_ty, pt, buffer, bit_offset + bits); | |
| 456 | bits += field_bits; | |
| 457 | } | |
| 458 | }, | |
| 459 | .@"union" => { | |
| 460 | const union_obj = zcu.typeToUnion(ty).?; | |
| 461 | assert(union_obj.layout == .@"packed"); | |
| 462 | if (val.unionTag(zcu)) |union_tag| { | |
| 463 | const field_index = zcu.unionTagFieldIndex(union_obj, union_tag).?; | |
| 464 | const field_type = Type.fromInterned(union_obj.field_types.get(ip)[field_index]); | |
| 465 | const field_val = try val.fieldValue(pt, field_index); | |
| 466 | return field_val.writeToPackedMemory(field_type, pt, buffer, bit_offset); | |
| 467 | } else { | |
| 468 | const backing_ty = try ty.unionBackingType(pt); | |
| 469 | return val.unionValue(zcu).writeToPackedMemory(backing_ty, pt, buffer, bit_offset); | |
| 470 | } | |
| 471 | }, | |
| 472 | .pointer => { | |
| 473 | assert(!ty.isSlice(zcu)); // No well defined layout. | |
| 474 | if (ip.getBackingAddrTag(val.toIntern()).? != .int) return error.ReinterpretDeclRef; | |
| 475 | return val.writeToPackedMemory(Type.usize, pt, buffer, bit_offset); | |
| 448 | .@"struct", .@"union" => { | |
| 449 | assert(ty.containerLayout(zcu) == .@"packed"); | |
| 450 | const int_val: Value = .fromInterned(ip.indexToKey(val.toIntern()).bitpack.backing_int_val); | |
| 451 | return int_val.writeToPackedMemory(pt, buffer, bit_offset); | |
| 476 | 452 | }, |
| 477 | 453 | .optional => { |
| 478 | 454 | assert(ty.isPtrLikeOptional(zcu)); |
| 479 | const child = ty.optionalChild(zcu); | |
| 480 | const opt_val = val.optionalValue(zcu); | |
| 481 | if (opt_val) |some| { | |
| 482 | return some.writeToPackedMemory(child, pt, buffer, bit_offset); | |
| 455 | if (val.optionalValue(zcu)) |ptr_val| { | |
| 456 | return ptr_val.writeToPackedMemory(pt, buffer, bit_offset); | |
| 483 | 457 | } else { |
| 484 | return writeToPackedMemory(try pt.intValue(Type.usize, 0), Type.usize, pt, buffer, bit_offset); | |
| 458 | return Value.zero_usize.writeToPackedMemory(pt, buffer, bit_offset); | |
| 485 | 459 | } |
| 486 | 460 | }, |
| 487 | 461 | else => @panic("TODO implement writeToPackedMemory for more types"), |
| ... | ... | @@ -531,13 +505,12 @@ pub fn readFromPackedMemory( |
| 531 | 505 | pt: Zcu.PerThread, |
| 532 | 506 | buffer: []const u8, |
| 533 | 507 | bit_offset: usize, |
| 534 | arena: Allocator, | |
| 508 | gpa: Allocator, | |
| 535 | 509 | ) error{ |
| 536 | 510 | IllDefinedMemoryLayout, |
| 537 | 511 | OutOfMemory, |
| 538 | 512 | }!Value { |
| 539 | 513 | const zcu = pt.zcu; |
| 540 | const ip = &zcu.intern_pool; | |
| 541 | 514 | const target = zcu.getTarget(); |
| 542 | 515 | const endian = target.cpu.arch.endian(); |
| 543 | 516 | switch (ty.zigTypeTag(zcu)) { |
| ... | ... | @@ -571,7 +544,8 @@ pub fn readFromPackedMemory( |
| 571 | 544 | const abi_size: usize = @intCast(ty.abiSize(zcu)); |
| 572 | 545 | const Limb = std.math.big.Limb; |
| 573 | 546 | const limb_count = (abi_size + @sizeOf(Limb) - 1) / @sizeOf(Limb); |
| 574 | const limbs_buffer = try arena.alloc(Limb, limb_count); | |
| 547 | const limbs_buffer = try gpa.alloc(Limb, limb_count); | |
| 548 | defer gpa.free(limbs_buffer); | |
| 575 | 549 | |
| 576 | 550 | var bigint = BigIntMutable.init(limbs_buffer, 0); |
| 577 | 551 | bigint.readPackedTwosComplement(buffer, bit_offset, bits, endian, int_info.signedness); |
| ... | ... | @@ -579,7 +553,7 @@ pub fn readFromPackedMemory( |
| 579 | 553 | }, |
| 580 | 554 | .@"enum" => { |
| 581 | 555 | const int_ty = ty.intTagType(zcu); |
| 582 | const int_val = try Value.readFromPackedMemory(int_ty, pt, buffer, bit_offset, arena); | |
| 556 | const int_val = try Value.readFromPackedMemory(int_ty, pt, buffer, bit_offset, gpa); | |
| 583 | 557 | return pt.getCoerced(int_val, ty); |
| 584 | 558 | }, |
| 585 | 559 | .float => return Value.fromInterned(try pt.intern(.{ .float = .{ |
| ... | ... | @@ -595,52 +569,32 @@ pub fn readFromPackedMemory( |
| 595 | 569 | } })), |
| 596 | 570 | .vector => { |
| 597 | 571 | const elem_ty = ty.childType(zcu); |
| 598 | const elems = try arena.alloc(InternPool.Index, @intCast(ty.arrayLen(zcu))); | |
| 572 | const elems = try gpa.alloc(InternPool.Index, @intCast(ty.arrayLen(zcu))); | |
| 573 | defer gpa.free(elems); | |
| 599 | 574 | |
| 600 | 575 | var bits: u16 = 0; |
| 601 | 576 | const elem_bit_size: u16 = @intCast(elem_ty.bitSize(zcu)); |
| 602 | 577 | for (elems, 0..) |_, i| { |
| 603 | 578 | // On big-endian systems, LLVM reverses the element order of vectors by default |
| 604 | 579 | const tgt_elem_i = if (endian == .big) elems.len - i - 1 else i; |
| 605 | elems[tgt_elem_i] = (try readFromPackedMemory(elem_ty, pt, buffer, bit_offset + bits, arena)).toIntern(); | |
| 580 | elems[tgt_elem_i] = (try readFromPackedMemory(elem_ty, pt, buffer, bit_offset + bits, gpa)).toIntern(); | |
| 606 | 581 | bits += elem_bit_size; |
| 607 | 582 | } |
| 608 | 583 | return pt.aggregateValue(ty, elems); |
| 609 | 584 | }, |
| 610 | .@"struct" => { | |
| 611 | // Sema is supposed to have emitted a compile error already for Auto layout structs, | |
| 612 | // and Extern is handled by non-packed readFromMemory. | |
| 613 | const struct_type = zcu.typeToPackedStruct(ty).?; | |
| 614 | var bits: u16 = 0; | |
| 615 | const field_vals = try arena.alloc(InternPool.Index, struct_type.field_types.len); | |
| 616 | for (field_vals, 0..) |*field_val, i| { | |
| 617 | const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]); | |
| 618 | const field_bits: u16 = @intCast(field_ty.bitSize(zcu)); | |
| 619 | field_val.* = (try readFromPackedMemory(field_ty, pt, buffer, bit_offset + bits, arena)).toIntern(); | |
| 620 | bits += field_bits; | |
| 621 | } | |
| 622 | return pt.aggregateValue(ty, field_vals); | |
| 623 | }, | |
| 624 | .@"union" => switch (ty.containerLayout(zcu)) { | |
| 625 | .auto, .@"extern" => unreachable, // Handled by non-packed readFromMemory | |
| 626 | .@"packed" => { | |
| 627 | const backing_ty = try ty.unionBackingType(pt); | |
| 628 | const val = (try readFromPackedMemory(backing_ty, pt, buffer, bit_offset, arena)).toIntern(); | |
| 629 | return Value.fromInterned(try pt.internUnion(.{ | |
| 630 | .ty = ty.toIntern(), | |
| 631 | .tag = .none, | |
| 632 | .val = val, | |
| 633 | })); | |
| 634 | }, | |
| 585 | .@"struct", .@"union" => { | |
| 586 | assert(ty.containerLayout(zcu) == .@"packed"); | |
| 587 | const int_val: Value = try .readFromPackedMemory(ty.bitpackBackingInt(zcu), pt, buffer, bit_offset, gpa); | |
| 588 | return pt.bitpackValue(ty, int_val); | |
| 635 | 589 | }, |
| 636 | 590 | .pointer => { |
| 637 | 591 | assert(!ty.isSlice(zcu)); // No well defined layout. |
| 638 | const addr = (try readFromPackedMemory(Type.usize, pt, buffer, bit_offset, arena)).toUnsignedInt(zcu); | |
| 592 | const addr = (try readFromPackedMemory(Type.usize, pt, buffer, bit_offset, gpa)).toUnsignedInt(zcu); | |
| 639 | 593 | return pt.ptrIntValue(ty, addr); |
| 640 | 594 | }, |
| 641 | 595 | .optional => { |
| 642 | 596 | assert(ty.isPtrLikeOptional(zcu)); |
| 643 | const addr = (try readFromPackedMemory(Type.usize, pt, buffer, bit_offset, arena)).toUnsignedInt(zcu); | |
| 597 | const addr = (try readFromPackedMemory(Type.usize, pt, buffer, bit_offset, gpa)).toUnsignedInt(zcu); | |
| 644 | 598 | return .fromInterned(try pt.intern(.{ .opt = .{ |
| 645 | 599 | .ty = ty.toIntern(), |
| 646 | 600 | .val = if (addr == 0) .none else (try pt.ptrIntValue(ty.childType(zcu), addr)).toIntern(), |
| ... | ... | @@ -915,8 +869,44 @@ pub fn fieldValue(val: Value, pt: Zcu.PerThread, index: usize) !Value { |
| 915 | 869 | .elems => |elems| elems[index], |
| 916 | 870 | .repeated_elem => |elem| elem, |
| 917 | 871 | }), |
| 918 | // TODO assert the tag is correct | |
| 919 | .un => |un| Value.fromInterned(un.val), | |
| 872 | .un => |un| { | |
| 873 | switch (Type.fromInterned(un.ty).containerLayout(zcu)) { | |
| 874 | .auto, .@"extern" => {}, // TODO assert the tag is correct | |
| 875 | .@"packed" => unreachable, | |
| 876 | } | |
| 877 | return .fromInterned(un.val); | |
| 878 | }, | |
| 879 | .bitpack => |bitpack| { | |
| 880 | const ty: Type = .fromInterned(bitpack.ty); | |
| 881 | assert(ty.containerLayout(zcu) == .@"packed"); | |
| 882 | const int_val: Value = .fromInterned(bitpack.backing_int_val); | |
| 883 | assert(!int_val.isUndef(zcu)); | |
| 884 | const field_ty = ty.fieldType(index, zcu); | |
| 885 | const field_bit_offset: u16 = switch (ty.zigTypeTag(zcu)) { | |
| 886 | .@"union" => 0, | |
| 887 | .@"struct" => off: { | |
| 888 | var off: u16 = 0; | |
| 889 | for (0..index) |preceding_field_index| { | |
| 890 | off += @intCast(ty.fieldType(preceding_field_index, zcu).bitSize(zcu)); | |
| 891 | } | |
| 892 | break :off off; | |
| 893 | }, | |
| 894 | else => unreachable, | |
| 895 | }; | |
| 896 | // Avoid hitting gpa for accesses to small packed structs | |
| 897 | var sfba_state = std.heap.stackFallback(128, zcu.comp.gpa); | |
| 898 | const sfba = sfba_state.get(); | |
| 899 | const buf = try sfba.alloc(u8, (ty.bitSize(zcu) + 7) / 8); | |
| 900 | defer sfba.free(buf); | |
| 901 | int_val.writeToPackedMemory(pt, buf, 0) catch |err| switch (err) { | |
| 902 | error.ReinterpretDeclRef => unreachable, // it's an integer | |
| 903 | error.OutOfMemory => |e| return e, | |
| 904 | }; | |
| 905 | return Value.readFromPackedMemory(field_ty, pt, buf, field_bit_offset, sfba) catch |err| switch (err) { | |
| 906 | error.IllDefinedMemoryLayout => unreachable, // it's a bitpack | |
| 907 | error.OutOfMemory => |e| return e, | |
| 908 | }; | |
| 909 | }, | |
| 920 | 910 | else => unreachable, |
| 921 | 911 | }; |
| 922 | 912 | } |
src/Zcu/PerThread.zig+9| ... | ... | @@ -3950,6 +3950,15 @@ pub fn floatValue(pt: Zcu.PerThread, ty: Type, x: anytype) Allocator.Error!Value |
| 3950 | 3950 | } })); |
| 3951 | 3951 | } |
| 3952 | 3952 | |
| 3953 | /// Create a value whose type is a `packed struct` or `packed union`, from the backing integer value. | |
| 3954 | pub fn bitpackValue(pt: Zcu.PerThread, ty: Type, backing_int_val: Value) Allocator.Error!Value { | |
| 3955 | assert(backing_int_val.typeOf(pt.zcu).toIntern() == ty.bitpackBackingInt(pt.zcu).toIntern()); | |
| 3956 | return .fromInterned(try pt.intern(.{ .bitpack = .{ | |
| 3957 | .ty = ty.toIntern(), | |
| 3958 | .backing_int_val = backing_int_val.toIntern(), | |
| 3959 | } })); | |
| 3960 | } | |
| 3961 | ||
| 3953 | 3962 | pub fn nullValue(pt: Zcu.PerThread, opt_ty: Type) Allocator.Error!Value { |
| 3954 | 3963 | assert(pt.zcu.intern_pool.isOptionalType(opt_ty.toIntern())); |
| 3955 | 3964 | return Value.fromInterned(try pt.intern(.{ .opt = .{ |
src/codegen.zig+6-36| ... | ... | @@ -570,42 +570,7 @@ pub fn generateSymbol( |
| 570 | 570 | .struct_type => { |
| 571 | 571 | const struct_type = ip.loadStructType(ty.toIntern()); |
| 572 | 572 | switch (struct_type.layout) { |
| 573 | .@"packed" => { | |
| 574 | const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; | |
| 575 | const start = w.end; | |
| 576 | const buffer = try w.writableSlice(abi_size); | |
| 577 | @memset(buffer, 0); | |
| 578 | var bits: u16 = 0; | |
| 579 | ||
| 580 | for (struct_type.field_types.get(ip), 0..) |field_ty, index| { | |
| 581 | const field_val = switch (aggregate.storage) { | |
| 582 | .bytes => |bytes| try pt.intern(.{ .int = .{ | |
| 583 | .ty = field_ty, | |
| 584 | .storage = .{ .u64 = bytes.at(index, ip) }, | |
| 585 | } }), | |
| 586 | .elems => |elems| elems[index], | |
| 587 | .repeated_elem => |elem| elem, | |
| 588 | }; | |
| 589 | ||
| 590 | // pointer may point to a decl which must be marked used | |
| 591 | // but can also result in a relocation. Therefore we handle those separately. | |
| 592 | if (Type.fromInterned(field_ty).zigTypeTag(zcu) == .pointer) { | |
| 593 | const field_offset = std.math.divExact(u16, bits, 8) catch |err| switch (err) { | |
| 594 | error.DivisionByZero => unreachable, | |
| 595 | error.UnexpectedRemainder => return error.RelocationNotByteAligned, | |
| 596 | }; | |
| 597 | w.end = start + field_offset; | |
| 598 | defer { | |
| 599 | assert(w.end == start + field_offset + @divExact(target.ptrBitWidth(), 8)); | |
| 600 | w.end = start + abi_size; | |
| 601 | } | |
| 602 | try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), w, reloc_parent); | |
| 603 | } else { | |
| 604 | Value.fromInterned(field_val).writeToPackedMemory(.fromInterned(field_ty), pt, buffer, bits) catch unreachable; | |
| 605 | } | |
| 606 | bits += @intCast(Type.fromInterned(field_ty).bitSize(zcu)); | |
| 607 | } | |
| 608 | }, | |
| 573 | .@"packed" => unreachable, | |
| 609 | 574 | .auto, .@"extern" => { |
| 610 | 575 | const struct_begin = w.end; |
| 611 | 576 | const field_types = struct_type.field_types.get(ip); |
| ... | ... | @@ -683,6 +648,7 @@ pub fn generateSymbol( |
| 683 | 648 | } |
| 684 | 649 | } |
| 685 | 650 | }, |
| 651 | .bitpack => |bitpack| try generateSymbol(bin_file, pt, src_loc, .fromInterned(bitpack.backing_int_val), w, reloc_parent), | |
| 686 | 652 | .memoized_call => unreachable, |
| 687 | 653 | } |
| 688 | 654 | } |
| ... | ... | @@ -1120,6 +1086,10 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo |
| 1120 | 1086 | target, |
| 1121 | 1087 | ); |
| 1122 | 1088 | }, |
| 1089 | .@"struct", .@"union" => if (ty.containerLayout(zcu) == .@"packed") { | |
| 1090 | const bitpack = ip.indexToKey(val.toIntern()).bitpack; | |
| 1091 | return lowerValue(pt, .fromInterned(bitpack.backing_int_val), target); | |
| 1092 | }, | |
| 1123 | 1093 | .error_set => { |
| 1124 | 1094 | const err_name = ip.indexToKey(val.toIntern()).err.name; |
| 1125 | 1095 | const error_index = ip.getErrorValueIfExists(err_name).?; |
src/codegen/aarch64/Select.zig+20-26| ... | ... | @@ -2791,17 +2791,17 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, |
| 2791 | 2791 | } else return isel.fail("invalid constraint: '{s}'", .{constraint}); |
| 2792 | 2792 | } |
| 2793 | 2793 | |
| 2794 | const clobbers = ip.indexToKey(unwrapped_asm.clobbers).aggregate; | |
| 2795 | const clobbers_ty: ZigType = .fromInterned(clobbers.ty); | |
| 2794 | const clobbers_val: Value = .fromInterned(unwrapped_asm.clobbers); | |
| 2795 | const clobbers_ty = clobbers_val.typeOf(zcu); | |
| 2796 | var clobbers_bigint_buf: Value.BigIntSpace = undefined; | |
| 2797 | const clobbers_bigint = clobbers_val.toBigInt(&clobbers_bigint_buf, zcu); | |
| 2796 | 2798 | for (0..clobbers_ty.structFieldCount(zcu)) |field_index| { |
| 2797 | switch (switch (clobbers.storage) { | |
| 2798 | .bytes => unreachable, | |
| 2799 | .elems => |elems| elems[field_index], | |
| 2800 | .repeated_elem => |repeated_elem| repeated_elem, | |
| 2801 | }) { | |
| 2802 | else => unreachable, | |
| 2803 | .bool_false => continue, | |
| 2804 | .bool_true => {}, | |
| 2799 | assert(clobbers_ty.fieldType(field_index, zcu).toIntern() == .bool_type); | |
| 2800 | const limb_bits = @bitSizeOf(std.math.big.Limb); | |
| 2801 | if (field_index / limb_bits >= clobbers_bigint.limbs.len) continue; // field is false | |
| 2802 | switch (@as(u1, @truncate(clobbers_bigint.limbs[field_index / limb_bits] >> @intCast(field_index % limb_bits)))) { | |
| 2803 | 0 => continue, // field is false | |
| 2804 | 1 => {}, // field is true | |
| 2805 | 2805 | } |
| 2806 | 2806 | const clobber_name = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?; |
| 2807 | 2807 | if (std.mem.eql(u8, clobber_name, "memory")) continue; |
| ... | ... | @@ -2816,14 +2816,11 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, |
| 2816 | 2816 | } |
| 2817 | 2817 | } |
| 2818 | 2818 | for (0..clobbers_ty.structFieldCount(zcu)) |field_index| { |
| 2819 | switch (switch (clobbers.storage) { | |
| 2820 | .bytes => unreachable, | |
| 2821 | .elems => |elems| elems[field_index], | |
| 2822 | .repeated_elem => |repeated_elem| repeated_elem, | |
| 2823 | }) { | |
| 2824 | else => unreachable, | |
| 2825 | .bool_false => continue, | |
| 2826 | .bool_true => {}, | |
| 2819 | const limb_bits = @bitSizeOf(std.math.big.Limb); | |
| 2820 | if (field_index / limb_bits >= clobbers_bigint.limbs.len) continue; // field is false | |
| 2821 | switch (@as(u1, @truncate(clobbers_bigint.limbs[field_index / limb_bits] >> field_index % limb_bits))) { | |
| 2822 | 0 => continue, // field is false | |
| 2823 | 1 => {}, // field is true | |
| 2827 | 2824 | } |
| 2828 | 2825 | const clobber_name = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?; |
| 2829 | 2826 | if (std.mem.eql(u8, clobber_name, "memory")) continue; |
| ... | ... | @@ -2872,14 +2869,11 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, |
| 2872 | 2869 | } |
| 2873 | 2870 | |
| 2874 | 2871 | for (0..clobbers_ty.structFieldCount(zcu)) |field_index| { |
| 2875 | switch (switch (clobbers.storage) { | |
| 2876 | .bytes => unreachable, | |
| 2877 | .elems => |elems| elems[field_index], | |
| 2878 | .repeated_elem => |repeated_elem| repeated_elem, | |
| 2879 | }) { | |
| 2880 | else => unreachable, | |
| 2881 | .bool_false => continue, | |
| 2882 | .bool_true => {}, | |
| 2872 | const limb_bits = @bitSizeOf(std.math.big.Limb); | |
| 2873 | if (field_index / limb_bits >= clobbers_bigint.limbs.len) continue; // field is false | |
| 2874 | switch (@as(u1, @truncate(clobbers_bigint.limbs[field_index / limb_bits] >> field_index % limb_bits))) { | |
| 2875 | 0 => continue, // field is false | |
| 2876 | 1 => {}, // field is true | |
| 2883 | 2877 | } |
| 2884 | 2878 | const clobber_name = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?; |
| 2885 | 2879 | if (std.mem.eql(u8, clobber_name, "memory")) continue; |
src/codegen/c.zig+68-114| ... | ... | @@ -1362,77 +1362,42 @@ pub const DeclGen = struct { |
| 1362 | 1362 | }, |
| 1363 | 1363 | .struct_type => { |
| 1364 | 1364 | const loaded_struct = ip.loadStructType(ty.toIntern()); |
| 1365 | switch (loaded_struct.layout) { | |
| 1366 | .auto, .@"extern" => { | |
| 1367 | if (!location.isInitializer()) { | |
| 1368 | try w.writeByte('('); | |
| 1369 | try dg.renderCType(w, ctype); | |
| 1370 | try w.writeByte(')'); | |
| 1371 | } | |
| 1365 | assert(loaded_struct.layout != .@"packed"); | |
| 1372 | 1366 | |
| 1373 | try w.writeByte('{'); | |
| 1374 | var field_it = loaded_struct.iterateRuntimeOrder(ip); | |
| 1375 | var need_comma = false; | |
| 1376 | while (field_it.next()) |field_index| { | |
| 1377 | const field_ty: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); | |
| 1378 | if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue; | |
| 1367 | if (!location.isInitializer()) { | |
| 1368 | try w.writeByte('('); | |
| 1369 | try dg.renderCType(w, ctype); | |
| 1370 | try w.writeByte(')'); | |
| 1371 | } | |
| 1379 | 1372 | |
| 1380 | if (need_comma) try w.writeByte(','); | |
| 1381 | need_comma = true; | |
| 1382 | const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) { | |
| 1383 | .bytes => |bytes| try pt.intern(.{ .int = .{ | |
| 1384 | .ty = field_ty.toIntern(), | |
| 1385 | .storage = .{ .u64 = bytes.at(field_index, ip) }, | |
| 1386 | } }), | |
| 1387 | .elems => |elems| elems[field_index], | |
| 1388 | .repeated_elem => |elem| elem, | |
| 1389 | }; | |
| 1390 | try dg.renderValue(w, Value.fromInterned(field_val), initializer_type); | |
| 1391 | } | |
| 1392 | try w.writeByte('}'); | |
| 1393 | }, | |
| 1394 | .@"packed" => { | |
| 1395 | // https://github.com/ziglang/zig/issues/24657 will eliminate most of the | |
| 1396 | // following logic, leaving only the recursive `renderValue` call. Once | |
| 1397 | // that proposal is implemented, a `packed struct` will literally be | |
| 1398 | // represented in the InternPool by its comptime-known backing integer. | |
| 1399 | var arena: std.heap.ArenaAllocator = .init(zcu.gpa); | |
| 1400 | defer arena.deinit(); | |
| 1401 | const backing_ty: Type = .fromInterned(loaded_struct.backingIntTypeUnordered(ip)); | |
| 1402 | const buf = try arena.allocator().alloc(u8, @intCast(ty.abiSize(zcu))); | |
| 1403 | val.writeToMemory(pt, buf) catch |err| switch (err) { | |
| 1404 | error.IllDefinedMemoryLayout => unreachable, | |
| 1405 | error.OutOfMemory => |e| return e, | |
| 1406 | error.ReinterpretDeclRef, error.Unimplemented => return dg.fail("TODO: C backend: lower packed struct value", .{}), | |
| 1407 | }; | |
| 1408 | const backing_val: Value = try .readUintFromMemory(backing_ty, pt, buf, arena.allocator()); | |
| 1409 | return dg.renderValue(w, backing_val, location); | |
| 1410 | }, | |
| 1373 | try w.writeByte('{'); | |
| 1374 | var field_it = loaded_struct.iterateRuntimeOrder(ip); | |
| 1375 | var need_comma = false; | |
| 1376 | while (field_it.next()) |field_index| { | |
| 1377 | const field_ty: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); | |
| 1378 | if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue; | |
| 1379 | ||
| 1380 | if (need_comma) try w.writeByte(','); | |
| 1381 | need_comma = true; | |
| 1382 | const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) { | |
| 1383 | .bytes => |bytes| try pt.intern(.{ .int = .{ | |
| 1384 | .ty = field_ty.toIntern(), | |
| 1385 | .storage = .{ .u64 = bytes.at(field_index, ip) }, | |
| 1386 | } }), | |
| 1387 | .elems => |elems| elems[field_index], | |
| 1388 | .repeated_elem => |elem| elem, | |
| 1389 | }; | |
| 1390 | try dg.renderValue(w, Value.fromInterned(field_val), initializer_type); | |
| 1411 | 1391 | } |
| 1392 | try w.writeByte('}'); | |
| 1412 | 1393 | }, |
| 1413 | 1394 | else => unreachable, |
| 1414 | 1395 | }, |
| 1396 | .bitpack => |bitpack| return dg.renderValue(w, .fromInterned(bitpack.backing_int_val), location), | |
| 1415 | 1397 | .un => |un| { |
| 1416 | 1398 | const loaded_union = ip.loadUnionType(ty.toIntern()); |
| 1417 | if (loaded_union.flagsUnordered(ip).layout == .@"packed") { | |
| 1418 | // https://github.com/ziglang/zig/issues/24657 will eliminate most of the | |
| 1419 | // following logic, leaving only the recursive `renderValue` call. Once | |
| 1420 | // that proposal is implemented, a `packed union` will literally be | |
| 1421 | // represented in the InternPool by its comptime-known backing integer. | |
| 1422 | var arena: std.heap.ArenaAllocator = .init(zcu.gpa); | |
| 1423 | defer arena.deinit(); | |
| 1424 | const backing_ty = try ty.unionBackingType(pt); | |
| 1425 | const buf = try arena.allocator().alloc(u8, @intCast(ty.abiSize(zcu))); | |
| 1426 | val.writeToMemory(pt, buf) catch |err| switch (err) { | |
| 1427 | error.IllDefinedMemoryLayout => unreachable, | |
| 1428 | error.OutOfMemory => |e| return e, | |
| 1429 | error.ReinterpretDeclRef, error.Unimplemented => return dg.fail("TODO: C backend: lower packed union value", .{}), | |
| 1430 | }; | |
| 1431 | const backing_val: Value = try .readUintFromMemory(backing_ty, pt, buf, arena.allocator()); | |
| 1432 | return dg.renderValue(w, backing_val, location); | |
| 1433 | } | |
| 1434 | 1399 | if (un.tag == .none) { |
| 1435 | const backing_ty = try ty.unionBackingType(pt); | |
| 1400 | const backing_ty = try ty.externUnionBackingType(pt); | |
| 1436 | 1401 | assert(loaded_union.flagsUnordered(ip).layout == .@"extern"); |
| 1437 | 1402 | if (location == .StaticInitializer) { |
| 1438 | 1403 | return dg.fail("TODO: C backend: implement extern union backing type rendering in static initializers", .{}); |
| ... | ... | @@ -1642,11 +1607,7 @@ pub const DeclGen = struct { |
| 1642 | 1607 | } |
| 1643 | 1608 | return w.writeByte('}'); |
| 1644 | 1609 | }, |
| 1645 | .@"packed" => return dg.renderUndefValue( | |
| 1646 | w, | |
| 1647 | .fromInterned(loaded_struct.backingIntTypeUnordered(ip)), | |
| 1648 | location, | |
| 1649 | ), | |
| 1610 | .@"packed" => return dg.renderUndefValue(w, ty.bitpackBackingInt(zcu), location), | |
| 1650 | 1611 | } |
| 1651 | 1612 | }, |
| 1652 | 1613 | .tuple_type => |tuple_info| { |
| ... | ... | @@ -1714,11 +1675,7 @@ pub const DeclGen = struct { |
| 1714 | 1675 | } |
| 1715 | 1676 | if (has_tag) try w.writeByte('}'); |
| 1716 | 1677 | }, |
| 1717 | .@"packed" => return dg.renderUndefValue( | |
| 1718 | w, | |
| 1719 | try ty.unionBackingType(pt), | |
| 1720 | location, | |
| 1721 | ), | |
| 1678 | .@"packed" => return dg.renderUndefValue(w, ty.bitpackBackingInt(zcu), location), | |
| 1722 | 1679 | } |
| 1723 | 1680 | }, |
| 1724 | 1681 | .error_union_type => |error_union_type| switch (ctype.info(ctype_pool)) { |
| ... | ... | @@ -5623,48 +5580,45 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5623 | 5580 | } |
| 5624 | 5581 | try w.writeByte(':'); |
| 5625 | 5582 | const ip = &zcu.intern_pool; |
| 5626 | const aggregate = ip.indexToKey(unwrapped_asm.clobbers).aggregate; | |
| 5627 | const struct_type: Type = .fromInterned(aggregate.ty); | |
| 5628 | switch (aggregate.storage) { | |
| 5629 | .elems => |elems| for (elems, 0..) |elem, i| switch (elem) { | |
| 5630 | .bool_true => { | |
| 5631 | const field_name = struct_type.structFieldName(i, zcu).toSlice(ip).?; | |
| 5632 | assert(field_name.len != 0); | |
| 5633 | ||
| 5634 | const target = &f.object.dg.mod.resolved_target.result; | |
| 5635 | var c_name_buf: [16]u8 = undefined; | |
| 5636 | const name = | |
| 5637 | if ((target.cpu.arch.isMIPS() or target.cpu.arch == .alpha) and field_name[0] == 'r') name: { | |
| 5638 | // Convert "rN" to "$N" | |
| 5639 | const c_name = (&c_name_buf)[0..field_name.len]; | |
| 5640 | @memcpy(c_name, field_name); | |
| 5641 | c_name_buf[0] = '$'; | |
| 5642 | break :name c_name; | |
| 5643 | } else if ((target.cpu.arch.isMIPS() and (mem.startsWith(u8, field_name, "fcc") or field_name[0] == 'w')) or | |
| 5644 | ((target.cpu.arch.isMIPS() or target.cpu.arch == .alpha) and field_name[0] == 'f') or | |
| 5645 | (target.cpu.arch == .kvx and !mem.eql(u8, field_name, "memory"))) name: { | |
| 5646 | // "$" prefix for these registers | |
| 5647 | c_name_buf[0] = '$'; | |
| 5648 | @memcpy((&c_name_buf)[1..][0..field_name.len], field_name); | |
| 5649 | break :name (&c_name_buf)[0 .. 1 + field_name.len]; | |
| 5650 | } else if (target.cpu.arch.isSPARC() and | |
| 5651 | (mem.eql(u8, field_name, "ccr") or mem.eql(u8, field_name, "icc") or mem.eql(u8, field_name, "xcc"))) name: { | |
| 5652 | // C compilers just use `icc` to encompass all of these. | |
| 5653 | break :name "icc"; | |
| 5654 | } else field_name; | |
| 5655 | ||
| 5656 | try w.print(" {f}", .{fmtStringLiteral(name, null)}); | |
| 5657 | (try w.writableArray(1))[0] = ','; | |
| 5658 | }, | |
| 5659 | .bool_false => continue, | |
| 5660 | else => unreachable, | |
| 5661 | }, | |
| 5662 | .repeated_elem => |elem| switch (elem) { | |
| 5663 | .bool_true => @panic("TODO"), | |
| 5664 | .bool_false => {}, | |
| 5665 | else => unreachable, | |
| 5666 | }, | |
| 5667 | .bytes => @panic("TODO"), | |
| 5583 | const clobbers_val: Value = .fromInterned(unwrapped_asm.clobbers); | |
| 5584 | const clobbers_ty = clobbers_val.typeOf(zcu); | |
| 5585 | var clobbers_bigint_buf: Value.BigIntSpace = undefined; | |
| 5586 | const clobbers_bigint = clobbers_val.toBigInt(&clobbers_bigint_buf, zcu); | |
| 5587 | for (0..clobbers_ty.structFieldCount(zcu)) |field_index| { | |
| 5588 | assert(clobbers_ty.fieldType(field_index, zcu).toIntern() == .bool_type); | |
| 5589 | const limb_bits = @bitSizeOf(std.math.big.Limb); | |
| 5590 | if (field_index / limb_bits >= clobbers_bigint.limbs.len) continue; // field is false | |
| 5591 | switch (@as(u1, @truncate(clobbers_bigint.limbs[field_index / limb_bits] >> @intCast(field_index % limb_bits)))) { | |
| 5592 | 0 => continue, // field is false | |
| 5593 | 1 => {}, // field is true | |
| 5594 | } | |
| 5595 | const field_name = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?; | |
| 5596 | assert(field_name.len != 0); | |
| 5597 | ||
| 5598 | const target = &f.object.dg.mod.resolved_target.result; | |
| 5599 | var c_name_buf: [16]u8 = undefined; | |
| 5600 | const name = | |
| 5601 | if ((target.cpu.arch.isMIPS() or target.cpu.arch == .alpha) and field_name[0] == 'r') name: { | |
| 5602 | // Convert "rN" to "$N" | |
| 5603 | const c_name = (&c_name_buf)[0..field_name.len]; | |
| 5604 | @memcpy(c_name, field_name); | |
| 5605 | c_name_buf[0] = '$'; | |
| 5606 | break :name c_name; | |
| 5607 | } else if ((target.cpu.arch.isMIPS() and (mem.startsWith(u8, field_name, "fcc") or field_name[0] == 'w')) or | |
| 5608 | ((target.cpu.arch.isMIPS() or target.cpu.arch == .alpha) and field_name[0] == 'f') or | |
| 5609 | (target.cpu.arch == .kvx and !mem.eql(u8, field_name, "memory"))) name: { | |
| 5610 | // "$" prefix for these registers | |
| 5611 | c_name_buf[0] = '$'; | |
| 5612 | @memcpy((&c_name_buf)[1..][0..field_name.len], field_name); | |
| 5613 | break :name (&c_name_buf)[0 .. 1 + field_name.len]; | |
| 5614 | } else if (target.cpu.arch.isSPARC() and | |
| 5615 | (mem.eql(u8, field_name, "ccr") or mem.eql(u8, field_name, "icc") or mem.eql(u8, field_name, "xcc"))) name: { | |
| 5616 | // C compilers just use `icc` to encompass all of these. | |
| 5617 | break :name "icc"; | |
| 5618 | } else field_name; | |
| 5619 | ||
| 5620 | try w.print(" {f}", .{fmtStringLiteral(name, null)}); | |
| 5621 | (try w.writableArray(1))[0] = ','; | |
| 5668 | 5622 | } |
| 5669 | 5623 | w.undo(1); // erase the last comma |
| 5670 | 5624 | try w.writeAll(");"); |
src/codegen/llvm.zig+15-24| ... | ... | @@ -3680,7 +3680,7 @@ pub const Object = struct { |
| 3680 | 3680 | const limbs = try allocator.alloc(std.math.big.Limb, std.math.big.int.calcTwosCompLimbCount(bits)); |
| 3681 | 3681 | defer allocator.free(limbs); |
| 3682 | 3682 | |
| 3683 | val.writeToPackedMemory(ty, pt, buffer, 0) catch unreachable; | |
| 3683 | val.writeToPackedMemory(pt, buffer, 0) catch unreachable; | |
| 3684 | 3684 | |
| 3685 | 3685 | var big: std.math.big.int.Mutable = .init(limbs, 0); |
| 3686 | 3686 | big.readTwosComplement(buffer, bits, target.cpu.arch.endian(), .unsigned); |
| ... | ... | @@ -7467,29 +7467,20 @@ pub const FuncGen = struct { |
| 7467 | 7467 | } |
| 7468 | 7468 | |
| 7469 | 7469 | const ip = &zcu.intern_pool; |
| 7470 | const aggregate = ip.indexToKey(unwrapped_asm.clobbers).aggregate; | |
| 7471 | const struct_type: Type = .fromInterned(aggregate.ty); | |
| 7472 | if (total_i != 0) try llvm_constraints.append(gpa, ','); | |
| 7473 | switch (aggregate.storage) { | |
| 7474 | .elems => |elems| for (elems, 0..) |elem, i| { | |
| 7475 | switch (elem) { | |
| 7476 | .bool_true => { | |
| 7477 | const name = struct_type.structFieldName(i, zcu).toSlice(ip).?; | |
| 7478 | total_i += try appendConstraints(gpa, &llvm_constraints, name, target); | |
| 7479 | }, | |
| 7480 | .bool_false => continue, | |
| 7481 | else => unreachable, | |
| 7482 | } | |
| 7483 | }, | |
| 7484 | .repeated_elem => |elem| switch (elem) { | |
| 7485 | .bool_true => for (0..struct_type.structFieldCount(zcu)) |i| { | |
| 7486 | const name = struct_type.structFieldName(i, zcu).toSlice(ip).?; | |
| 7487 | total_i += try appendConstraints(gpa, &llvm_constraints, name, target); | |
| 7488 | }, | |
| 7489 | .bool_false => {}, | |
| 7490 | else => unreachable, | |
| 7491 | }, | |
| 7492 | .bytes => @panic("TODO"), | |
| 7470 | const clobbers_val: Value = .fromInterned(unwrapped_asm.clobbers); | |
| 7471 | const clobbers_ty = clobbers_val.typeOf(zcu); | |
| 7472 | var clobbers_bigint_buf: Value.BigIntSpace = undefined; | |
| 7473 | const clobbers_bigint = clobbers_val.toBigInt(&clobbers_bigint_buf, zcu); | |
| 7474 | for (0..clobbers_ty.structFieldCount(zcu)) |field_index| { | |
| 7475 | assert(clobbers_ty.fieldType(field_index, zcu).toIntern() == .bool_type); | |
| 7476 | const limb_bits = @bitSizeOf(std.math.big.Limb); | |
| 7477 | if (field_index / limb_bits >= clobbers_bigint.limbs.len) continue; // field is false | |
| 7478 | switch (@as(u1, @truncate(clobbers_bigint.limbs[field_index / limb_bits] >> @intCast(field_index % limb_bits)))) { | |
| 7479 | 0 => continue, // field is false | |
| 7480 | 1 => {}, // field is true | |
| 7481 | } | |
| 7482 | const name = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?; | |
| 7483 | total_i += try appendConstraints(gpa, &llvm_constraints, name, target); | |
| 7493 | 7484 | } |
| 7494 | 7485 | |
| 7495 | 7486 | // We have finished scanning through all inputs/outputs, so the number of |
src/codegen/riscv64/CodeGen.zig+20-25| ... | ... | @@ -6149,31 +6149,26 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void { |
| 6149 | 6149 | |
| 6150 | 6150 | const zcu = func.pt.zcu; |
| 6151 | 6151 | const ip = &zcu.intern_pool; |
| 6152 | const aggregate = ip.indexToKey(unwrapped_asm.clobbers).aggregate; | |
| 6153 | const struct_type: Type = .fromInterned(aggregate.ty); | |
| 6154 | switch (aggregate.storage) { | |
| 6155 | .elems => |elems| for (elems, 0..) |elem, i| { | |
| 6156 | switch (elem) { | |
| 6157 | .bool_true => { | |
| 6158 | const clobber = struct_type.structFieldName(i, zcu).toSlice(ip).?; | |
| 6159 | assert(clobber.len != 0); | |
| 6160 | if (std.mem.eql(u8, clobber, "memory")) { | |
| 6161 | // nothing really to do | |
| 6162 | } else { | |
| 6163 | try func.register_manager.getReg(parseRegName(clobber) orelse | |
| 6164 | return func.fail("invalid clobber: '{s}'", .{clobber}), null); | |
| 6165 | } | |
| 6166 | }, | |
| 6167 | .bool_false => continue, | |
| 6168 | else => unreachable, | |
| 6169 | } | |
| 6170 | }, | |
| 6171 | .repeated_elem => |elem| switch (elem) { | |
| 6172 | .bool_true => @panic("TODO"), | |
| 6173 | .bool_false => {}, | |
| 6174 | else => unreachable, | |
| 6175 | }, | |
| 6176 | .bytes => @panic("TODO"), | |
| 6152 | const clobbers_val: Value = .fromInterned(unwrapped_asm.clobbers); | |
| 6153 | const clobbers_ty = clobbers_val.typeOf(zcu); | |
| 6154 | var clobbers_bigint_buf: Value.BigIntSpace = undefined; | |
| 6155 | const clobbers_bigint = clobbers_val.toBigInt(&clobbers_bigint_buf, zcu); | |
| 6156 | for (0..clobbers_ty.structFieldCount(zcu)) |field_index| { | |
| 6157 | assert(clobbers_ty.fieldType(field_index, zcu).toIntern() == .bool_type); | |
| 6158 | const limb_bits = @bitSizeOf(std.math.big.Limb); | |
| 6159 | if (field_index / limb_bits >= clobbers_bigint.limbs.len) continue; // field is false | |
| 6160 | switch (@as(u1, @truncate(clobbers_bigint.limbs[field_index / limb_bits] >> @intCast(field_index % limb_bits)))) { | |
| 6161 | 0 => continue, // field is false | |
| 6162 | 1 => {}, // field is true | |
| 6163 | } | |
| 6164 | const clobber = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?; | |
| 6165 | assert(clobber.len != 0); | |
| 6166 | if (std.mem.eql(u8, clobber, "memory")) { | |
| 6167 | // nothing really to do | |
| 6168 | } else { | |
| 6169 | try func.register_manager.getReg(parseRegName(clobber) orelse | |
| 6170 | return func.fail("invalid clobber: '{s}'", .{clobber}), null); | |
| 6171 | } | |
| 6177 | 6172 | } |
| 6178 | 6173 | |
| 6179 | 6174 | const Label = struct { |
src/codegen/spirv/CodeGen.zig+1-1| ... | ... | @@ -969,7 +969,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id { |
| 969 | 969 | const bytes = std.mem.alignForward(u16, cg.module.backingIntBits(bits).@"0", 8) / 8; |
| 970 | 970 | var limbs: [8]u8 = undefined; |
| 971 | 971 | @memset(&limbs, 0); |
| 972 | val.writeToPackedMemory(ty, pt, limbs[0..bytes], 0) catch unreachable; | |
| 972 | val.writeToPackedMemory(pt, limbs[0..bytes], 0) catch unreachable; | |
| 973 | 973 | const backing_ty: Type = .fromInterned(struct_type.backingIntTypeUnordered(ip)); |
| 974 | 974 | return try cg.constInt(backing_ty, @as(u64, @bitCast(limbs))); |
| 975 | 975 | } |
src/codegen/wasm/CodeGen.zig+2-2| ... | ... | @@ -3253,7 +3253,7 @@ fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue { |
| 3253 | 3253 | // are by-ref types. |
| 3254 | 3254 | assert(struct_type.layout == .@"packed"); |
| 3255 | 3255 | var buf: [8]u8 = .{0} ** 8; // zero the buffer so we do not read 0xaa as integer |
| 3256 | val.writeToPackedMemory(ty, pt, &buf, 0) catch unreachable; | |
| 3256 | val.writeToPackedMemory(pt, &buf, 0) catch unreachable; | |
| 3257 | 3257 | const backing_int_ty = Type.fromInterned(struct_type.backingIntTypeUnordered(ip)); |
| 3258 | 3258 | const int_val = try pt.intValue( |
| 3259 | 3259 | backing_int_ty, |
| ... | ... | @@ -3267,7 +3267,7 @@ fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue { |
| 3267 | 3267 | const int_type = try pt.intType(.unsigned, @intCast(ty.bitSize(zcu))); |
| 3268 | 3268 | |
| 3269 | 3269 | var buf: [8]u8 = .{0} ** 8; // zero the buffer so we do not read 0xaa as integer |
| 3270 | val.writeToPackedMemory(ty, pt, &buf, 0) catch unreachable; | |
| 3270 | val.writeToPackedMemory(pt, &buf, 0) catch unreachable; | |
| 3271 | 3271 | const int_val = try pt.intValue( |
| 3272 | 3272 | int_type, |
| 3273 | 3273 | mem.readInt(u64, &buf, .little), |
src/codegen/x86_64/CodeGen.zig+32-35| ... | ... | @@ -177294,41 +177294,38 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 177294 | 177294 | } |
| 177295 | 177295 | |
| 177296 | 177296 | const ip = &zcu.intern_pool; |
| 177297 | const aggregate = ip.indexToKey(unwrapped_asm.clobbers).aggregate; | |
| 177298 | const struct_type: Type = .fromInterned(aggregate.ty); | |
| 177299 | switch (aggregate.storage) { | |
| 177300 | .elems => |elems| for (elems, 0..) |elem, i| switch (elem) { | |
| 177301 | .bool_true => { | |
| 177302 | const clobber = struct_type.structFieldName(i, zcu).toSlice(ip).?; | |
| 177303 | assert(clobber.len != 0); | |
| 177304 | ||
| 177305 | if (std.mem.eql(u8, clobber, "memory") or | |
| 177306 | std.mem.eql(u8, clobber, "fpsr") or | |
| 177307 | std.mem.eql(u8, clobber, "fpcr") or | |
| 177308 | std.mem.eql(u8, clobber, "mxcsr") or | |
| 177309 | std.mem.eql(u8, clobber, "dirflag")) | |
| 177310 | { | |
| 177311 | // ok, sure | |
| 177312 | } else if (std.mem.eql(u8, clobber, "cc") or | |
| 177313 | std.mem.eql(u8, clobber, "flags") or | |
| 177314 | std.mem.eql(u8, clobber, "eflags") or | |
| 177315 | std.mem.eql(u8, clobber, "rflags")) | |
| 177316 | { | |
| 177317 | try self.spillEflagsIfOccupied(); | |
| 177318 | } else { | |
| 177319 | try self.register_manager.getReg(parseRegName(clobber) orelse | |
| 177320 | return self.fail("invalid clobber: '{s}'", .{clobber}), null); | |
| 177321 | } | |
| 177322 | }, | |
| 177323 | .bool_false => continue, | |
| 177324 | else => unreachable, | |
| 177325 | }, | |
| 177326 | .repeated_elem => |elem| switch (elem) { | |
| 177327 | .bool_true => @panic("TODO"), | |
| 177328 | .bool_false => {}, | |
| 177329 | else => unreachable, | |
| 177330 | }, | |
| 177331 | .bytes => @panic("TODO"), | |
| 177297 | const clobbers_val: Value = .fromInterned(unwrapped_asm.clobbers); | |
| 177298 | const clobbers_ty = clobbers_val.typeOf(zcu); | |
| 177299 | var clobbers_bigint_buf: Value.BigIntSpace = undefined; | |
| 177300 | const clobbers_bigint = clobbers_val.toBigInt(&clobbers_bigint_buf, zcu); | |
| 177301 | for (0..clobbers_ty.structFieldCount(zcu)) |field_index| { | |
| 177302 | assert(clobbers_ty.fieldType(field_index, zcu).toIntern() == .bool_type); | |
| 177303 | const limb_bits = @bitSizeOf(std.math.big.Limb); | |
| 177304 | if (field_index / limb_bits >= clobbers_bigint.limbs.len) continue; // field is false | |
| 177305 | switch (@as(u1, @truncate(clobbers_bigint.limbs[field_index / limb_bits] >> @intCast(field_index % limb_bits)))) { | |
| 177306 | 0 => continue, // field is false | |
| 177307 | 1 => {}, // field is true | |
| 177308 | } | |
| 177309 | const clobber = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?; | |
| 177310 | assert(clobber.len != 0); | |
| 177311 | ||
| 177312 | if (std.mem.eql(u8, clobber, "memory") or | |
| 177313 | std.mem.eql(u8, clobber, "fpsr") or | |
| 177314 | std.mem.eql(u8, clobber, "fpcr") or | |
| 177315 | std.mem.eql(u8, clobber, "mxcsr") or | |
| 177316 | std.mem.eql(u8, clobber, "dirflag")) | |
| 177317 | { | |
| 177318 | // ok, sure | |
| 177319 | } else if (std.mem.eql(u8, clobber, "cc") or | |
| 177320 | std.mem.eql(u8, clobber, "flags") or | |
| 177321 | std.mem.eql(u8, clobber, "eflags") or | |
| 177322 | std.mem.eql(u8, clobber, "rflags")) | |
| 177323 | { | |
| 177324 | try self.spillEflagsIfOccupied(); | |
| 177325 | } else { | |
| 177326 | try self.register_manager.getReg(parseRegName(clobber) orelse | |
| 177327 | return self.fail("invalid clobber: '{s}'", .{clobber}), null); | |
| 177328 | } | |
| 177332 | 177329 | } |
| 177333 | 177330 | |
| 177334 | 177331 | const Label = struct { |
src/link/Dwarf.zig+11| ... | ... | @@ -3378,6 +3378,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo |
| 3378 | 3378 | .opt, |
| 3379 | 3379 | .aggregate, |
| 3380 | 3380 | .un, |
| 3381 | .bitpack, | |
| 3381 | 3382 | => .decl_const, |
| 3382 | 3383 | .variable => .decl_var, |
| 3383 | 3384 | .@"extern" => unreachable, |
| ... | ... | @@ -4014,6 +4015,7 @@ fn updateLazyType( |
| 4014 | 4015 | .opt, |
| 4015 | 4016 | .aggregate, |
| 4016 | 4017 | .un, |
| 4018 | .bitpack, | |
| 4017 | 4019 | // memoization, not types |
| 4018 | 4020 | .memoized_call, |
| 4019 | 4021 | => unreachable, |
| ... | ... | @@ -4092,6 +4094,15 @@ fn updateLazyValue( |
| 4092 | 4094 | }, .fromInterned(int.ty), Value.fromInterned(value_index).toBigInt(&big_int_space, zcu)); |
| 4093 | 4095 | try wip_nav.refType(.fromInterned(int.ty)); |
| 4094 | 4096 | }, |
| 4097 | .bitpack => |bitpack| { | |
| 4098 | const backing_int_val: Value = .fromInterned(bitpack.backing_int_val); | |
| 4099 | try wip_nav.bigIntConstValue(.{ | |
| 4100 | .sdata = .sdata_comptime_value, | |
| 4101 | .udata = .udata_comptime_value, | |
| 4102 | .block = .block_comptime_value, | |
| 4103 | }, backing_int_val.typeOf(zcu), backing_int_val.toBigInt(&big_int_space, zcu)); | |
| 4104 | try wip_nav.refType(.fromInterned(bitpack.ty)); | |
| 4105 | }, | |
| 4095 | 4106 | .err => |err| { |
| 4096 | 4107 | try wip_nav.abbrevCode(.udata_comptime_value); |
| 4097 | 4108 | try wip_nav.refType(.fromInterned(err.ty)); |
src/mutable_value.zig+15-11| ... | ... | @@ -97,8 +97,8 @@ pub const MutableValue = union(enum) { |
| 97 | 97 | /// * Non-error error unions use `eu_payload` |
| 98 | 98 | /// * Non-null optionals use `eu_payload |
| 99 | 99 | /// * Slices use `slice` |
| 100 | /// * Unions use `un` | |
| 101 | /// * Aggregates use `repeated` or `bytes` or `aggregate` | |
| 100 | /// * Unions use `un` (excluding packed unions) | |
| 101 | /// * Aggregates use `repeated` or `bytes` or `aggregate` (excluding packed structs) | |
| 102 | 102 | /// If `!allow_bytes`, the `bytes` representation will not be used. |
| 103 | 103 | /// If `!allow_repeated`, the `repeated` representation will not be used. |
| 104 | 104 | pub fn unintern( |
| ... | ... | @@ -209,6 +209,7 @@ pub const MutableValue = union(enum) { |
| 209 | 209 | .undef => |ty_ip| switch (Type.fromInterned(ty_ip).zigTypeTag(zcu)) { |
| 210 | 210 | .@"struct", .array, .vector => |type_tag| { |
| 211 | 211 | const ty = Type.fromInterned(ty_ip); |
| 212 | if (type_tag == .@"struct" and ty.containerLayout(zcu) == .@"packed") return; | |
| 212 | 213 | const opt_sent = ty.sentinel(zcu); |
| 213 | 214 | if (type_tag == .@"struct" or opt_sent != null or !allow_repeated) { |
| 214 | 215 | const len_no_sent = ip.aggregateTypeLen(ty_ip); |
| ... | ... | @@ -241,15 +242,18 @@ pub const MutableValue = union(enum) { |
| 241 | 242 | } }; |
| 242 | 243 | } |
| 243 | 244 | }, |
| 244 | .@"union" => { | |
| 245 | const payload = try arena.create(MutableValue); | |
| 246 | const backing_ty = try Type.fromInterned(ty_ip).unionBackingType(pt); | |
| 247 | payload.* = .{ .interned = try pt.intern(.{ .undef = backing_ty.toIntern() }) }; | |
| 248 | mv.* = .{ .un = .{ | |
| 249 | .ty = ty_ip, | |
| 250 | .tag = .none, | |
| 251 | .payload = payload, | |
| 252 | } }; | |
| 245 | .@"union" => switch (Type.fromInterned(ty_ip).containerLayout(zcu)) { | |
| 246 | .auto, .@"packed" => {}, | |
| 247 | .@"extern" => { | |
| 248 | const payload = try arena.create(MutableValue); | |
| 249 | const backing_ty = try Type.fromInterned(ty_ip).externUnionBackingType(pt); | |
| 250 | payload.* = .{ .interned = try pt.intern(.{ .undef = backing_ty.toIntern() }) }; | |
| 251 | mv.* = .{ .un = .{ | |
| 252 | .ty = ty_ip, | |
| 253 | .tag = .none, | |
| 254 | .payload = payload, | |
| 255 | } }; | |
| 256 | }, | |
| 253 | 257 | }, |
| 254 | 258 | .pointer => { |
| 255 | 259 | const ptr_ty = ip.indexToKey(ty_ip).ptr_type; |
src/print_value.zig+27-1| ... | ... | @@ -164,7 +164,7 @@ pub fn print( |
| 164 | 164 | return; |
| 165 | 165 | } |
| 166 | 166 | if (un.tag == .none) { |
| 167 | const backing_ty = try val.typeOf(zcu).unionBackingType(pt); | |
| 167 | const backing_ty = try val.typeOf(zcu).externUnionBackingType(pt); | |
| 168 | 168 | try writer.print("@bitCast(@as({f}, ", .{backing_ty.fmt(pt)}); |
| 169 | 169 | try print(Value.fromInterned(un.val), writer, level - 1, pt, opt_sema); |
| 170 | 170 | try writer.writeAll("))"); |
| ... | ... | @@ -176,6 +176,32 @@ pub fn print( |
| 176 | 176 | try writer.writeAll(" }"); |
| 177 | 177 | } |
| 178 | 178 | }, |
| 179 | .bitpack => |bitpack| { | |
| 180 | const ty: Type = .fromInterned(bitpack.ty); | |
| 181 | switch (ty.zigTypeTag(zcu)) { | |
| 182 | .@"struct" => { | |
| 183 | if (ty.structFieldCount(zcu) == 0) { | |
| 184 | return writer.writeAll(".{}"); | |
| 185 | } | |
| 186 | try writer.writeAll(".{ "); | |
| 187 | const max_len = @min(ty.structFieldCount(zcu), max_aggregate_items); | |
| 188 | for (0..max_len) |i| { | |
| 189 | if (i != 0) try writer.writeAll(", "); | |
| 190 | const field_name = ty.structFieldName(@intCast(i), zcu).unwrap().?; | |
| 191 | try writer.print(".{f} = ", .{field_name.fmt(ip)}); | |
| 192 | try print(try val.fieldValue(pt, i), writer, level - 1, pt, opt_sema); | |
| 193 | } | |
| 194 | try writer.writeAll(" }"); | |
| 195 | return; | |
| 196 | }, | |
| 197 | .@"union" => { | |
| 198 | try writer.print("@bitCast(@as({f}, ", .{ty.bitpackBackingInt(zcu).fmt(pt)}); | |
| 199 | try print(.fromInterned(bitpack.backing_int_val), writer, level - 1, pt, opt_sema); | |
| 200 | try writer.writeAll("))"); | |
| 201 | }, | |
| 202 | else => unreachable, | |
| 203 | } | |
| 204 | }, | |
| 179 | 205 | .memoized_call => unreachable, |
| 180 | 206 | } |
| 181 | 207 | } |