authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-01-08 06:38:47-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-01-16 20:47:30-05:00
log63730441d01a860a53d190e88079452947a4149d
tree54c74892ce56e92a69d821ca543f70b3deddc9a2
parent5069f574f43f1c9fe7ced12f9fd5f05bdedf6abb

x86_64: implement union access


4 files changed, 286 insertions(+), 71 deletions(-)

lib/std/debug.zig+1
......@@ -23,6 +23,7 @@ pub const Coverage = @import("debug/Coverage.zig");
2323
2424pub const FormattedPanic = @import("debug/FormattedPanic.zig");
2525pub const SimplePanic = @import("debug/SimplePanic.zig");
26pub const NoPanic = @import("debug/NoPanic.zig");
2627
2728/// Unresolved source locations can be represented with a single `usize` that
2829/// corresponds to a virtual memory address of the program counter. Combined
lib/std/debug/NoPanic.zig created+59
......@@ -0,0 +1,59 @@
1//! This namespace can be used with `pub const Panic = std.debug.NoPanic;` in the root file.
2//! It emits as little code as possible, for testing purposes.
3//!
4//! For a functional alternative, see `std.debug.FormattedPanic`.
5
6const std = @import("../std.zig");
7
8pub fn call(_: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
9 @branchHint(.cold);
10 @trap();
11}
12
13pub inline fn sentinelMismatch(_: anytype, _: anytype) noreturn {
14 @branchHint(.cold);
15 @trap();
16}
17
18pub inline fn unwrapError(_: ?*std.builtin.StackTrace, _: anyerror) noreturn {
19 @branchHint(.cold);
20 @trap();
21}
22
23pub inline fn outOfBounds(_: usize, _: usize) noreturn {
24 @branchHint(.cold);
25 @trap();
26}
27
28pub inline fn startGreaterThanEnd(_: usize, _: usize) noreturn {
29 @branchHint(.cold);
30 @trap();
31}
32
33pub inline fn inactiveUnionField(_: anytype, _: anytype) noreturn {
34 @branchHint(.cold);
35 @trap();
36}
37
38pub const messages = struct {
39 pub const reached_unreachable = "";
40 pub const unwrap_null = "";
41 pub const cast_to_null = "";
42 pub const incorrect_alignment = "";
43 pub const invalid_error_code = "";
44 pub const cast_truncated_data = "";
45 pub const negative_to_unsigned = "";
46 pub const integer_overflow = "";
47 pub const shl_overflow = "";
48 pub const shr_overflow = "";
49 pub const divide_by_zero = "";
50 pub const exact_division_remainder = "";
51 pub const integer_part_out_of_bounds = "";
52 pub const corrupt_switch = "";
53 pub const shift_rhs_too_big = "";
54 pub const invalid_enum_value = "";
55 pub const for_len_mismatch = "";
56 pub const memcpy_len_mismatch = "";
57 pub const memcpy_alias = "";
58 pub const noreturn_returned = "";
59};
src/arch/x86_64/CodeGen.zig+225-70
......@@ -2467,8 +2467,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
24672467 .memcpy => try cg.airMemcpy(inst),
24682468 .memset => try cg.airMemset(inst, false),
24692469 .memset_safe => try cg.airMemset(inst, true),
2470 .set_union_tag => try cg.airSetUnionTag(inst),
2471 .get_union_tag => try cg.airGetUnionTag(inst),
24722470 .ctz => try cg.airCtz(inst),
24732471 .popcount => try cg.airPopCount(inst),
24742472 .byte_swap => try cg.airByteSwap(inst),
......@@ -2480,7 +2478,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
24802478 .shuffle => try cg.airShuffle(inst),
24812479 .reduce => try cg.airReduce(inst),
24822480 .aggregate_init => try cg.airAggregateInit(inst),
2483 .union_init => try cg.airUnionInit(inst),
24842481 .prefetch => try cg.airPrefetch(inst),
24852482 .mul_add => try cg.airMulAdd(inst),
24862483
......@@ -2528,7 +2525,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
25282525 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
25292526 try ops[0].toSlicePtr(cg);
25302527 var res: [1]Temp = undefined;
2531 cg.select(&res, &.{cg.typeOfIndex(inst)}, &ops, comptime &.{ .{
2528 cg.select(&res, &.{ty_pl.ty.toType()}, &ops, comptime &.{ .{
25322529 .patterns = &.{
25332530 .{ .src = .{ .to_gpr, .simm32 } },
25342531 },
......@@ -2645,7 +2642,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
26452642 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
26462643 try ops[0].toSlicePtr(cg);
26472644 var res: [1]Temp = undefined;
2648 cg.select(&res, &.{cg.typeOfIndex(inst)}, &ops, comptime &.{ .{
2645 cg.select(&res, &.{ty_pl.ty.toType()}, &ops, comptime &.{ .{
26492646 .patterns = &.{
26502647 .{ .src = .{ .to_gpr, .simm32 } },
26512648 },
......@@ -2772,20 +2769,22 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
27722769 try res[0].moveTo(inst, cg);
27732770 },
27742771 .alloc => if (use_old) try cg.airAlloc(inst) else {
2775 var slot = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .lea_frame = .{
2772 const ty = air_datas[@intFromEnum(inst)].ty;
2773 var slot = try cg.tempInit(ty, .{ .lea_frame = .{
27762774 .index = try cg.allocMemPtr(inst),
27772775 } });
27782776 try slot.moveTo(inst, cg);
27792777 },
27802778 .inferred_alloc, .inferred_alloc_comptime => unreachable,
27812779 .ret_ptr => if (use_old) try cg.airRetPtr(inst) else {
2780 const ty = air_datas[@intFromEnum(inst)].ty;
27822781 var slot = switch (cg.ret_mcv.long) {
27832782 else => unreachable,
2784 .none => try cg.tempFromValue(cg.typeOfIndex(inst), .{ .lea_frame = .{
2783 .none => try cg.tempInit(ty, .{ .lea_frame = .{
27852784 .index = try cg.allocMemPtr(inst),
27862785 } }),
27872786 .load_frame => slot: {
2788 var slot = try cg.tempFromValue(cg.typeOfIndex(inst), cg.ret_mcv.long);
2787 var slot = try cg.tempInit(ty, cg.ret_mcv.long);
27892788 try slot.toOffset(cg.ret_mcv.short.indirect.off, cg);
27902789 break :slot slot;
27912790 },
......@@ -2797,7 +2796,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
27972796 const bin_op = air_datas[@intFromEnum(inst)].bin_op;
27982797 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
27992798 var res: [1]Temp = undefined;
2800 cg.select(&res, &.{cg.typeOfIndex(inst)}, &ops, switch (@as(Mir.Inst.Tag, switch (air_tag) {
2799 cg.select(&res, &.{cg.typeOf(bin_op.lhs)}, &ops, switch (@as(Mir.Inst.Tag, switch (air_tag) {
28012800 else => unreachable,
28022801 .bit_and => .@"and",
28032802 .bit_or => .@"or",
......@@ -3156,7 +3155,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
31563155 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
31573156 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
31583157 var res: [1]Temp = undefined;
3159 cg.select(&res, &.{cg.typeOfIndex(inst)}, &ops, comptime &.{ .{
3158 cg.select(&res, &.{ty_op.ty.toType()}, &ops, comptime &.{ .{
31603159 .src_constraints = .{ .{ .signed_or_exact_int = .byte }, .any },
31613160 .patterns = &.{
31623161 .{ .src = .{ .mut_mem, .none } },
......@@ -4239,14 +4238,14 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
42394238 .trap => try cg.asmOpOnly(.{ ._, .ud2 }),
42404239 .breakpoint => try cg.asmOpOnly(.{ ._, .int3 }),
42414240 .ret_addr => if (use_old) try cg.airRetAddr(inst) else {
4242 var slot = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .load_frame = .{
4241 var slot = try cg.tempInit(.usize, .{ .load_frame = .{
42434242 .index = .ret_addr,
42444243 } });
42454244 while (try slot.toRegClass(true, .general_purpose, cg)) {}
42464245 try slot.moveTo(inst, cg);
42474246 },
42484247 .frame_addr => if (use_old) try cg.airFrameAddress(inst) else {
4249 var slot = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .lea_frame = .{
4248 var slot = try cg.tempInit(.usize, .{ .lea_frame = .{
42504249 .index = .base_ptr,
42514250 } });
42524251 try slot.moveTo(inst, cg);
......@@ -4260,7 +4259,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
42604259 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
42614260 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
42624261 var res: [1]Temp = undefined;
4263 cg.select(&res, &.{cg.typeOfIndex(inst)}, &ops, comptime &.{ .{
4262 cg.select(&res, &.{ty_op.ty.toType()}, &ops, comptime &.{ .{
42644263 .required_features = .{ .slow_incdec, null, null, null },
42654264 .src_constraints = .{ .{ .exact_signed_int = 1 }, .any },
42664265 .patterns = &.{
......@@ -6997,7 +6996,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
69976996 switch (extra.compareOperator()) {
69986997 .lt => unreachable,
69996998 .lte => unreachable,
7000 .eq, .neq => |cmp_op| cg.select(&res, &.{cg.typeOfIndex(inst)}, &ops, switch (@as(Condition, switch (cmp_op) {
6999 .eq, .neq => |cmp_op| cg.select(&res, &.{ty_pl.ty.toType()}, &ops, switch (@as(Condition, switch (cmp_op) {
70017000 else => unreachable,
70027001 .eq => .e,
70037002 .neq => .ne,
......@@ -8825,7 +8824,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
88258824 .unsigned;
88268825 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
88278826 var res: [1]Temp = undefined;
8828 cg.select(&res, &.{cg.typeOfIndex(inst)}, &ops, switch (@as(Condition, switch (signedness) {
8827 cg.select(&res, &.{.bool}, &ops, switch (@as(Condition, switch (signedness) {
88298828 .signed => switch (air_tag) {
88308829 else => unreachable,
88318830 .cmp_lt, .cmp_lt_optimized => .l,
......@@ -9011,7 +9010,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
90119010 });
90129011 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
90139012 var res: [1]Temp = undefined;
9014 cg.select(&res, &.{cg.typeOfIndex(inst)}, &ops, switch (@as(Condition, switch (air_tag) {
9013 cg.select(&res, &.{.bool}, &ops, switch (@as(Condition, switch (air_tag) {
90159014 else => unreachable,
90169015 .cmp_eq, .cmp_eq_optimized => .e,
90179016 .cmp_neq, .cmp_neq_optimized => .ne,
......@@ -9540,7 +9539,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
95409539 .fromSize(opt_child_abi_size) }),
95419540 .u(0),
95429541 );
9543 var is_null = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .eflags = .e });
9542 var is_null = try cg.tempInit(.bool, .{ .eflags = .e });
95449543 try ops[0].die(cg);
95459544 try is_null.moveTo(inst, cg);
95469545 },
......@@ -9563,7 +9562,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
95639562 .fromSize(opt_child_abi_size) }),
95649563 .u(0),
95659564 );
9566 var is_non_null = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .eflags = .ne });
9565 var is_non_null = try cg.tempInit(.bool, .{ .eflags = .ne });
95679566 try ops[0].die(cg);
95689567 try is_non_null.moveTo(inst, cg);
95699568 },
......@@ -9581,7 +9580,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
95819580 try ops[0].tracking(cg).short.deref().mem(cg, .{ .size = cg.memSize(eu_err_ty) }),
95829581 .u(0),
95839582 );
9584 var is_err = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .eflags = .ne });
9583 var is_err = try cg.tempInit(.bool, .{ .eflags = .ne });
95859584 try ops[0].die(cg);
95869585 try is_err.moveTo(inst, cg);
95879586 },
......@@ -9599,7 +9598,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
95999598 try ops[0].tracking(cg).short.deref().mem(cg, .{ .size = cg.memSize(eu_err_ty) }),
96009599 .u(0),
96019600 );
9602 var is_non_err = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .eflags = .e });
9601 var is_non_err = try cg.tempInit(.bool, .{ .eflags = .e });
96039602 try ops[0].die(cg);
96049603 try is_non_err.moveTo(inst, cg);
96059604 },
......@@ -9631,8 +9630,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
96319630 const opt_child_ty = opt_ty.optionalChild(zcu);
96329631 const opt_child_abi_size: i32 = @intCast(opt_child_ty.abiSize(zcu));
96339632 try ops[0].toOffset(opt_child_abi_size, cg);
9634 var has_value = try cg.tempFromValue(.bool, .{ .immediate = 1 });
9635 try ops[0].store(&has_value, cg);
9633 var has_value = try cg.tempInit(.bool, .{ .immediate = 1 });
9634 try ops[0].store(0, &has_value, cg);
96369635 try has_value.die(cg);
96379636 try ops[0].toOffset(-opt_child_abi_size, cg);
96389637 }
......@@ -9654,7 +9653,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
96549653 const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu));
96559654 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
96569655 try ops[0].toOffset(eu_err_off, cg);
9657 var err = try ops[0].load(eu_ty.errorUnionSet(zcu), cg);
9656 var err = try ops[0].load(0, eu_ty.errorUnionSet(zcu), cg);
96589657 try ops[0].die(cg);
96599658 try err.moveTo(inst, cg);
96609659 },
......@@ -9667,8 +9666,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
96679666 const eu_pl_off: i32 = @intCast(codegen.errUnionPayloadOffset(eu_pl_ty, zcu));
96689667 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
96699668 try ops[0].toOffset(eu_err_off, cg);
9670 var no_err = try cg.tempFromValue(eu_err_ty, .{ .immediate = 0 });
9671 try ops[0].store(&no_err, cg);
9669 var no_err = try cg.tempInit(eu_err_ty, .{ .immediate = 0 });
9670 try ops[0].store(0, &no_err, cg);
96729671 try no_err.die(cg);
96739672 try ops[0].toOffset(eu_pl_off - eu_err_off, cg);
96749673 try ops[0].moveTo(inst, cg);
......@@ -9679,7 +9678,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
96799678 var ops = try cg.tempsFromOperands(inst, .{extra.struct_operand});
96809679 try ops[0].toOffset(cg.fieldOffset(
96819680 cg.typeOf(extra.struct_operand),
9682 cg.typeOfIndex(inst),
9681 ty_pl.ty.toType(),
96839682 extra.field_index,
96849683 ), cg);
96859684 try ops[0].moveTo(inst, cg);
......@@ -9689,7 +9688,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
96899688 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
96909689 try ops[0].toOffset(cg.fieldOffset(
96919690 cg.typeOf(ty_op.operand),
9692 cg.typeOfIndex(inst),
9691 ty_op.ty.toType(),
96939692 0,
96949693 ), cg);
96959694 try ops[0].moveTo(inst, cg);
......@@ -9699,7 +9698,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
96999698 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
97009699 try ops[0].toOffset(cg.fieldOffset(
97019700 cg.typeOf(ty_op.operand),
9702 cg.typeOfIndex(inst),
9701 ty_op.ty.toType(),
97039702 1,
97049703 ), cg);
97059704 try ops[0].moveTo(inst, cg);
......@@ -9709,7 +9708,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
97099708 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
97109709 try ops[0].toOffset(cg.fieldOffset(
97119710 cg.typeOf(ty_op.operand),
9712 cg.typeOfIndex(inst),
9711 ty_op.ty.toType(),
97139712 2,
97149713 ), cg);
97159714 try ops[0].moveTo(inst, cg);
......@@ -9719,11 +9718,29 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
97199718 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
97209719 try ops[0].toOffset(cg.fieldOffset(
97219720 cg.typeOf(ty_op.operand),
9722 cg.typeOfIndex(inst),
9721 ty_op.ty.toType(),
97239722 3,
97249723 ), cg);
97259724 try ops[0].moveTo(inst, cg);
97269725 },
9726 .set_union_tag => if (use_old) try cg.airSetUnionTag(inst) else {
9727 const bin_op = air_datas[@intFromEnum(inst)].bin_op;
9728 const union_ty = cg.typeOf(bin_op.lhs).childType(zcu);
9729 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
9730 const union_layout = union_ty.unionGetLayout(zcu);
9731 if (union_layout.tag_size > 0) try ops[0].store(@intCast(union_layout.tagOffset()), &ops[1], cg);
9732 for (ops) |op| try op.die(cg);
9733 },
9734 .get_union_tag => if (use_old) try cg.airGetUnionTag(inst) else {
9735 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
9736 const union_ty = cg.typeOf(ty_op.operand);
9737 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
9738 const union_layout = union_ty.unionGetLayout(zcu);
9739 assert(union_layout.tag_size > 0);
9740 var res = try ops[0].read(@intCast(union_layout.tagOffset()), ty_op.ty.toType(), cg);
9741 for (ops) |op| if (op.index != res.index) try op.die(cg);
9742 try res.moveTo(inst, cg);
9743 },
97279744 .slice => if (use_old) try cg.airSlice(inst) else {
97289745 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
97299746 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
......@@ -9764,7 +9781,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
97649781 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
97659782 try ops[0].toSlicePtr(cg);
97669783 var res: [1]Temp = undefined;
9767 const res_ty = cg.typeOfIndex(inst);
9784 const res_ty = cg.typeOf(bin_op.lhs).elemType2(zcu);
97689785 cg.select(&res, &.{res_ty}, &ops, comptime &.{ .{
97699786 .dst_constraints = .{.{ .int = .byte }},
97709787 .patterns = &.{
......@@ -9840,7 +9857,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
98409857 } },
98419858 } }) catch |err| switch (err) {
98429859 error.SelectFailed => switch (res_ty.abiSize(zcu)) {
9843 0 => res[0] = try cg.tempFromValue(res_ty, .none),
9860 0 => res[0] = try cg.tempInit(res_ty, .none),
98449861 else => |elem_size| {
98459862 while (true) for (&ops) |*op| {
98469863 if (try op.toRegClass(true, .general_purpose, cg)) break;
......@@ -9878,7 +9895,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
98789895 .scale = .fromFactor(@intCast(elem_size)),
98799896 } },
98809897 });
9881 res[0] = try ops[0].load(res_ty, cg);
9898 res[0] = try ops[0].load(0, res_ty, cg);
98829899 },
98839900 },
98849901 else => |e| return e,
......@@ -9897,7 +9914,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
98979914 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
98989915 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
98999916 try ops[0].toSlicePtr(cg);
9900 const dst_ty = cg.typeOfIndex(inst);
9917 const dst_ty = ty_pl.ty.toType();
99019918 if (dst_ty.ptrInfo(zcu).flags.vector_index == .none) zero_offset: {
99029919 const elem_size = dst_ty.childType(zcu).abiSize(zcu);
99039920 if (elem_size == 0) break :zero_offset;
......@@ -9944,19 +9961,38 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
99449961 .array_to_slice => if (use_old) try cg.airArrayToSlice(inst) else {
99459962 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
99469963 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
9947 var len = try cg.tempFromValue(.usize, .{
9964 var len = try cg.tempInit(.usize, .{
99489965 .immediate = cg.typeOf(ty_op.operand).childType(zcu).arrayLen(zcu),
99499966 });
99509967 try ops[0].toPair(&len, cg);
99519968 try ops[0].moveTo(inst, cg);
99529969 },
99539970 .error_set_has_value => return cg.fail("TODO implement error_set_has_value", .{}),
9971 .union_init => if (use_old) try cg.airUnionInit(inst) else {
9972 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
9973 const extra = cg.air.extraData(Air.UnionInit, ty_pl.payload).data;
9974 const union_ty = ty_pl.ty.toType();
9975 var ops = try cg.tempsFromOperands(inst, .{extra.init});
9976 var res = try cg.tempAllocMem(union_ty);
9977 const union_layout = union_ty.unionGetLayout(zcu);
9978 if (union_layout.tag_size > 0) {
9979 var tag_temp = try cg.tempFromValue(try pt.enumValueFieldIndex(
9980 union_ty.unionTagTypeSafety(zcu).?,
9981 extra.field_index,
9982 ));
9983 try res.write(@intCast(union_layout.tagOffset()), &tag_temp, cg);
9984 try tag_temp.die(cg);
9985 }
9986 try res.write(@intCast(union_layout.payloadOffset()), &ops[0], cg);
9987 try ops[0].die(cg);
9988 try res.moveTo(inst, cg);
9989 },
99549990 .field_parent_ptr => if (use_old) try cg.airFieldParentPtr(inst) else {
99559991 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
99569992 const extra = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
99579993 var ops = try cg.tempsFromOperands(inst, .{extra.field_ptr});
99589994 try ops[0].toOffset(-cg.fieldOffset(
9959 cg.typeOfIndex(inst),
9995 ty_pl.ty.toType(),
99609996 cg.typeOf(extra.field_ptr),
99619997 extra.field_index,
99629998 ), cg);
......@@ -10273,7 +10309,7 @@ fn allocRegOrMemAdvanced(self: *CodeGen, ty: Type, inst: ?Air.Inst.Index, reg_ok
1027310309 };
1027410310
1027510311 if (reg_ok) need_mem: {
10276 if (abi_size <= @as(u32, switch (ty.zigTypeTag(zcu)) {
10312 if (std.math.isPowerOfTwo(abi_size) and abi_size <= @as(u32, switch (ty.zigTypeTag(zcu)) {
1027710313 .float => switch (ty.floatBits(self.target.*)) {
1027810314 16, 32, 64, 128 => 16,
1027910315 80 => break :need_mem,
......@@ -11042,7 +11078,8 @@ fn airTrunc(self: *CodeGen, inst: Air.Inst.Index) !void {
1104211078 if (src_mcv.getReg()) |reg| self.register_manager.lockRegAssumeUnused(reg) else null;
1104311079 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
1104411080
11045 const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
11081 const dst_mcv = if (src_mcv.isRegister() and src_mcv.getReg().?.class() == self.regClassForType(dst_ty) and
11082 self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
1104611083 src_mcv
1104711084 else if (dst_abi_size <= 8)
1104811085 try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv)
......@@ -15513,12 +15550,12 @@ fn airLoad(self: *CodeGen, inst: Air.Inst.Index) !void {
1551315550 const ptr_ty = self.typeOf(ty_op.operand);
1551415551 const elem_size = elem_ty.abiSize(zcu);
1551515552
15516 const elem_rc = self.regSetForType(elem_ty);
15517 const ptr_rc = self.regSetForType(ptr_ty);
15553 const elem_rs = self.regSetForType(elem_ty);
15554 const ptr_rs = self.regSetForType(ptr_ty);
1551815555
1551915556 const ptr_mcv = try self.resolveInst(ty_op.operand);
15520 const dst_mcv = if (elem_size <= 8 and elem_rc.supersetOf(ptr_rc) and
15521 self.reuseOperand(inst, ty_op.operand, 0, ptr_mcv))
15557 const dst_mcv = if (elem_size <= 8 and std.math.isPowerOfTwo(elem_size) and
15558 elem_rs.supersetOf(ptr_rs) and self.reuseOperand(inst, ty_op.operand, 0, ptr_mcv))
1552215559 // The MCValue that holds the pointer can be re-used as the value.
1552315560 ptr_mcv
1552415561 else
......@@ -28295,17 +28332,19 @@ const Temp = struct {
2829528332 return true;
2829628333 }
2829728334
28298 fn load(ptr: *Temp, val_ty: Type, cg: *CodeGen) !Temp {
28335 fn load(ptr: *Temp, disp: i32, val_ty: Type, cg: *CodeGen) !Temp {
2829928336 const val = try cg.tempAlloc(val_ty);
28300 switch (val.tracking(cg).short) {
28337 const val_mcv = val.tracking(cg).short;
28338 switch (val_mcv) {
2830128339 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
2830228340 .register => |val_reg| {
2830328341 while (try ptr.toLea(cg)) {}
28304 try cg.genSetReg(val_reg, val_ty, ptr.tracking(cg).short.deref(), .{});
28342 try cg.genSetReg(val_reg, val_ty, ptr.tracking(cg).short.offset(disp).deref(), .{});
2830528343 },
28306 .load_frame => |val_frame_addr| {
28307 var val_ptr = try cg.tempFromValue(.usize, .{ .lea_frame = val_frame_addr });
28308 var len = try cg.tempFromValue(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });
28344 .memory, .indirect, .load_frame, .load_symbol => {
28345 try ptr.toOffset(disp, cg);
28346 var val_ptr = try cg.tempInit(.usize, val_mcv.address());
28347 var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });
2830928348 try val_ptr.memcpy(ptr, &len, cg);
2831028349 try val_ptr.die(cg);
2831128350 try len.die(cg);
......@@ -28314,27 +28353,38 @@ const Temp = struct {
2831428353 return val;
2831528354 }
2831628355
28317 fn store(ptr: *Temp, val: *Temp, cg: *CodeGen) !void {
28356 fn store(ptr: *Temp, disp: i32, val: *Temp, cg: *CodeGen) !void {
2831828357 const val_ty = val.typeOf(cg);
28319 const val_abi_size: u32 = @intCast(val_ty.abiSize(cg.pt.zcu));
2832028358 val: switch (val.tracking(cg).short) {
2832128359 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
28322 .immediate => |imm| if (std.math.cast(i32, imm)) |s| {
28360 .immediate => |val_imm| {
28361 const val_op: Immediate = if (std.math.cast(u32, val_imm)) |val_uimm32|
28362 .u(val_uimm32)
28363 else if (std.math.cast(i32, @as(i64, @bitCast(val_imm)))) |val_simm32|
28364 .s(val_simm32)
28365 else
28366 continue :val .{ .register = undefined };
2832328367 while (try ptr.toLea(cg)) {}
2832428368 try cg.asmMemoryImmediate(
2832528369 .{ ._, .mov },
28326 try ptr.tracking(cg).short.deref().mem(cg, .{ .size = cg.memSize(val_ty) }),
28327 .s(s),
28370 try ptr.tracking(cg).short.deref().mem(cg, .{
28371 .size = cg.memSize(val_ty),
28372 .disp = disp,
28373 }),
28374 val_op,
2832828375 );
28329 } else continue :val .{ .register = undefined },
28376 },
2833028377 .register => {
2833128378 while (try ptr.toLea(cg) or try val.toRegClass(true, .general_purpose, cg)) {}
2833228379 const val_reg = val.tracking(cg).short.register;
2833328380 switch (val_reg.class()) {
2833428381 .general_purpose => try cg.asmMemoryRegister(
2833528382 .{ ._, .mov },
28336 try ptr.tracking(cg).short.deref().mem(cg, .{ .size = cg.memSize(val_ty) }),
28337 registerAlias(val_reg, val_abi_size),
28383 try ptr.tracking(cg).short.deref().mem(cg, .{
28384 .size = cg.memSize(val_ty),
28385 .disp = disp,
28386 }),
28387 registerAlias(val_reg, @intCast(val_ty.abiSize(cg.pt.zcu))),
2833828388 ),
2833928389 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
2834028390 }
......@@ -28342,6 +28392,111 @@ const Temp = struct {
2834228392 }
2834328393 }
2834428394
28395 fn read(src: *Temp, disp: i32, val_ty: Type, cg: *CodeGen) !Temp {
28396 const val = try cg.tempAlloc(val_ty);
28397 while (try src.toBase(cg)) {}
28398 const val_mcv = val.tracking(cg).short;
28399 switch (val_mcv) {
28400 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
28401 .register => |val_reg| try src.readReg(disp, val_ty, registerAlias(
28402 val_reg,
28403 @intCast(val_ty.abiSize(cg.pt.zcu)),
28404 ), cg),
28405 }
28406 return val;
28407 }
28408
28409 fn readReg(src: Temp, disp: i32, dst_ty: Type, dst_reg: Register, cg: *CodeGen) !void {
28410 const strat = try cg.moveStrategy(dst_ty, dst_reg.class(), false);
28411 try strat.read(cg, dst_reg, try src.tracking(cg).short.mem(cg, .{
28412 .size = .fromBitSize(@min(8 * dst_ty.abiSize(cg.pt.zcu), dst_reg.bitSize())),
28413 .disp = disp,
28414 }));
28415 }
28416
28417 fn write(dst: *Temp, disp: i32, val: *Temp, cg: *CodeGen) !void {
28418 const val_ty = val.typeOf(cg);
28419 while (try dst.toBase(cg)) {}
28420 val_to_gpr: while (true) : (while (try val.toRegClass(false, .general_purpose, cg)) {}) {
28421 const val_mcv = val.tracking(cg).short;
28422 switch (val_mcv) {
28423 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
28424 .immediate => |val_imm| {
28425 const val_op: Immediate = if (std.math.cast(u32, val_imm)) |val_uimm32|
28426 .u(val_uimm32)
28427 else if (std.math.cast(i32, @as(i64, @bitCast(val_imm)))) |val_simm32|
28428 .s(val_simm32)
28429 else
28430 continue :val_to_gpr;
28431 try cg.asmMemoryImmediate(
28432 .{ ._, .mov },
28433 try dst.tracking(cg).short.mem(cg, .{
28434 .size = cg.memSize(val_ty),
28435 .disp = disp,
28436 }),
28437 val_op,
28438 );
28439 },
28440 .register => |val_reg| try dst.writeReg(disp, val_ty, registerAlias(
28441 val_reg,
28442 @intCast(val_ty.abiSize(cg.pt.zcu)),
28443 ), cg),
28444 inline .register_pair, .register_triple, .register_quadruple => |val_regs| {
28445 var part_disp = disp;
28446 for (val_regs) |val_reg| {
28447 try dst.writeReg(part_disp, val_ty, val_reg, cg);
28448 part_disp += @divExact(val_reg.bitSize(), 8);
28449 }
28450 },
28451 .register_offset => |val_reg_off| switch (val_reg_off.off) {
28452 0 => try dst.writeReg(disp, val_ty, registerAlias(
28453 val_reg_off.reg,
28454 @intCast(val_ty.abiSize(cg.pt.zcu)),
28455 ), cg),
28456 else => continue :val_to_gpr,
28457 },
28458 .lea_frame, .lea_symbol => continue :val_to_gpr,
28459 .memory, .indirect, .load_frame, .load_symbol => {
28460 var dst_ptr = try cg.tempInit(.usize, dst.tracking(cg).short.address().offset(disp));
28461 var val_ptr = try cg.tempInit(.usize, val_mcv.address());
28462 var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });
28463 try dst_ptr.memcpy(&val_ptr, &len, cg);
28464 try dst_ptr.die(cg);
28465 try val_ptr.die(cg);
28466 try len.die(cg);
28467 },
28468 }
28469 break;
28470 }
28471 }
28472
28473 fn writeReg(dst: Temp, disp: i32, src_ty: Type, src_reg: Register, cg: *CodeGen) !void {
28474 const src_rc = src_reg.class();
28475 const src_abi_size = src_ty.abiSize(cg.pt.zcu);
28476 const strat = try cg.moveStrategy(src_ty, src_rc, false);
28477 if (src_rc == .x87 or std.math.isPowerOfTwo(src_abi_size)) {
28478 try strat.write(cg, try dst.tracking(cg).short.mem(cg, .{
28479 .size = .fromBitSize(@min(8 * src_abi_size, src_reg.bitSize())),
28480 .disp = disp,
28481 }), src_reg);
28482 } else {
28483 const frame_alloc: FrameAlloc = .initSpill(src_ty, cg.pt.zcu);
28484 const frame_index = try cg.allocFrameIndex(frame_alloc);
28485 const frame_size: Memory.Size = .fromSize(frame_alloc.abi_size);
28486 try strat.write(cg, .{
28487 .base = .{ .frame = frame_index },
28488 .mod = .{ .rm = .{ .size = frame_size } },
28489 }, src_reg);
28490 var dst_ptr = try cg.tempInit(.usize, dst.tracking(cg).short.address());
28491 var src_ptr = try cg.tempInit(.usize, .{ .lea_frame = .{ .index = frame_index } });
28492 var len = try cg.tempInit(.usize, .{ .immediate = src_abi_size });
28493 try dst_ptr.memcpy(&src_ptr, &len, cg);
28494 try dst_ptr.die(cg);
28495 try src_ptr.die(cg);
28496 try len.die(cg);
28497 }
28498 }
28499
2834528500 fn memcpy(dst: *Temp, src: *Temp, len: *Temp, cg: *CodeGen) !void {
2834628501 while (true) for ([_]*Temp{ dst, src, len }, [_]Register{ .rdi, .rsi, .rcx }) |temp, reg| {
2834728502 if (try temp.toReg(reg, cg)) break;
......@@ -28498,7 +28653,7 @@ fn tempAllocMem(cg: *CodeGen, ty: Type) !Temp {
2849828653 return .{ .index = temp_index.toIndex() };
2849928654}
2850028655
28501fn tempFromValue(cg: *CodeGen, ty: Type, value: MCValue) !Temp {
28656fn tempInit(cg: *CodeGen, ty: Type, value: MCValue) !Temp {
2850228657 const temp_index = cg.next_temp_index;
2850328658 temp_index.tracking(cg).* = .init(value);
2850428659 cg.temp_type[@intFromEnum(temp_index)] = ty;
......@@ -28507,6 +28662,10 @@ fn tempFromValue(cg: *CodeGen, ty: Type, value: MCValue) !Temp {
2850728662 return .{ .index = temp_index.toIndex() };
2850828663}
2850928664
28665fn tempFromValue(cg: *CodeGen, value: Value) !Temp {
28666 return cg.tempInit(value.typeOf(cg.pt.zcu), try cg.genTypedValue(value));
28667}
28668
2851028669fn tempFromOperand(
2851128670 cg: *CodeGen,
2851228671 inst: Air.Inst.Index,
......@@ -28549,7 +28708,7 @@ fn tempFromOperand(
2854928708 else => break :init const_mcv,
2855028709 }
2855128710 });
28552 return cg.tempFromValue(.fromInterned(ip.typeOf(val)), gop.value_ptr.short);
28711 return cg.tempInit(.fromInterned(ip.typeOf(val)), gop.value_ptr.short);
2855328712 }
2855428713
2855528714 const temp_index = cg.next_temp_index;
......@@ -29023,8 +29182,8 @@ const Select = struct {
2902329182 return switch (spec.kind) {
2902429183 .unused => null,
2902529184 .any => try cg.tempAlloc(spec.type),
29026 .cc => |cc| try cg.tempFromValue(spec.type, .{ .eflags = cc }),
29027 .reg => |reg| try cg.tempFromValue(spec.type, .{ .register = reg }),
29185 .cc => |cc| try cg.tempInit(spec.type, .{ .eflags = cc }),
29186 .reg => |reg| try cg.tempInit(spec.type, .{ .register = reg }),
2902829187 .rc => |rc| try cg.tempAllocReg(spec.type, regSetForRegClass(rc)),
2902929188 .rc_mask => |rc_mask| try cg.tempAllocReg(spec.type, regSetForRegClass(rc_mask.rc)),
2903029189 .mem => try cg.tempAllocMem(spec.type),
......@@ -29081,18 +29240,14 @@ const Select = struct {
2908129240 break :res_scalar .{ scalar_int_ty, try pt.intValue_big(scalar_int_ty, big_int.toConst()) };
2908229241 },
2908329242 };
29084 const res_ty, const res_val: Value = if (vector_len) |len| res: {
29085 const vector_ty = try pt.vectorType(.{
29243 const res_val: Value = if (vector_len) |len| .fromInterned(try pt.intern(.{ .aggregate = .{
29244 .ty = (try pt.vectorType(.{
2908629245 .len = len,
2908729246 .child = res_scalar_ty.toIntern(),
29088 });
29089 const vector_val = try pt.intern(.{ .aggregate = .{
29090 .ty = vector_ty.toIntern(),
29091 .storage = .{ .repeated_elem = res_scalar_val.toIntern() },
29092 } });
29093 break :res .{ vector_ty, .fromInterned(vector_val) };
29094 } else .{ res_scalar_ty, res_scalar_val };
29095 return try cg.tempFromValue(res_ty, try cg.genTypedValue(res_val));
29247 })).toIntern(),
29248 .storage = .{ .repeated_elem = res_scalar_val.toIntern() },
29249 } })) else res_scalar_val;
29250 return try cg.tempFromValue(res_val);
2909629251 },
2909729252 .ref => |ref| ref.deref(s),
2909829253 .ref_mask => |ref_mask| ref_mask.ref.deref(s),
test/behavior/union.zig+1-1
......@@ -2246,12 +2246,12 @@ test "matching captures causes union equivalence" {
22462246}
22472247
22482248test "signed enum tag with negative value" {
2249 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
22502249 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
22512250 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
22522251 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
22532252 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
22542253 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2254 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
22552255
22562256 const Enum = enum(i8) {
22572257 a = -1,