Commit 63730441d0
Changed files (4)
lib/std/debug/NoPanic.zig
@@ -0,0 +1,59 @@
+//! This namespace can be used with `pub const Panic = std.debug.NoPanic;` in the root file.
+//! It emits as little code as possible, for testing purposes.
+//!
+//! For a functional alternative, see `std.debug.FormattedPanic`.
+
+const std = @import("../std.zig");
+
+pub fn call(_: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub inline fn sentinelMismatch(_: anytype, _: anytype) noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub inline fn unwrapError(_: ?*std.builtin.StackTrace, _: anyerror) noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub inline fn outOfBounds(_: usize, _: usize) noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub inline fn startGreaterThanEnd(_: usize, _: usize) noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub inline fn inactiveUnionField(_: anytype, _: anytype) noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub const messages = struct {
+ pub const reached_unreachable = "";
+ pub const unwrap_null = "";
+ pub const cast_to_null = "";
+ pub const incorrect_alignment = "";
+ pub const invalid_error_code = "";
+ pub const cast_truncated_data = "";
+ pub const negative_to_unsigned = "";
+ pub const integer_overflow = "";
+ pub const shl_overflow = "";
+ pub const shr_overflow = "";
+ pub const divide_by_zero = "";
+ pub const exact_division_remainder = "";
+ pub const integer_part_out_of_bounds = "";
+ pub const corrupt_switch = "";
+ pub const shift_rhs_too_big = "";
+ pub const invalid_enum_value = "";
+ pub const for_len_mismatch = "";
+ pub const memcpy_len_mismatch = "";
+ pub const memcpy_alias = "";
+ pub const noreturn_returned = "";
+};
lib/std/debug.zig
@@ -23,6 +23,7 @@ pub const Coverage = @import("debug/Coverage.zig");
pub const FormattedPanic = @import("debug/FormattedPanic.zig");
pub const SimplePanic = @import("debug/SimplePanic.zig");
+pub const NoPanic = @import("debug/NoPanic.zig");
/// Unresolved source locations can be represented with a single `usize` that
/// corresponds to a virtual memory address of the program counter. Combined
src/arch/x86_64/CodeGen.zig
@@ -2467,8 +2467,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.memcpy => try cg.airMemcpy(inst),
.memset => try cg.airMemset(inst, false),
.memset_safe => try cg.airMemset(inst, true),
- .set_union_tag => try cg.airSetUnionTag(inst),
- .get_union_tag => try cg.airGetUnionTag(inst),
.ctz => try cg.airCtz(inst),
.popcount => try cg.airPopCount(inst),
.byte_swap => try cg.airByteSwap(inst),
@@ -2480,7 +2478,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.shuffle => try cg.airShuffle(inst),
.reduce => try cg.airReduce(inst),
.aggregate_init => try cg.airAggregateInit(inst),
- .union_init => try cg.airUnionInit(inst),
.prefetch => try cg.airPrefetch(inst),
.mul_add => try cg.airMulAdd(inst),
@@ -2528,7 +2525,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
try ops[0].toSlicePtr(cg);
var res: [1]Temp = undefined;
- cg.select(&res, &.{cg.typeOfIndex(inst)}, &ops, comptime &.{ .{
+ cg.select(&res, &.{ty_pl.ty.toType()}, &ops, comptime &.{ .{
.patterns = &.{
.{ .src = .{ .to_gpr, .simm32 } },
},
@@ -2645,7 +2642,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
try ops[0].toSlicePtr(cg);
var res: [1]Temp = undefined;
- cg.select(&res, &.{cg.typeOfIndex(inst)}, &ops, comptime &.{ .{
+ cg.select(&res, &.{ty_pl.ty.toType()}, &ops, comptime &.{ .{
.patterns = &.{
.{ .src = .{ .to_gpr, .simm32 } },
},
@@ -2772,20 +2769,22 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
try res[0].moveTo(inst, cg);
},
.alloc => if (use_old) try cg.airAlloc(inst) else {
- var slot = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .lea_frame = .{
+ const ty = air_datas[@intFromEnum(inst)].ty;
+ var slot = try cg.tempInit(ty, .{ .lea_frame = .{
.index = try cg.allocMemPtr(inst),
} });
try slot.moveTo(inst, cg);
},
.inferred_alloc, .inferred_alloc_comptime => unreachable,
.ret_ptr => if (use_old) try cg.airRetPtr(inst) else {
+ const ty = air_datas[@intFromEnum(inst)].ty;
var slot = switch (cg.ret_mcv.long) {
else => unreachable,
- .none => try cg.tempFromValue(cg.typeOfIndex(inst), .{ .lea_frame = .{
+ .none => try cg.tempInit(ty, .{ .lea_frame = .{
.index = try cg.allocMemPtr(inst),
} }),
.load_frame => slot: {
- var slot = try cg.tempFromValue(cg.typeOfIndex(inst), cg.ret_mcv.long);
+ var slot = try cg.tempInit(ty, cg.ret_mcv.long);
try slot.toOffset(cg.ret_mcv.short.indirect.off, cg);
break :slot slot;
},
@@ -2797,7 +2796,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
const bin_op = air_datas[@intFromEnum(inst)].bin_op;
var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
var res: [1]Temp = undefined;
- cg.select(&res, &.{cg.typeOfIndex(inst)}, &ops, switch (@as(Mir.Inst.Tag, switch (air_tag) {
+ cg.select(&res, &.{cg.typeOf(bin_op.lhs)}, &ops, switch (@as(Mir.Inst.Tag, switch (air_tag) {
else => unreachable,
.bit_and => .@"and",
.bit_or => .@"or",
@@ -3156,7 +3155,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
const ty_op = air_datas[@intFromEnum(inst)].ty_op;
var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
var res: [1]Temp = undefined;
- cg.select(&res, &.{cg.typeOfIndex(inst)}, &ops, comptime &.{ .{
+ cg.select(&res, &.{ty_op.ty.toType()}, &ops, comptime &.{ .{
.src_constraints = .{ .{ .signed_or_exact_int = .byte }, .any },
.patterns = &.{
.{ .src = .{ .mut_mem, .none } },
@@ -4239,14 +4238,14 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.trap => try cg.asmOpOnly(.{ ._, .ud2 }),
.breakpoint => try cg.asmOpOnly(.{ ._, .int3 }),
.ret_addr => if (use_old) try cg.airRetAddr(inst) else {
- var slot = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .load_frame = .{
+ var slot = try cg.tempInit(.usize, .{ .load_frame = .{
.index = .ret_addr,
} });
while (try slot.toRegClass(true, .general_purpose, cg)) {}
try slot.moveTo(inst, cg);
},
.frame_addr => if (use_old) try cg.airFrameAddress(inst) else {
- var slot = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .lea_frame = .{
+ var slot = try cg.tempInit(.usize, .{ .lea_frame = .{
.index = .base_ptr,
} });
try slot.moveTo(inst, cg);
@@ -4260,7 +4259,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
const ty_op = air_datas[@intFromEnum(inst)].ty_op;
var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
var res: [1]Temp = undefined;
- cg.select(&res, &.{cg.typeOfIndex(inst)}, &ops, comptime &.{ .{
+ cg.select(&res, &.{ty_op.ty.toType()}, &ops, comptime &.{ .{
.required_features = .{ .slow_incdec, null, null, null },
.src_constraints = .{ .{ .exact_signed_int = 1 }, .any },
.patterns = &.{
@@ -6997,7 +6996,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
switch (extra.compareOperator()) {
.lt => unreachable,
.lte => unreachable,
- .eq, .neq => |cmp_op| cg.select(&res, &.{cg.typeOfIndex(inst)}, &ops, switch (@as(Condition, switch (cmp_op) {
+ .eq, .neq => |cmp_op| cg.select(&res, &.{ty_pl.ty.toType()}, &ops, switch (@as(Condition, switch (cmp_op) {
else => unreachable,
.eq => .e,
.neq => .ne,
@@ -8825,7 +8824,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.unsigned;
var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
var res: [1]Temp = undefined;
- cg.select(&res, &.{cg.typeOfIndex(inst)}, &ops, switch (@as(Condition, switch (signedness) {
+ cg.select(&res, &.{.bool}, &ops, switch (@as(Condition, switch (signedness) {
.signed => switch (air_tag) {
else => unreachable,
.cmp_lt, .cmp_lt_optimized => .l,
@@ -9011,7 +9010,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
});
var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
var res: [1]Temp = undefined;
- cg.select(&res, &.{cg.typeOfIndex(inst)}, &ops, switch (@as(Condition, switch (air_tag) {
+ cg.select(&res, &.{.bool}, &ops, switch (@as(Condition, switch (air_tag) {
else => unreachable,
.cmp_eq, .cmp_eq_optimized => .e,
.cmp_neq, .cmp_neq_optimized => .ne,
@@ -9540,7 +9539,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.fromSize(opt_child_abi_size) }),
.u(0),
);
- var is_null = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .eflags = .e });
+ var is_null = try cg.tempInit(.bool, .{ .eflags = .e });
try ops[0].die(cg);
try is_null.moveTo(inst, cg);
},
@@ -9563,7 +9562,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.fromSize(opt_child_abi_size) }),
.u(0),
);
- var is_non_null = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .eflags = .ne });
+ var is_non_null = try cg.tempInit(.bool, .{ .eflags = .ne });
try ops[0].die(cg);
try is_non_null.moveTo(inst, cg);
},
@@ -9581,7 +9580,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
try ops[0].tracking(cg).short.deref().mem(cg, .{ .size = cg.memSize(eu_err_ty) }),
.u(0),
);
- var is_err = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .eflags = .ne });
+ var is_err = try cg.tempInit(.bool, .{ .eflags = .ne });
try ops[0].die(cg);
try is_err.moveTo(inst, cg);
},
@@ -9599,7 +9598,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
try ops[0].tracking(cg).short.deref().mem(cg, .{ .size = cg.memSize(eu_err_ty) }),
.u(0),
);
- var is_non_err = try cg.tempFromValue(cg.typeOfIndex(inst), .{ .eflags = .e });
+ var is_non_err = try cg.tempInit(.bool, .{ .eflags = .e });
try ops[0].die(cg);
try is_non_err.moveTo(inst, cg);
},
@@ -9631,8 +9630,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
const opt_child_ty = opt_ty.optionalChild(zcu);
const opt_child_abi_size: i32 = @intCast(opt_child_ty.abiSize(zcu));
try ops[0].toOffset(opt_child_abi_size, cg);
- var has_value = try cg.tempFromValue(.bool, .{ .immediate = 1 });
- try ops[0].store(&has_value, cg);
+ var has_value = try cg.tempInit(.bool, .{ .immediate = 1 });
+ try ops[0].store(0, &has_value, cg);
try has_value.die(cg);
try ops[0].toOffset(-opt_child_abi_size, cg);
}
@@ -9654,7 +9653,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu));
var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
try ops[0].toOffset(eu_err_off, cg);
- var err = try ops[0].load(eu_ty.errorUnionSet(zcu), cg);
+ var err = try ops[0].load(0, eu_ty.errorUnionSet(zcu), cg);
try ops[0].die(cg);
try err.moveTo(inst, cg);
},
@@ -9667,8 +9666,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
const eu_pl_off: i32 = @intCast(codegen.errUnionPayloadOffset(eu_pl_ty, zcu));
var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
try ops[0].toOffset(eu_err_off, cg);
- var no_err = try cg.tempFromValue(eu_err_ty, .{ .immediate = 0 });
- try ops[0].store(&no_err, cg);
+ var no_err = try cg.tempInit(eu_err_ty, .{ .immediate = 0 });
+ try ops[0].store(0, &no_err, cg);
try no_err.die(cg);
try ops[0].toOffset(eu_pl_off - eu_err_off, cg);
try ops[0].moveTo(inst, cg);
@@ -9679,7 +9678,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
var ops = try cg.tempsFromOperands(inst, .{extra.struct_operand});
try ops[0].toOffset(cg.fieldOffset(
cg.typeOf(extra.struct_operand),
- cg.typeOfIndex(inst),
+ ty_pl.ty.toType(),
extra.field_index,
), cg);
try ops[0].moveTo(inst, cg);
@@ -9689,7 +9688,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
try ops[0].toOffset(cg.fieldOffset(
cg.typeOf(ty_op.operand),
- cg.typeOfIndex(inst),
+ ty_op.ty.toType(),
0,
), cg);
try ops[0].moveTo(inst, cg);
@@ -9699,7 +9698,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
try ops[0].toOffset(cg.fieldOffset(
cg.typeOf(ty_op.operand),
- cg.typeOfIndex(inst),
+ ty_op.ty.toType(),
1,
), cg);
try ops[0].moveTo(inst, cg);
@@ -9709,7 +9708,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
try ops[0].toOffset(cg.fieldOffset(
cg.typeOf(ty_op.operand),
- cg.typeOfIndex(inst),
+ ty_op.ty.toType(),
2,
), cg);
try ops[0].moveTo(inst, cg);
@@ -9719,11 +9718,29 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
try ops[0].toOffset(cg.fieldOffset(
cg.typeOf(ty_op.operand),
- cg.typeOfIndex(inst),
+ ty_op.ty.toType(),
3,
), cg);
try ops[0].moveTo(inst, cg);
},
+ .set_union_tag => if (use_old) try cg.airSetUnionTag(inst) else {
+ const bin_op = air_datas[@intFromEnum(inst)].bin_op;
+ const union_ty = cg.typeOf(bin_op.lhs).childType(zcu);
+ var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
+ const union_layout = union_ty.unionGetLayout(zcu);
+ if (union_layout.tag_size > 0) try ops[0].store(@intCast(union_layout.tagOffset()), &ops[1], cg);
+ for (ops) |op| try op.die(cg);
+ },
+ .get_union_tag => if (use_old) try cg.airGetUnionTag(inst) else {
+ const ty_op = air_datas[@intFromEnum(inst)].ty_op;
+ const union_ty = cg.typeOf(ty_op.operand);
+ var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
+ const union_layout = union_ty.unionGetLayout(zcu);
+ assert(union_layout.tag_size > 0);
+ var res = try ops[0].read(@intCast(union_layout.tagOffset()), ty_op.ty.toType(), cg);
+ for (ops) |op| if (op.index != res.index) try op.die(cg);
+ try res.moveTo(inst, cg);
+ },
.slice => if (use_old) try cg.airSlice(inst) else {
const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
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 {
var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
try ops[0].toSlicePtr(cg);
var res: [1]Temp = undefined;
- const res_ty = cg.typeOfIndex(inst);
+ const res_ty = cg.typeOf(bin_op.lhs).elemType2(zcu);
cg.select(&res, &.{res_ty}, &ops, comptime &.{ .{
.dst_constraints = .{.{ .int = .byte }},
.patterns = &.{
@@ -9840,7 +9857,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
} },
} }) catch |err| switch (err) {
error.SelectFailed => switch (res_ty.abiSize(zcu)) {
- 0 => res[0] = try cg.tempFromValue(res_ty, .none),
+ 0 => res[0] = try cg.tempInit(res_ty, .none),
else => |elem_size| {
while (true) for (&ops) |*op| {
if (try op.toRegClass(true, .general_purpose, cg)) break;
@@ -9878,7 +9895,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.scale = .fromFactor(@intCast(elem_size)),
} },
});
- res[0] = try ops[0].load(res_ty, cg);
+ res[0] = try ops[0].load(0, res_ty, cg);
},
},
else => |e| return e,
@@ -9897,7 +9914,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
try ops[0].toSlicePtr(cg);
- const dst_ty = cg.typeOfIndex(inst);
+ const dst_ty = ty_pl.ty.toType();
if (dst_ty.ptrInfo(zcu).flags.vector_index == .none) zero_offset: {
const elem_size = dst_ty.childType(zcu).abiSize(zcu);
if (elem_size == 0) break :zero_offset;
@@ -9944,19 +9961,38 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.array_to_slice => if (use_old) try cg.airArrayToSlice(inst) else {
const ty_op = air_datas[@intFromEnum(inst)].ty_op;
var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
- var len = try cg.tempFromValue(.usize, .{
+ var len = try cg.tempInit(.usize, .{
.immediate = cg.typeOf(ty_op.operand).childType(zcu).arrayLen(zcu),
});
try ops[0].toPair(&len, cg);
try ops[0].moveTo(inst, cg);
},
.error_set_has_value => return cg.fail("TODO implement error_set_has_value", .{}),
+ .union_init => if (use_old) try cg.airUnionInit(inst) else {
+ const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
+ const extra = cg.air.extraData(Air.UnionInit, ty_pl.payload).data;
+ const union_ty = ty_pl.ty.toType();
+ var ops = try cg.tempsFromOperands(inst, .{extra.init});
+ var res = try cg.tempAllocMem(union_ty);
+ const union_layout = union_ty.unionGetLayout(zcu);
+ if (union_layout.tag_size > 0) {
+ var tag_temp = try cg.tempFromValue(try pt.enumValueFieldIndex(
+ union_ty.unionTagTypeSafety(zcu).?,
+ extra.field_index,
+ ));
+ try res.write(@intCast(union_layout.tagOffset()), &tag_temp, cg);
+ try tag_temp.die(cg);
+ }
+ try res.write(@intCast(union_layout.payloadOffset()), &ops[0], cg);
+ try ops[0].die(cg);
+ try res.moveTo(inst, cg);
+ },
.field_parent_ptr => if (use_old) try cg.airFieldParentPtr(inst) else {
const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
const extra = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
var ops = try cg.tempsFromOperands(inst, .{extra.field_ptr});
try ops[0].toOffset(-cg.fieldOffset(
- cg.typeOfIndex(inst),
+ ty_pl.ty.toType(),
cg.typeOf(extra.field_ptr),
extra.field_index,
), cg);
@@ -10273,7 +10309,7 @@ fn allocRegOrMemAdvanced(self: *CodeGen, ty: Type, inst: ?Air.Inst.Index, reg_ok
};
if (reg_ok) need_mem: {
- if (abi_size <= @as(u32, switch (ty.zigTypeTag(zcu)) {
+ if (std.math.isPowerOfTwo(abi_size) and abi_size <= @as(u32, switch (ty.zigTypeTag(zcu)) {
.float => switch (ty.floatBits(self.target.*)) {
16, 32, 64, 128 => 16,
80 => break :need_mem,
@@ -11042,7 +11078,8 @@ fn airTrunc(self: *CodeGen, inst: Air.Inst.Index) !void {
if (src_mcv.getReg()) |reg| self.register_manager.lockRegAssumeUnused(reg) else null;
defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
- const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
+ const dst_mcv = if (src_mcv.isRegister() and src_mcv.getReg().?.class() == self.regClassForType(dst_ty) and
+ self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
src_mcv
else if (dst_abi_size <= 8)
try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv)
@@ -15513,12 +15550,12 @@ fn airLoad(self: *CodeGen, inst: Air.Inst.Index) !void {
const ptr_ty = self.typeOf(ty_op.operand);
const elem_size = elem_ty.abiSize(zcu);
- const elem_rc = self.regSetForType(elem_ty);
- const ptr_rc = self.regSetForType(ptr_ty);
+ const elem_rs = self.regSetForType(elem_ty);
+ const ptr_rs = self.regSetForType(ptr_ty);
const ptr_mcv = try self.resolveInst(ty_op.operand);
- const dst_mcv = if (elem_size <= 8 and elem_rc.supersetOf(ptr_rc) and
- self.reuseOperand(inst, ty_op.operand, 0, ptr_mcv))
+ const dst_mcv = if (elem_size <= 8 and std.math.isPowerOfTwo(elem_size) and
+ elem_rs.supersetOf(ptr_rs) and self.reuseOperand(inst, ty_op.operand, 0, ptr_mcv))
// The MCValue that holds the pointer can be re-used as the value.
ptr_mcv
else
@@ -28295,17 +28332,19 @@ const Temp = struct {
return true;
}
- fn load(ptr: *Temp, val_ty: Type, cg: *CodeGen) !Temp {
+ fn load(ptr: *Temp, disp: i32, val_ty: Type, cg: *CodeGen) !Temp {
const val = try cg.tempAlloc(val_ty);
- switch (val.tracking(cg).short) {
+ const val_mcv = val.tracking(cg).short;
+ switch (val_mcv) {
else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
.register => |val_reg| {
while (try ptr.toLea(cg)) {}
- try cg.genSetReg(val_reg, val_ty, ptr.tracking(cg).short.deref(), .{});
+ try cg.genSetReg(val_reg, val_ty, ptr.tracking(cg).short.offset(disp).deref(), .{});
},
- .load_frame => |val_frame_addr| {
- var val_ptr = try cg.tempFromValue(.usize, .{ .lea_frame = val_frame_addr });
- var len = try cg.tempFromValue(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });
+ .memory, .indirect, .load_frame, .load_symbol => {
+ try ptr.toOffset(disp, cg);
+ var val_ptr = try cg.tempInit(.usize, val_mcv.address());
+ var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });
try val_ptr.memcpy(ptr, &len, cg);
try val_ptr.die(cg);
try len.die(cg);
@@ -28314,27 +28353,38 @@ const Temp = struct {
return val;
}
- fn store(ptr: *Temp, val: *Temp, cg: *CodeGen) !void {
+ fn store(ptr: *Temp, disp: i32, val: *Temp, cg: *CodeGen) !void {
const val_ty = val.typeOf(cg);
- const val_abi_size: u32 = @intCast(val_ty.abiSize(cg.pt.zcu));
val: switch (val.tracking(cg).short) {
else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
- .immediate => |imm| if (std.math.cast(i32, imm)) |s| {
+ .immediate => |val_imm| {
+ const val_op: Immediate = if (std.math.cast(u32, val_imm)) |val_uimm32|
+ .u(val_uimm32)
+ else if (std.math.cast(i32, @as(i64, @bitCast(val_imm)))) |val_simm32|
+ .s(val_simm32)
+ else
+ continue :val .{ .register = undefined };
while (try ptr.toLea(cg)) {}
try cg.asmMemoryImmediate(
.{ ._, .mov },
- try ptr.tracking(cg).short.deref().mem(cg, .{ .size = cg.memSize(val_ty) }),
- .s(s),
+ try ptr.tracking(cg).short.deref().mem(cg, .{
+ .size = cg.memSize(val_ty),
+ .disp = disp,
+ }),
+ val_op,
);
- } else continue :val .{ .register = undefined },
+ },
.register => {
while (try ptr.toLea(cg) or try val.toRegClass(true, .general_purpose, cg)) {}
const val_reg = val.tracking(cg).short.register;
switch (val_reg.class()) {
.general_purpose => try cg.asmMemoryRegister(
.{ ._, .mov },
- try ptr.tracking(cg).short.deref().mem(cg, .{ .size = cg.memSize(val_ty) }),
- registerAlias(val_reg, val_abi_size),
+ try ptr.tracking(cg).short.deref().mem(cg, .{
+ .size = cg.memSize(val_ty),
+ .disp = disp,
+ }),
+ registerAlias(val_reg, @intCast(val_ty.abiSize(cg.pt.zcu))),
),
else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
}
@@ -28342,6 +28392,111 @@ const Temp = struct {
}
}
+ fn read(src: *Temp, disp: i32, val_ty: Type, cg: *CodeGen) !Temp {
+ const val = try cg.tempAlloc(val_ty);
+ while (try src.toBase(cg)) {}
+ const val_mcv = val.tracking(cg).short;
+ switch (val_mcv) {
+ else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
+ .register => |val_reg| try src.readReg(disp, val_ty, registerAlias(
+ val_reg,
+ @intCast(val_ty.abiSize(cg.pt.zcu)),
+ ), cg),
+ }
+ return val;
+ }
+
+ fn readReg(src: Temp, disp: i32, dst_ty: Type, dst_reg: Register, cg: *CodeGen) !void {
+ const strat = try cg.moveStrategy(dst_ty, dst_reg.class(), false);
+ try strat.read(cg, dst_reg, try src.tracking(cg).short.mem(cg, .{
+ .size = .fromBitSize(@min(8 * dst_ty.abiSize(cg.pt.zcu), dst_reg.bitSize())),
+ .disp = disp,
+ }));
+ }
+
+ fn write(dst: *Temp, disp: i32, val: *Temp, cg: *CodeGen) !void {
+ const val_ty = val.typeOf(cg);
+ while (try dst.toBase(cg)) {}
+ val_to_gpr: while (true) : (while (try val.toRegClass(false, .general_purpose, cg)) {}) {
+ const val_mcv = val.tracking(cg).short;
+ switch (val_mcv) {
+ else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
+ .immediate => |val_imm| {
+ const val_op: Immediate = if (std.math.cast(u32, val_imm)) |val_uimm32|
+ .u(val_uimm32)
+ else if (std.math.cast(i32, @as(i64, @bitCast(val_imm)))) |val_simm32|
+ .s(val_simm32)
+ else
+ continue :val_to_gpr;
+ try cg.asmMemoryImmediate(
+ .{ ._, .mov },
+ try dst.tracking(cg).short.mem(cg, .{
+ .size = cg.memSize(val_ty),
+ .disp = disp,
+ }),
+ val_op,
+ );
+ },
+ .register => |val_reg| try dst.writeReg(disp, val_ty, registerAlias(
+ val_reg,
+ @intCast(val_ty.abiSize(cg.pt.zcu)),
+ ), cg),
+ inline .register_pair, .register_triple, .register_quadruple => |val_regs| {
+ var part_disp = disp;
+ for (val_regs) |val_reg| {
+ try dst.writeReg(part_disp, val_ty, val_reg, cg);
+ part_disp += @divExact(val_reg.bitSize(), 8);
+ }
+ },
+ .register_offset => |val_reg_off| switch (val_reg_off.off) {
+ 0 => try dst.writeReg(disp, val_ty, registerAlias(
+ val_reg_off.reg,
+ @intCast(val_ty.abiSize(cg.pt.zcu)),
+ ), cg),
+ else => continue :val_to_gpr,
+ },
+ .lea_frame, .lea_symbol => continue :val_to_gpr,
+ .memory, .indirect, .load_frame, .load_symbol => {
+ var dst_ptr = try cg.tempInit(.usize, dst.tracking(cg).short.address().offset(disp));
+ var val_ptr = try cg.tempInit(.usize, val_mcv.address());
+ var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });
+ try dst_ptr.memcpy(&val_ptr, &len, cg);
+ try dst_ptr.die(cg);
+ try val_ptr.die(cg);
+ try len.die(cg);
+ },
+ }
+ break;
+ }
+ }
+
+ fn writeReg(dst: Temp, disp: i32, src_ty: Type, src_reg: Register, cg: *CodeGen) !void {
+ const src_rc = src_reg.class();
+ const src_abi_size = src_ty.abiSize(cg.pt.zcu);
+ const strat = try cg.moveStrategy(src_ty, src_rc, false);
+ if (src_rc == .x87 or std.math.isPowerOfTwo(src_abi_size)) {
+ try strat.write(cg, try dst.tracking(cg).short.mem(cg, .{
+ .size = .fromBitSize(@min(8 * src_abi_size, src_reg.bitSize())),
+ .disp = disp,
+ }), src_reg);
+ } else {
+ const frame_alloc: FrameAlloc = .initSpill(src_ty, cg.pt.zcu);
+ const frame_index = try cg.allocFrameIndex(frame_alloc);
+ const frame_size: Memory.Size = .fromSize(frame_alloc.abi_size);
+ try strat.write(cg, .{
+ .base = .{ .frame = frame_index },
+ .mod = .{ .rm = .{ .size = frame_size } },
+ }, src_reg);
+ var dst_ptr = try cg.tempInit(.usize, dst.tracking(cg).short.address());
+ var src_ptr = try cg.tempInit(.usize, .{ .lea_frame = .{ .index = frame_index } });
+ var len = try cg.tempInit(.usize, .{ .immediate = src_abi_size });
+ try dst_ptr.memcpy(&src_ptr, &len, cg);
+ try dst_ptr.die(cg);
+ try src_ptr.die(cg);
+ try len.die(cg);
+ }
+ }
+
fn memcpy(dst: *Temp, src: *Temp, len: *Temp, cg: *CodeGen) !void {
while (true) for ([_]*Temp{ dst, src, len }, [_]Register{ .rdi, .rsi, .rcx }) |temp, reg| {
if (try temp.toReg(reg, cg)) break;
@@ -28498,7 +28653,7 @@ fn tempAllocMem(cg: *CodeGen, ty: Type) !Temp {
return .{ .index = temp_index.toIndex() };
}
-fn tempFromValue(cg: *CodeGen, ty: Type, value: MCValue) !Temp {
+fn tempInit(cg: *CodeGen, ty: Type, value: MCValue) !Temp {
const temp_index = cg.next_temp_index;
temp_index.tracking(cg).* = .init(value);
cg.temp_type[@intFromEnum(temp_index)] = ty;
@@ -28507,6 +28662,10 @@ fn tempFromValue(cg: *CodeGen, ty: Type, value: MCValue) !Temp {
return .{ .index = temp_index.toIndex() };
}
+fn tempFromValue(cg: *CodeGen, value: Value) !Temp {
+ return cg.tempInit(value.typeOf(cg.pt.zcu), try cg.genTypedValue(value));
+}
+
fn tempFromOperand(
cg: *CodeGen,
inst: Air.Inst.Index,
@@ -28549,7 +28708,7 @@ fn tempFromOperand(
else => break :init const_mcv,
}
});
- return cg.tempFromValue(.fromInterned(ip.typeOf(val)), gop.value_ptr.short);
+ return cg.tempInit(.fromInterned(ip.typeOf(val)), gop.value_ptr.short);
}
const temp_index = cg.next_temp_index;
@@ -29023,8 +29182,8 @@ const Select = struct {
return switch (spec.kind) {
.unused => null,
.any => try cg.tempAlloc(spec.type),
- .cc => |cc| try cg.tempFromValue(spec.type, .{ .eflags = cc }),
- .reg => |reg| try cg.tempFromValue(spec.type, .{ .register = reg }),
+ .cc => |cc| try cg.tempInit(spec.type, .{ .eflags = cc }),
+ .reg => |reg| try cg.tempInit(spec.type, .{ .register = reg }),
.rc => |rc| try cg.tempAllocReg(spec.type, regSetForRegClass(rc)),
.rc_mask => |rc_mask| try cg.tempAllocReg(spec.type, regSetForRegClass(rc_mask.rc)),
.mem => try cg.tempAllocMem(spec.type),
@@ -29081,18 +29240,14 @@ const Select = struct {
break :res_scalar .{ scalar_int_ty, try pt.intValue_big(scalar_int_ty, big_int.toConst()) };
},
};
- const res_ty, const res_val: Value = if (vector_len) |len| res: {
- const vector_ty = try pt.vectorType(.{
+ const res_val: Value = if (vector_len) |len| .fromInterned(try pt.intern(.{ .aggregate = .{
+ .ty = (try pt.vectorType(.{
.len = len,
.child = res_scalar_ty.toIntern(),
- });
- const vector_val = try pt.intern(.{ .aggregate = .{
- .ty = vector_ty.toIntern(),
- .storage = .{ .repeated_elem = res_scalar_val.toIntern() },
- } });
- break :res .{ vector_ty, .fromInterned(vector_val) };
- } else .{ res_scalar_ty, res_scalar_val };
- return try cg.tempFromValue(res_ty, try cg.genTypedValue(res_val));
+ })).toIntern(),
+ .storage = .{ .repeated_elem = res_scalar_val.toIntern() },
+ } })) else res_scalar_val;
+ return try cg.tempFromValue(res_val);
},
.ref => |ref| ref.deref(s),
.ref_mask => |ref_mask| ref_mask.ref.deref(s),
test/behavior/union.zig
@@ -2246,12 +2246,12 @@ test "matching captures causes union equivalence" {
}
test "signed enum tag with negative value" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
const Enum = enum(i8) {
a = -1,