Commit ae3d95fc8d
Changed files (6)
src
test
behavior
x86_64
src/arch/x86_64/bits.zig
@@ -366,7 +366,6 @@ pub const Register = enum(u8) {
@intFromEnum(Register.eax) ... @intFromEnum(Register.r15d) => @intFromEnum(Register.eax),
@intFromEnum(Register.ax) ... @intFromEnum(Register.r15w) => @intFromEnum(Register.ax),
@intFromEnum(Register.al) ... @intFromEnum(Register.r15b) => @intFromEnum(Register.al),
- @intFromEnum(Register.ah) ... @intFromEnum(Register.bh) => @intFromEnum(Register.ah) - 4,
else => unreachable,
// zig fmt: on
};
@@ -385,7 +384,10 @@ pub const Register = enum(u8) {
}
pub fn to8(reg: Register) Register {
- return @enumFromInt(@intFromEnum(reg) - reg.gpBase() + @intFromEnum(Register.al));
+ return switch (@intFromEnum(reg)) {
+ else => @enumFromInt(@intFromEnum(reg) - reg.gpBase() + @intFromEnum(Register.al)),
+ @intFromEnum(Register.ah)...@intFromEnum(Register.bh) => reg,
+ };
}
fn sseBase(reg: Register) u7 {
src/arch/x86_64/CodeGen.zig
@@ -150,7 +150,7 @@ const Owner = union(enum) {
};
const MaskKind = enum(u1) { sign, all };
-const MaskInfo = packed struct { kind: MaskKind, inverted: bool, scalar: Memory.Size };
+const MaskInfo = packed struct { kind: MaskKind, inverted: bool = false, scalar: Memory.Size };
pub const MCValue = union(enum) {
/// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc.
@@ -2657,10 +2657,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
} else { // hack around Sema OPV bugs
res[0] = ops[0];
}
- for (ops) |op| for (res) |r| {
- if (op.index == r.index) break;
- } else try op.die(cg);
- try res[0].moveTo(inst, cg);
+ try res[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg);
},
.ptr_sub => |air_tag| if (use_old) try cg.airPtrArithmetic(inst, air_tag) else {
const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
@@ -2792,17 +2789,14 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
// hack around Sema OPV bugs
res[0] = ops[0];
}
- for (ops) |op| for (res) |r| {
- if (op.index == r.index) break;
- } else try op.die(cg);
- try res[0].moveTo(inst, cg);
+ try res[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg);
},
.alloc => if (use_old) try cg.airAlloc(inst) else {
const ty = air_datas[@intFromEnum(inst)].ty;
- var slot = try cg.tempInit(ty, .{ .lea_frame = .{
+ const slot = try cg.tempInit(ty, .{ .lea_frame = .{
.index = try cg.allocMemPtr(inst),
} });
- try slot.moveTo(inst, cg);
+ try slot.finish(inst, &.{}, &.{}, cg);
},
.inferred_alloc, .inferred_alloc_comptime => unreachable,
.ret_ptr => if (use_old) try cg.airRetPtr(inst) else {
@@ -2818,7 +2812,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
break :slot slot;
},
};
- try slot.moveTo(inst, cg);
+ try slot.finish(inst, &.{}, &.{}, cg);
},
.assembly => try cg.airAsm(inst),
.bit_and, .bit_or, .xor, .bool_and, .bool_or => |air_tag| if (use_old) try cg.airBinOp(inst, air_tag) else {
@@ -3154,10 +3148,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
}),
else => |e| return e,
};
- for (ops) |op| for (res) |r| {
- if (op.index == r.index) break;
- } else try op.die(cg);
- try res[0].moveTo(inst, cg);
+ try res[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg);
},
.not => |air_tag| if (use_old) try cg.airUnOp(inst, air_tag) else {
const ty_op = air_datas[@intFromEnum(inst)].ty_op;
@@ -4207,10 +4198,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
}),
else => |e| return e,
};
- for (ops) |op| for (res) |r| {
- if (op.index == r.index) break;
- } else try op.die(cg);
- try res[0].moveTo(inst, cg);
+ try res[0].finish(inst, &.{ty_op.operand}, &ops, cg);
},
.block => if (use_old) try cg.airBlock(inst) else {
@@ -4250,13 +4238,13 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.index = .ret_addr,
} });
while (try slot.toRegClass(true, .general_purpose, cg)) {}
- try slot.moveTo(inst, cg);
+ try slot.finish(inst, &.{}, &.{}, cg);
},
.frame_addr => if (use_old) try cg.airFrameAddress(inst) else {
- var slot = try cg.tempInit(.usize, .{ .lea_frame = .{
+ const slot = try cg.tempInit(.usize, .{ .lea_frame = .{
.index = .base_ptr,
} });
- try slot.moveTo(inst, cg);
+ try slot.finish(inst, &.{}, &.{}, cg);
},
.call => try cg.airCall(inst, .auto, .{ .safety = true }),
.call_always_tail => try cg.airCall(inst, .always_tail, .{ .safety = true }),
@@ -6986,10 +6974,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
}),
else => |e| return e,
};
- for (ops) |op| for (res) |r| {
- if (op.index == r.index) break;
- } else try op.die(cg);
- try res[0].moveTo(inst, cg);
+ try res[0].finish(inst, &.{ty_op.operand}, &ops, cg);
},
.cmp_vector, .cmp_vector_optimized => |air_tag| if (use_old) try cg.airCmpVector(inst) else fallback: {
@@ -8394,6 +8379,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
} },
}, .{
.dst_constraints = .{.{ .bool_vec = .byte }},
+ .src_constraints = .{ .any_scalar_int, .any_scalar_int },
.patterns = &.{
.{ .src = .{ .to_mem, .to_mem } },
},
@@ -8550,6 +8536,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
} },
}, .{
.dst_constraints = .{.{ .bool_vec = .dword }},
+ .src_constraints = .{ .any_scalar_int, .any_scalar_int },
.patterns = &.{
.{ .src = .{ .to_mem, .to_mem } },
},
@@ -8710,6 +8697,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
}, .{
.required_features = .{ .@"64bit", null, null, null },
.dst_constraints = .{.{ .bool_vec = .qword }},
+ .src_constraints = .{ .any_scalar_int, .any_scalar_int },
.patterns = &.{
.{ .src = .{ .to_mem, .to_mem } },
},
@@ -8784,6 +8772,72 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.{ ._, ._r, .sh, .tmp3d, .si(3), ._, ._ },
.{ ._, ._, .mov, .memi(.dst0p, .tmp3), .tmp2p, ._, ._ },
} },
+ }, .{
+ .required_features = .{ .f16c, null, null, null },
+ .src_constraints = .{
+ .{ .scalar_exact_float = .{ .of = .qword, .is = .word } },
+ .{ .scalar_exact_float = .{ .of = .qword, .is = .word } },
+ },
+ .patterns = &.{
+ .{ .src = .{ .mem, .mem } },
+ .{ .src = .{ .sse, .mem } },
+ .{ .src = .{ .mem, .sse } },
+ .{ .src = .{ .to_sse, .to_sse } },
+ },
+ .extra_temps = .{
+ .{ .kind = .{ .rc = .sse } },
+ .unused,
+ .unused,
+ .unused,
+ .unused,
+ .unused,
+ },
+ .dst_temps = .{.{ .rc_mask = .{ .rc = .sse, .info = .{
+ .kind = .all,
+ .scalar = .dword,
+ } } }},
+ .each = .{ .once = &.{
+ .{ ._, .v_ps, .cvtph2, .dst0x, .src0q, ._, ._ },
+ .{ ._, .v_ps, .cvtph2, .tmp0x, .src1q, ._, ._ },
+ .{ ._, .v_ps, .cmp, .dst0x, .dst0x, .tmp0x, .si(switch (cc) {
+ else => unreachable,
+ .e => 0b00000,
+ .ne => 0b00100,
+ }) },
+ } },
+ }, .{
+ .required_features = .{ .f16c, null, null, null },
+ .src_constraints = .{
+ .{ .scalar_exact_float = .{ .of = .xword, .is = .word } },
+ .{ .scalar_exact_float = .{ .of = .xword, .is = .word } },
+ },
+ .patterns = &.{
+ .{ .src = .{ .mem, .mem } },
+ .{ .src = .{ .to_sse, .mem } },
+ .{ .src = .{ .mem, .to_sse } },
+ .{ .src = .{ .to_sse, .to_sse } },
+ },
+ .extra_temps = .{
+ .{ .kind = .{ .rc = .sse } },
+ .unused,
+ .unused,
+ .unused,
+ .unused,
+ .unused,
+ },
+ .dst_temps = .{.{ .rc_mask = .{ .rc = .sse, .info = .{
+ .kind = .all,
+ .scalar = .dword,
+ } } }},
+ .each = .{ .once = &.{
+ .{ ._, .v_ps, .cvtph2, .dst0y, .src0x, ._, ._ },
+ .{ ._, .v_ps, .cvtph2, .tmp0y, .src1x, ._, ._ },
+ .{ ._, .v_ps, .cmp, .dst0y, .dst0y, .tmp0y, .si(switch (cc) {
+ else => unreachable,
+ .e => 0b00000,
+ .ne => 0b00100,
+ }) },
+ } },
} },
}) catch |err| switch (err) {
error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
@@ -8797,10 +8851,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.gte => unreachable,
.gt => unreachable,
}
- for (ops) |op| for (res) |r| {
- if (op.index == r.index) break;
- } else try op.die(cg);
- try res[0].moveTo(inst, cg);
+ try res[0].finish(inst, &.{ extra.lhs, extra.rhs }, &ops, cg);
},
.abs => |air_tag| if (use_old) try cg.airAbs(inst) else fallback: {
@@ -9836,10 +9887,18 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.required_features = .{ .x87, null, null, null },
.src_constraints = .{ .{ .scalar_exact_float = .{ .of = .xword, .is = .tbyte } }, .any },
.patterns = &.{
+ .{ .src = .{ .mem, .none } },
.{ .src = .{ .to_x87, .none } },
},
+ .extra_temps = .{
+ .{ .type = .f80, .kind = .{ .reg = .st7 } },
+ .unused,
+ .unused,
+ .unused,
+ .unused,
+ .unused,
+ },
.dst_temps = .{.{ .mut_reg = .{ .ref = .src0, .rc = .x87 } }},
- .clobbers = .{ .st = 1 },
.each = .{ .once = &.{
.{ ._, .f_, .ld, .src0t, ._, ._, ._ },
.{ ._, .f_, .abs, ._, ._, ._, ._ },
@@ -9967,10 +10026,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
}),
else => |e| return e,
};
- for (ops) |op| for (res) |r| {
- if (op.index == r.index) break;
- } else try op.die(cg);
- try res[0].moveTo(inst, cg);
+ try res[0].finish(inst, &.{ty_op.operand}, &ops, cg);
},
.cmp_lt,
@@ -10166,10 +10222,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
}),
else => |e| return e,
};
- for (ops) |op| for (res) |r| {
- if (op.index == r.index) break;
- } else try op.die(cg);
- try res[0].moveTo(inst, cg);
+ try res[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg);
},
.cmp_eq,
.cmp_eq_optimized,
@@ -10182,7 +10235,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
}) else fallback: {
const bin_op = air_datas[@intFromEnum(inst)].bin_op;
const scalar_ty = cg.typeOf(bin_op.lhs).scalarType(zcu);
- if (cg.intInfo(scalar_ty) == null) break :fallback try cg.airCmp(inst, switch (air_tag) {
+ if (cg.intInfo(scalar_ty) == null and cg.floatBits(scalar_ty) == null) break :fallback try cg.airCmp(inst, switch (air_tag) {
else => unreachable,
.cmp_eq, .cmp_eq_optimized => .eq,
.cmp_neq, .cmp_neq_optimized => .neq,
@@ -10424,6 +10477,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
} },
}, .{
.required_features = .{ .avx2, null, null, null },
+ .src_constraints = .{
+ .{ .remainder_int = .{ .of = .yword, .is = .yword } },
+ .{ .remainder_int = .{ .of = .yword, .is = .yword } },
+ },
.patterns = &.{
.{ .src = .{ .to_mem, .to_mem } },
},
@@ -10481,6 +10538,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
} },
}, .{
.required_features = .{ .avx, null, null, null },
+ .src_constraints = .{
+ .{ .remainder_int = .{ .of = .yword, .is = .yword } },
+ .{ .remainder_int = .{ .of = .yword, .is = .yword } },
+ },
.patterns = &.{
.{ .src = .{ .to_mem, .to_mem } },
},
@@ -10506,6 +10567,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
} },
}, .{
.required_features = .{ .avx, null, null, null },
+ .src_constraints = .{
+ .{ .remainder_int = .{ .of = .xword, .is = .xword } },
+ .{ .remainder_int = .{ .of = .xword, .is = .xword } },
+ },
.patterns = &.{
.{ .src = .{ .to_mem, .to_mem } },
},
@@ -10531,6 +10596,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
} },
}, .{
.required_features = .{ .sse4_1, null, null, null },
+ .src_constraints = .{
+ .{ .remainder_int = .{ .of = .xword, .is = .xword } },
+ .{ .remainder_int = .{ .of = .xword, .is = .xword } },
+ },
.patterns = &.{
.{ .src = .{ .to_mem, .to_mem } },
},
@@ -10556,6 +10625,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
} },
}, .{
.required_features = .{ .sse2, null, null, null },
+ .src_constraints = .{
+ .{ .remainder_int = .{ .of = .xword, .is = .xword } },
+ .{ .remainder_int = .{ .of = .xword, .is = .xword } },
+ },
.patterns = &.{
.{ .src = .{ .to_mem, .to_mem } },
},
@@ -10584,6 +10657,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
} },
}, .{
.required_features = .{ .sse, .mmx, null, null },
+ .src_constraints = .{
+ .{ .remainder_int = .{ .of = .qword, .is = .qword } },
+ .{ .remainder_int = .{ .of = .qword, .is = .qword } },
+ },
.patterns = &.{
.{ .src = .{ .to_mem, .to_mem } },
},
@@ -10611,6 +10688,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.{ ._, ._, .cmp, .tmp0d, .si(0xff), ._, ._ },
} },
}, .{
+ .src_constraints = .{
+ .{ .remainder_int = .{ .of = .qword, .is = .qword } },
+ .{ .remainder_int = .{ .of = .qword, .is = .qword } },
+ },
.patterns = &.{
.{ .src = .{ .to_mem, .to_mem } },
},
@@ -10634,6 +10715,443 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
.{ ._, ._, .@"test", .tmp1p, .tmp1p, ._, ._ },
} },
+ }, .{
+ .required_features = .{ .f16c, null, null, null },
+ .src_constraints = .{ .{ .float = .word }, .{ .float = .word } },
+ .patterns = &.{
+ .{ .src = .{ .to_sse, .to_sse } },
+ },
+ .extra_temps = .{
+ .{ .kind = .{ .rc = .sse } },
+ .{ .kind = .{ .rc = .sse } },
+ .unused,
+ .unused,
+ .unused,
+ .unused,
+ },
+ .dst_temps = .{.{ .cc = switch (cc) {
+ else => unreachable,
+ .e => .z_and_np,
+ .ne => .nz_or_p,
+ } }},
+ .clobbers = .{ .eflags = true },
+ .each = .{ .once = &.{
+ .{ ._, .vp_, .unpcklwd, .tmp0x, .src0x, .src1x, ._ },
+ .{ ._, .v_ps, .cvtph2, .tmp0x, .tmp0x, ._, ._ },
+ .{ ._, .v_, .movshdup, .tmp1x, .tmp0x, ._, ._ },
+ .{ ._, .v_ss, .ucomi, .tmp0x, .tmp1x, ._, ._ },
+ } },
+ }, .{
+ .required_features = .{ .sse, null, null, null },
+ .src_constraints = .{ .{ .float = .word }, .{ .float = .word } },
+ .patterns = &.{
+ .{ .src = .{ .{ .to_reg = .xmm0 }, .{ .to_reg = .xmm1 } } },
+ },
+ .call_frame = .{ .size = 0, .alignment = .@"16" },
+ .extra_temps = .{
+ .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
+ else => unreachable,
+ .e => "__eqhf2",
+ .ne => "__nehf2",
+ } } } },
+ .{ .type = .i32, .kind = .{ .reg = .eax } },
+ .unused,
+ .unused,
+ .unused,
+ .unused,
+ },
+ .dst_temps = .{.{ .cc = cc }},
+ .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
+ .each = .{ .once = &.{
+ .{ ._, ._, .call, .tmp0p, ._, ._, ._ },
+ .{ ._, ._, .@"test", .tmp1d, .tmp1d, ._, ._ },
+ } },
+ }, .{
+ .required_features = .{ .avx, null, null, null },
+ .src_constraints = .{ .{ .float = .dword }, .{ .float = .dword } },
+ .patterns = &.{
+ .{ .src = .{ .to_sse, .mem } },
+ .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
+ .{ .src = .{ .to_sse, .to_sse } },
+ },
+ .extra_temps = .{
+ .{ .type = .f16, .kind = .{ .rc = .sse } },
+ .{ .type = .f16, .kind = .{ .rc = .sse } },
+ .unused,
+ .unused,
+ .unused,
+ .unused,
+ },
+ .dst_temps = .{.{ .cc = switch (cc) {
+ else => unreachable,
+ .e => .z_and_np,
+ .ne => .nz_or_p,
+ } }},
+ .clobbers = .{ .eflags = true },
+ .each = .{ .once = &.{
+ .{ ._, .v_ss, .ucomi, .src0x, .src1d, ._, ._ },
+ } },
+ }, .{
+ .required_features = .{ .sse, null, null, null },
+ .src_constraints = .{ .{ .float = .dword }, .{ .float = .dword } },
+ .patterns = &.{
+ .{ .src = .{ .to_sse, .mem } },
+ .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
+ .{ .src = .{ .to_sse, .to_sse } },
+ },
+ .extra_temps = .{
+ .{ .type = .f16, .kind = .{ .rc = .sse } },
+ .{ .type = .f16, .kind = .{ .rc = .sse } },
+ .unused,
+ .unused,
+ .unused,
+ .unused,
+ },
+ .dst_temps = .{.{ .cc = switch (cc) {
+ else => unreachable,
+ .e => .z_and_np,
+ .ne => .nz_or_p,
+ } }},
+ .clobbers = .{ .eflags = true },
+ .each = .{ .once = &.{
+ .{ ._, ._ss, .ucomi, .src0x, .src1d, ._, ._ },
+ } },
+ }, .{
+ .required_features = .{ .sse, null, null, null },
+ .src_constraints = .{ .{ .float = .dword }, .{ .float = .word } },
+ .patterns = &.{
+ .{ .src = .{ .{ .to_reg = .xmm0 }, .{ .to_reg = .xmm1 } } },
+ },
+ .call_frame = .{ .size = 0, .alignment = .@"16" },
+ .extra_temps = .{
+ .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
+ else => unreachable,
+ .e => "__eqsf2",
+ .ne => "__nesf2",
+ } } } },
+ .{ .type = .i32, .kind = .{ .reg = .eax } },
+ .unused,
+ .unused,
+ .unused,
+ .unused,
+ },
+ .dst_temps = .{.{ .cc = cc }},
+ .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
+ .each = .{ .once = &.{
+ .{ ._, ._, .call, .tmp0p, ._, ._, ._ },
+ .{ ._, ._, .@"test", .tmp1d, .tmp1d, ._, ._ },
+ } },
+ }, .{
+ .required_features = .{ .avx, null, null, null },
+ .src_constraints = .{ .{ .float = .qword }, .{ .float = .qword } },
+ .patterns = &.{
+ .{ .src = .{ .to_sse, .mem } },
+ .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
+ .{ .src = .{ .to_sse, .to_sse } },
+ },
+ .extra_temps = .{
+ .{ .type = .f16, .kind = .{ .rc = .sse } },
+ .{ .type = .f16, .kind = .{ .rc = .sse } },
+ .unused,
+ .unused,
+ .unused,
+ .unused,
+ },
+ .dst_temps = .{.{ .cc = switch (cc) {
+ else => unreachable,
+ .e => .z_and_np,
+ .ne => .nz_or_p,
+ } }},
+ .clobbers = .{ .eflags = true },
+ .each = .{ .once = &.{
+ .{ ._, .v_sd, .ucomi, .src0x, .src1q, ._, ._ },
+ } },
+ }, .{
+ .required_features = .{ .sse2, null, null, null },
+ .src_constraints = .{ .{ .float = .qword }, .{ .float = .qword } },
+ .patterns = &.{
+ .{ .src = .{ .to_sse, .mem } },
+ .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
+ .{ .src = .{ .to_sse, .to_sse } },
+ },
+ .extra_temps = .{
+ .{ .type = .f16, .kind = .{ .rc = .sse } },
+ .{ .type = .f16, .kind = .{ .rc = .sse } },
+ .unused,
+ .unused,
+ .unused,
+ .unused,
+ },
+ .dst_temps = .{.{ .cc = switch (cc) {
+ else => unreachable,
+ .e => .z_and_np,
+ .ne => .nz_or_p,
+ } }},
+ .clobbers = .{ .eflags = true },
+ .each = .{ .once = &.{
+ .{ ._, ._sd, .ucomi, .src0x, .src1q, ._, ._ },
+ } },
+ }, .{
+ .required_features = .{ .sse, null, null, null },
+ .src_constraints = .{ .{ .float = .qword }, .{ .float = .qword } },
+ .patterns = &.{
+ .{ .src = .{ .{ .to_reg = .xmm0 }, .{ .to_reg = .xmm1 } } },
+ },
+ .call_frame = .{ .size = 0, .alignment = .@"16" },
+ .extra_temps = .{
+ .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
+ else => unreachable,
+ .e => "__eqdf2",
+ .ne => "__nedf2",
+ } } } },
+ .{ .type = .i32, .kind = .{ .reg = .eax } },
+ .unused,
+ .unused,
+ .unused,
+ .unused,
+ },
+ .dst_temps = .{.{ .cc = cc }},
+ .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
+ .each = .{ .once = &.{
+ .{ ._, ._, .call, .tmp0p, ._, ._, ._ },
+ .{ ._, ._, .@"test", .tmp1d, .tmp1d, ._, ._ },
+ } },
+ }, .{
+ .required_features = .{ .x87, .cmov, null, null },
+ .src_constraints = .{ .{ .float = .tbyte }, .{ .float = .tbyte } },
+ .patterns = &.{
+ .{ .src = .{ .mem, .mem } },
+ },
+ .extra_temps = .{
+ .{ .type = .f80, .kind = .{ .reg = .st6 } },
+ .{ .type = .f80, .kind = .{ .reg = .st7 } },
+ .unused,
+ .unused,
+ .unused,
+ .unused,
+ },
+ .dst_temps = .{.{ .cc = switch (cc) {
+ else => unreachable,
+ .e => .z_and_np,
+ .ne => .nz_or_p,
+ } }},
+ .clobbers = .{ .eflags = true },
+ .each = .{ .once = &.{
+ .{ ._, .f_, .ld, .src1t, ._, ._, ._ },
+ .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
+ .{ ._, .f_p, .ucomi, .tmp0t, .tmp1t, ._, ._ },
+ .{ ._, .f_p, .st, .tmp1t, ._, ._, ._ },
+ } },
+ }, .{
+ .required_features = .{ .x87, .cmov, null, null },
+ .src_constraints = .{ .{ .float = .tbyte }, .{ .float = .tbyte } },
+ .patterns = &.{
+ .{ .src = .{ .to_x87, .mem }, .commute = .{ 0, 1 } },
+ .{ .src = .{ .mem, .to_x87 } },
+ .{ .src = .{ .to_x87, .to_x87 } },
+ },
+ .extra_temps = .{
+ .{ .type = .f80, .kind = .{ .reg = .st7 } },
+ .unused,
+ .unused,
+ .unused,
+ .unused,
+ .unused,
+ },
+ .dst_temps = .{.{ .cc = switch (cc) {
+ else => unreachable,
+ .e => .z_and_np,
+ .ne => .nz_or_p,
+ } }},
+ .clobbers = .{ .eflags = true },
+ .each = .{ .once = &.{
+ .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
+ .{ ._, .f_p, .ucomi, .tmp0t, .src1t, ._, ._ },
+ } },
+ }, .{
+ .required_features = .{ .sahf, .x87, null, null },
+ .src_constraints = .{ .{ .float = .tbyte }, .{ .float = .tbyte } },
+ .patterns = &.{
+ .{ .src = .{ .mem, .mem } },
+ },
+ .extra_temps = .{
+ .{ .type = .f80, .kind = .{ .reg = .st6 } },
+ .{ .type = .f80, .kind = .{ .reg = .st7 } },
+ .{ .type = .u16, .kind = .{ .reg = .ax } },
+ .unused,
+ .unused,
+ .unused,
+ },
+ .dst_temps = .{.{ .cc = switch (cc) {
+ else => unreachable,
+ .e => .z_and_np,
+ .ne => .nz_or_p,
+ } }},
+ .clobbers = .{ .eflags = true },
+ .each = .{ .once = &.{
+ .{ ._, .f_, .ld, .src1t, ._, ._, ._ },
+ .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
+ .{ ._, .f_pp, .ucom, ._, ._, ._, ._ },
+ .{ ._, .fn_sw, .st, .tmp2w, ._, ._, ._ },
+ .{ ._, ._, .sahf, ._, ._, ._, ._ },
+ } },
+ }, .{
+ .required_features = .{ .@"64bit", .x87, null, null },
+ .src_constraints = .{ .{ .float = .tbyte }, .{ .float = .tbyte } },
+ .patterns = &.{
+ .{ .src = .{ .mem, .mem } },
+ },
+ .extra_temps = .{
+ .{ .type = .f80, .kind = .{ .reg = .st6 } },
+ .{ .type = .f80, .kind = .{ .reg = .st7 } },
+ .{ .type = .u16, .kind = .{ .reg = .ax } },
+ .{ .type = .u8, .kind = .{ .reg = .ah } },
+ .unused,
+ .unused,
+ },
+ .dst_temps = .{.{ .cc = cc }},
+ .clobbers = .{ .eflags = true },
+ .each = .{ .once = &.{
+ .{ ._, .f_, .ld, .src1t, ._, ._, ._ },
+ .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
+ .{ ._, .f_pp, .ucom, ._, ._, ._, ._ },
+ .{ ._, .fn_sw, .st, .tmp2w, ._, ._, ._ },
+ .{ ._, ._, .xor, .tmp3b, .si(0b0_1_000_000), ._, ._ },
+ .{ ._, ._, .@"test", .tmp3b, .si(0b0_1_000_100), ._, ._ },
+ } },
+ }, .{
+ .required_features = .{ .x87, null, null, null },
+ .src_constraints = .{ .{ .float = .tbyte }, .{ .float = .tbyte } },
+ .patterns = &.{
+ .{ .src = .{ .mem, .mem } },
+ },
+ .extra_temps = .{
+ .{ .type = .f80, .kind = .{ .reg = .st6 } },
+ .{ .type = .f80, .kind = .{ .reg = .st7 } },
+ .{ .type = .u16, .kind = .{ .reg = .ax } },
+ .unused,
+ .unused,
+ .unused,
+ },
+ .dst_temps = .{.{ .cc = switch (cc) {
+ else => unreachable,
+ .e => .z_and_np,
+ .ne => .nz_or_p,
+ } }},
+ .clobbers = .{ .eflags = true },
+ .each = .{ .once = &.{
+ .{ ._, .f_, .ld, .src1t, ._, ._, ._ },
+ .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
+ .{ ._, .f_pp, .ucom, ._, ._, ._, ._ },
+ .{ ._, .fn_sw, .st, .tmp2w, ._, ._, ._ },
+ .{ ._, ._, .sahf, ._, ._, ._, ._ },
+ } },
+ }, .{
+ .required_features = .{ .sahf, .x87, null, null },
+ .src_constraints = .{ .{ .float = .tbyte }, .{ .float = .tbyte } },
+ .patterns = &.{
+ .{ .src = .{ .to_x87, .mem }, .commute = .{ 0, 1 } },
+ .{ .src = .{ .mem, .to_x87 } },
+ .{ .src = .{ .to_x87, .to_x87 } },
+ },
+ .extra_temps = .{
+ .{ .type = .f80, .kind = .{ .reg = .st6 } },
+ .{ .type = .f80, .kind = .{ .reg = .st7 } },
+ .{ .type = .u16, .kind = .{ .reg = .ax } },
+ .unused,
+ .unused,
+ .unused,
+ },
+ .dst_temps = .{.{ .cc = switch (cc) {
+ else => unreachable,
+ .e => .z_and_np,
+ .ne => .nz_or_p,
+ } }},
+ .clobbers = .{ .eflags = true },
+ .each = .{ .once = &.{
+ .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
+ .{ ._, .f_p, .ucom, .src1t, ._, ._, ._ },
+ .{ ._, .fn_sw, .st, .tmp2w, ._, ._, ._ },
+ .{ ._, ._, .sahf, ._, ._, ._, ._ },
+ } },
+ }, .{
+ .required_features = .{ .@"64bit", .x87, null, null },
+ .src_constraints = .{ .{ .float = .tbyte }, .{ .float = .tbyte } },
+ .patterns = &.{
+ .{ .src = .{ .to_x87, .mem }, .commute = .{ 0, 1 } },
+ .{ .src = .{ .mem, .to_x87 } },
+ .{ .src = .{ .to_x87, .to_x87 } },
+ },
+ .extra_temps = .{
+ .{ .type = .f80, .kind = .{ .reg = .st6 } },
+ .{ .type = .f80, .kind = .{ .reg = .st7 } },
+ .{ .type = .u16, .kind = .{ .reg = .ax } },
+ .{ .type = .u8, .kind = .{ .reg = .ah } },
+ .unused,
+ .unused,
+ },
+ .dst_temps = .{.{ .cc = cc }},
+ .clobbers = .{ .eflags = true },
+ .each = .{ .once = &.{
+ .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
+ .{ ._, .f_p, .ucom, .src1t, ._, ._, ._ },
+ .{ ._, .fn_sw, .st, .tmp2w, ._, ._, ._ },
+ .{ ._, ._, .xor, .tmp3b, .si(0b0_1_000_000), ._, ._ },
+ .{ ._, ._, .@"test", .tmp3b, .si(0b0_1_000_100), ._, ._ },
+ } },
+ }, .{
+ .required_features = .{ .x87, null, null, null },
+ .src_constraints = .{ .{ .float = .tbyte }, .{ .float = .tbyte } },
+ .patterns = &.{
+ .{ .src = .{ .to_x87, .mem }, .commute = .{ 0, 1 } },
+ .{ .src = .{ .mem, .to_x87 } },
+ .{ .src = .{ .to_x87, .to_x87 } },
+ },
+ .extra_temps = .{
+ .{ .type = .f80, .kind = .{ .reg = .st6 } },
+ .{ .type = .f80, .kind = .{ .reg = .st7 } },
+ .{ .type = .u16, .kind = .{ .reg = .ax } },
+ .unused,
+ .unused,
+ .unused,
+ },
+ .dst_temps = .{.{ .cc = switch (cc) {
+ else => unreachable,
+ .e => .z_and_np,
+ .ne => .nz_or_p,
+ } }},
+ .clobbers = .{ .eflags = true },
+ .each = .{ .once = &.{
+ .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
+ .{ ._, .f_p, .ucom, .src1t, ._, ._, ._ },
+ .{ ._, .fn_sw, .st, .tmp2w, ._, ._, ._ },
+ .{ ._, ._, .sahf, ._, ._, ._, ._ },
+ } },
+ }, .{
+ .required_features = .{ .sse, null, null, null },
+ .src_constraints = .{ .{ .float = .xword }, .{ .float = .xword } },
+ .patterns = &.{
+ .{ .src = .{ .{ .to_reg = .xmm0 }, .{ .to_reg = .xmm1 } } },
+ },
+ .call_frame = .{ .size = 0, .alignment = .@"16" },
+ .extra_temps = .{
+ .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
+ else => unreachable,
+ .e => "__eqtf2",
+ .ne => "__netf2",
+ } } } },
+ .{ .type = .i32, .kind = .{ .reg = .eax } },
+ .unused,
+ .unused,
+ .unused,
+ .unused,
+ },
+ .dst_temps = .{.{ .cc = cc }},
+ .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
+ .each = .{ .once = &.{
+ .{ ._, ._, .call, .tmp0p, ._, ._, ._ },
+ .{ ._, ._, .@"test", .tmp1d, .tmp1d, ._, ._ },
+ } },
} },
}) catch |err| switch (err) {
error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
@@ -10644,10 +11162,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
}),
else => |e| return e,
};
- for (ops) |op| for (res) |r| {
- if (op.index == r.index) break;
- } else try op.die(cg);
- try res[0].moveTo(inst, cg);
+ try res[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg);
},
.cond_br => try cg.airCondBr(inst),
@@ -10718,9 +11233,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.fromSize(opt_child_abi_size) }),
.u(0),
);
- var is_null = try cg.tempInit(.bool, .{ .eflags = .e });
- try ops[0].die(cg);
- try is_null.moveTo(inst, cg);
+ const is_null = try cg.tempInit(.bool, .{ .eflags = .e });
+ try is_null.finish(inst, &.{un_op}, &ops, cg);
},
.is_non_null_ptr => if (use_old) try cg.airIsNonNullPtr(inst) else {
const un_op = air_datas[@intFromEnum(inst)].un_op;
@@ -10741,9 +11255,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.fromSize(opt_child_abi_size) }),
.u(0),
);
- var is_non_null = try cg.tempInit(.bool, .{ .eflags = .ne });
- try ops[0].die(cg);
- try is_non_null.moveTo(inst, cg);
+ const is_non_null = try cg.tempInit(.bool, .{ .eflags = .ne });
+ try is_non_null.finish(inst, &.{un_op}, &ops, cg);
},
.is_err_ptr => if (use_old) try cg.airIsErrPtr(inst) else {
const un_op = air_datas[@intFromEnum(inst)].un_op;
@@ -10759,9 +11272,8 @@ 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.tempInit(.bool, .{ .eflags = .ne });
- try ops[0].die(cg);
- try is_err.moveTo(inst, cg);
+ const is_err = try cg.tempInit(.bool, .{ .eflags = .ne });
+ try is_err.finish(inst, &.{un_op}, &ops, cg);
},
.is_non_err_ptr => if (use_old) try cg.airIsNonErrPtr(inst) else {
const un_op = air_datas[@intFromEnum(inst)].un_op;
@@ -10777,9 +11289,8 @@ 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.tempInit(.bool, .{ .eflags = .e });
- try ops[0].die(cg);
- try is_non_err.moveTo(inst, cg);
+ const is_non_err = try cg.tempInit(.bool, .{ .eflags = .e });
+ try is_non_err.finish(inst, &.{un_op}, &ops, cg);
},
.load => if (use_old) try cg.airLoad(inst) else fallback: {
const ty_op = air_datas[@intFromEnum(inst)].ty_op;
@@ -10790,26 +11301,25 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
(ptr_info.flags.vector_index == .none or val_ty.toIntern() == .bool_type))
break :fallback try cg.airLoad(inst);
var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
- var res = try ops[0].load(val_ty, .{
+ const res = try ops[0].load(val_ty, .{
.disp = switch (ptr_info.flags.vector_index) {
.none => 0,
.runtime => unreachable,
else => |vector_index| @intCast(val_ty.abiSize(zcu) * @intFromEnum(vector_index)),
},
}, cg);
- for (ops) |op| if (op.index != res.index) try op.die(cg);
- try res.moveTo(inst, cg);
+ try res.finish(inst, &.{ty_op.operand}, &ops, cg);
},
.int_from_ptr => if (use_old) try cg.airIntFromPtr(inst) else {
const un_op = air_datas[@intFromEnum(inst)].un_op;
var ops = try cg.tempsFromOperands(inst, .{un_op});
try ops[0].toSlicePtr(cg);
- try ops[0].moveTo(inst, cg);
+ try ops[0].finish(inst, &.{un_op}, &ops, cg);
},
.int_from_bool => if (use_old) try cg.airIntFromBool(inst) else {
const un_op = air_datas[@intFromEnum(inst)].un_op;
- var ops = try cg.tempsFromOperands(inst, .{un_op});
- try ops[0].moveTo(inst, cg);
+ const ops = try cg.tempsFromOperands(inst, .{un_op});
+ try ops[0].finish(inst, &.{un_op}, &ops, cg);
},
.ret => try cg.airRet(inst, false),
.ret_safe => try cg.airRet(inst, true),
@@ -10848,8 +11358,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.unreach => {},
.optional_payload_ptr => if (use_old) try cg.airOptionalPayloadPtr(inst) else {
const ty_op = air_datas[@intFromEnum(inst)].ty_op;
- var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
- try ops[0].moveTo(inst, cg);
+ const ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
+ try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);
},
.optional_payload_ptr_set => if (use_old) try cg.airOptionalPayloadPtrSet(inst) else {
const ty_op = air_datas[@intFromEnum(inst)].ty_op;
@@ -10864,7 +11374,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
try has_value.die(cg);
try ops[0].toOffset(-opt_child_abi_size, cg);
}
- try ops[0].moveTo(inst, cg);
+ try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);
},
.unwrap_errunion_payload_ptr => if (use_old) try cg.airUnwrapErrUnionPayloadPtr(inst) else {
const ty_op = air_datas[@intFromEnum(inst)].ty_op;
@@ -10873,7 +11383,7 @@ 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_pl_off, cg);
- try ops[0].moveTo(inst, cg);
+ try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);
},
.unwrap_errunion_err_ptr => if (use_old) try cg.airUnwrapErrUnionErrPtr(inst) else {
const ty_op = air_datas[@intFromEnum(inst)].ty_op;
@@ -10882,9 +11392,8 @@ 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);
- try ops[0].die(cg);
- try err.moveTo(inst, cg);
+ const err = try ops[0].load(eu_ty.errorUnionSet(zcu), .{}, cg);
+ try err.finish(inst, &.{ty_op.operand}, &ops, cg);
},
.errunion_payload_ptr_set => if (use_old) try cg.airErrUnionPayloadPtrSet(inst) else {
const ty_op = air_datas[@intFromEnum(inst)].ty_op;
@@ -10899,7 +11408,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
try ops[0].store(&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);
+ try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);
},
.struct_field_ptr => if (use_old) try cg.airStructFieldPtr(inst) else {
const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
@@ -10910,7 +11419,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
ty_pl.ty.toType(),
extra.field_index,
), cg);
- try ops[0].moveTo(inst, cg);
+ try ops[0].finish(inst, &.{extra.struct_operand}, &ops, cg);
},
.struct_field_ptr_index_0,
.struct_field_ptr_index_1,
@@ -10936,7 +11445,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.struct_field_ptr_index_3 => 3,
},
), cg);
- try ops[0].moveTo(inst, cg);
+ try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);
},
.struct_field_val => if (use_old) try cg.airStructFieldVal(inst) else fallback: {
const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
@@ -10953,8 +11462,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
try ops[0].read(field_ty, .{ .disp = field_off }, cg)
else
try cg.tempInit(field_ty, .none);
- for (ops) |op| if (op.index != res.index) try op.die(cg);
- try res.moveTo(inst, cg);
+ try res.finish(inst, &.{extra.struct_operand}, &ops, cg);
},
.set_union_tag => if (use_old) try cg.airSetUnionTag(inst) else {
const bin_op = air_datas[@intFromEnum(inst)].bin_op;
@@ -10965,7 +11473,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
if (union_layout.tag_size > 0) try ops[0].store(&ops[1], .{
.disp = @intCast(union_layout.tagOffset()),
}, cg);
- for (ops) |op| try op.die(cg);
+ const res = try cg.tempInit(.void, .none);
+ try res.finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg);
},
.get_union_tag => if (use_old) try cg.airGetUnionTag(inst) else {
const ty_op = air_datas[@intFromEnum(inst)].ty_op;
@@ -10973,42 +11482,41 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
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(ty_op.ty.toType(), .{
+ const res = try ops[0].read(ty_op.ty.toType(), .{
.disp = @intCast(union_layout.tagOffset()),
}, cg);
- for (ops) |op| if (op.index != res.index) try op.die(cg);
- try res.moveTo(inst, cg);
+ try res.finish(inst, &.{ty_op.operand}, &ops, 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;
var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
try ops[0].toPair(&ops[1], cg);
- try ops[0].moveTo(inst, cg);
+ try ops[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg);
},
.slice_len => if (use_old) try cg.airSliceLen(inst) else {
const ty_op = air_datas[@intFromEnum(inst)].ty_op;
var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
try ops[0].toSliceLen(cg);
- try ops[0].moveTo(inst, cg);
+ try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);
},
.slice_ptr => if (use_old) try cg.airSlicePtr(inst) else {
const ty_op = air_datas[@intFromEnum(inst)].ty_op;
var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
try ops[0].toSlicePtr(cg);
- try ops[0].moveTo(inst, cg);
+ try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);
},
.ptr_slice_len_ptr => if (use_old) try cg.airPtrSliceLenPtr(inst) else {
const ty_op = air_datas[@intFromEnum(inst)].ty_op;
var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
try ops[0].toOffset(8, cg);
- try ops[0].moveTo(inst, cg);
+ try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);
},
.ptr_slice_ptr_ptr => if (use_old) try cg.airPtrSlicePtrPtr(inst) else {
const ty_op = air_datas[@intFromEnum(inst)].ty_op;
var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
try ops[0].toOffset(0, cg);
- try ops[0].moveTo(inst, cg);
+ try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);
},
.slice_elem_val, .ptr_elem_val => |air_tag| if (use_old) switch (air_tag) {
else => unreachable,
@@ -11139,10 +11647,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
// hack around Sema OPV bugs
res[0] = try cg.tempInit(res_ty, .none);
}
- for (ops) |op| for (res) |r| {
- if (op.index == r.index) break;
- } else try op.die(cg);
- try res[0].moveTo(inst, cg);
+ try res[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg);
},
.slice_elem_ptr, .ptr_elem_ptr => |air_tag| if (use_old) switch (air_tag) {
else => unreachable,
@@ -11195,8 +11700,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
} },
});
}
- try ops[1].die(cg);
- try ops[0].moveTo(inst, cg);
+ try ops[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg);
},
.array_to_slice => if (use_old) try cg.airArrayToSlice(inst) else {
const ty_op = air_datas[@intFromEnum(inst)].ty_op;
@@ -11205,7 +11709,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.immediate = cg.typeOf(ty_op.operand).childType(zcu).arrayLen(zcu),
});
try ops[0].toPair(&len, cg);
- try ops[0].moveTo(inst, cg);
+ try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);
},
.error_set_has_value => return cg.fail("TODO implement error_set_has_value", .{}),
.union_init => if (use_old) try cg.airUnionInit(inst) else {
@@ -11228,8 +11732,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
try res.write(&ops[0], .{
.disp = @intCast(union_layout.payloadOffset()),
}, cg);
- try ops[0].die(cg);
- try res.moveTo(inst, cg);
+ try res.finish(inst, &.{extra.init}, &ops, cg);
},
.field_parent_ptr => if (use_old) try cg.airFieldParentPtr(inst) else {
const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
@@ -11240,7 +11743,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
cg.typeOf(extra.field_ptr),
extra.field_index,
), cg);
- try ops[0].moveTo(inst, cg);
+ try ops[0].finish(inst, &.{extra.field_ptr}, &ops, cg);
},
.is_named_enum_value => return cg.fail("TODO implement is_named_enum_value", .{}),
@@ -11274,8 +11777,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.addrspace_cast => {
const ty_op = air_datas[@intFromEnum(inst)].ty_op;
- var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
- try ops[0].moveTo(inst, cg);
+ const ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
+ try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);
},
.save_err_return_trace_index => {
@@ -21474,11 +21977,16 @@ fn airRet(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void {
const ret_ty = self.fn_type.fnReturnType(zcu);
switch (self.ret_mcv.short) {
.none => {},
- .register,
- .register_pair,
- .register_triple,
- .register_quadruple,
- => try self.genCopy(ret_ty, self.ret_mcv.short, .{ .air_ref = un_op }, .{ .safety = safety }),
+ .register => |reg| {
+ const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
+ defer self.register_manager.unlockReg(reg_lock);
+ try self.genCopy(ret_ty, self.ret_mcv.short, .{ .air_ref = un_op }, .{ .safety = safety });
+ },
+ inline .register_pair, .register_triple, .register_quadruple => |regs| {
+ const reg_locks = self.register_manager.lockRegsAssumeUnused(regs.len, regs);
+ defer for (reg_locks) |reg_lock| self.register_manager.unlockReg(reg_lock);
+ try self.genCopy(ret_ty, self.ret_mcv.short, .{ .air_ref = un_op }, .{ .safety = safety });
+ },
.indirect => |reg_off| {
try self.register_manager.getReg(reg_off.reg, null);
const lock = self.register_manager.lockRegAssumeUnused(reg_off.reg);
@@ -29772,6 +30280,7 @@ const Temp = struct {
cg.temp_type[@intFromEnum(result_temp_index)] = .slice_const_u8;
result_temp_index.tracking(cg).* = .init(result);
first_temp.* = result_temp;
+ second_temp.* = result_temp;
}
fn asMask(temp: Temp, info: MaskInfo, cg: *CodeGen) void {
@@ -30248,7 +30757,20 @@ const Temp = struct {
try cg.asmOpOnly(.{ .@"rep _sb", .sto });
}
- fn moveTo(temp: Temp, inst: Air.Inst.Index, cg: *CodeGen) !void {
+ fn finish(
+ temp: Temp,
+ inst: Air.Inst.Index,
+ op_refs: []const Air.Inst.Ref,
+ op_temps: []const Temp,
+ cg: *CodeGen,
+ ) !void {
+ const tomb_bits = cg.liveness.getTombBits(inst);
+ for (0.., op_refs, op_temps) |op_index, op_ref, op_temp| {
+ if (op_temp.index != temp.index) try op_temp.die(cg);
+ if (tomb_bits & @as(Liveness.Bpi, 1) << @intCast(op_index) == 0) continue;
+ if (cg.reused_operands.isSet(op_index)) continue;
+ try cg.processDeath(op_ref.toIndexAllowNone() orelse continue);
+ }
if (cg.liveness.isUnused(inst)) try temp.die(cg) else switch (temp.unwrap(cg)) {
.ref, .err_ret_trace => {
const result = try cg.allocRegOrMem(inst, true);
@@ -30529,35 +31051,94 @@ const Select = struct {
};
switch (mir_tag[0]) {
.f_ => switch (mir_tag[1]) {
- .abs, .st => {},
+ .@"2xm1",
+ .abs,
+ .add,
+ .chs,
+ .clex,
+ .com,
+ .comi,
+ .cos,
+ .div,
+ .divr,
+ .free,
+ .mul,
+ .nop,
+ .prem,
+ .rndint,
+ .scale,
+ .sin,
+ .sqrt,
+ .st,
+ .sub,
+ .subr,
+ .tst,
+ .ucom,
+ .ucomi,
+ .wait,
+ .xam,
+ .xch,
+ => {},
+ .init, .save => s.top = 0,
+ .ld, .ptan, .sincos, .xtract => s.top -%= 1,
+ .patan, .yl2x => s.top +%= 1,
+ .rstor => unreachable,
+ else => unreachable,
+ },
+ .f_1 => switch (mir_tag[1]) {
.ld => s.top -%= 1,
- else => {
- const fixes = @tagName(mir_tag[0]);
- const fixes_blank = std.mem.indexOfScalar(u8, fixes, '_').?;
- std.debug.panic("{s}: {s}{s}{s}\n", .{
- @src().fn_name,
- fixes[0..fixes_blank],
- @tagName(mir_tag[1]),
- fixes[fixes_blank + 1 ..],
- });
- },
+ .prem => {},
+ else => unreachable,
},
- .f_p => switch (mir_tag[1]) {
+ .f_b, .f_be, .f_e, .f_nb, .f_nbe, .f_ne, .f_nu, .f_u => switch (mir_tag[1]) {
+ .cmov => {},
+ else => unreachable,
+ },
+ .f_cw, .f_env, .f_sw => switch (mir_tag[1]) {
+ .ld, .st => {},
+ else => unreachable,
+ },
+ .f_p1 => switch (mir_tag[1]) {
+ .yl2x => s.top +%= 1,
+ else => unreachable,
+ },
+ .fb_ => switch (mir_tag[1]) {
+ .ld => s.top -%= 1,
+ else => unreachable,
+ },
+ .fb_p => switch (mir_tag[1]) {
.st => s.top +%= 1,
- else => {
- const fixes = @tagName(mir_tag[0]);
- const fixes_blank = std.mem.indexOfScalar(u8, fixes, '_').?;
- std.debug.panic("{s}: {s}{s}{s}\n", .{
- @src().fn_name,
- fixes[0..fixes_blank],
- @tagName(mir_tag[1]),
- fixes[fixes_blank + 1 ..],
- });
- },
+ else => unreachable,
},
- .f_1,
- => switch (mir_tag[1]) {
+ .fi_ => switch (mir_tag[1]) {
+ .add, .com, .div, .divr, .mul, .st, .stt, .sub, .subr => {},
.ld => s.top -%= 1,
+ else => unreachable,
+ },
+ .fi_p => switch (mir_tag[1]) {
+ .com, .st => s.top +%= 1,
+ else => unreachable,
+ },
+ .fn_ => switch (mir_tag[1]) {
+ .clex => {},
+ .init, .save => s.top = 0,
+ else => unreachable,
+ },
+ .fn_cw, .fn_env, .fn_sw => switch (mir_tag[1]) {
+ .st => {},
+ else => unreachable,
+ },
+ .f_cstp => switch (mir_tag[1]) {
+ .de => s.top -%= 1,
+ .in => s.top +%= 1,
+ else => unreachable,
+ },
+ .f_l2e, .f_l2t, .f_lg2, .f_ln2, .f_pi, .f_z => switch (mir_tag[1]) {
+ .ld => s.top -%= 1,
+ else => unreachable,
+ },
+ .f_p => switch (mir_tag[1]) {
+ .add, .com, .comi, .div, .divr, .mul, .st, .sub, .subr, .ucom, .ucomi => s.top +%= 1,
else => {
const fixes = @tagName(mir_tag[0]);
const fixes_blank = std.mem.indexOfScalar(u8, fixes, '_').?;
@@ -30569,41 +31150,13 @@ const Select = struct {
});
},
},
- .f_l2e,
- .f_l2t,
- .f_lg2,
- .f_ln2,
- .f_pi,
- .f_z,
- => switch (mir_tag[1]) {
- .ld => s.top -%= 1,
+ .f_pp => switch (mir_tag[1]) {
+ .com, .ucom => s.top +%= 2,
else => unreachable,
},
- .f_b,
- .f_be,
- .f_cw,
- .f_e,
- .f_env,
- .f_nb,
- .f_nbe,
- .f_ne,
- .f_nu,
- .f_p1,
- .f_pp,
- .f_sw,
- .f_u,
- .fb_,
- .fb_p,
- .fi_,
- .fi_p,
- .fn_,
- .fn_cw,
- .fn_env,
- .fn_sw,
- => {},
- .f_cstp => switch (mir_tag[1]) {
- .de => s.top -%= 1,
- .in => s.top +%= 1,
+ .fx_ => switch (mir_tag[1]) {
+ .rstor => unreachable,
+ .save => {},
else => unreachable,
},
else => {},
@@ -30620,9 +31173,13 @@ const Select = struct {
dst_constraints: [@intFromEnum(Select.Operand.Ref.src0) - @intFromEnum(Select.Operand.Ref.dst0)]Constraint = @splat(.any),
src_constraints: [@intFromEnum(Select.Operand.Ref.none) - @intFromEnum(Select.Operand.Ref.src0)]Constraint = @splat(.any),
patterns: []const Select.Pattern,
+ call_frame: packed struct(u16) { size: u10, alignment: InternPool.Alignment } = .{ .size = 0, .alignment = .none },
extra_temps: [@intFromEnum(Select.Operand.Ref.dst0) - @intFromEnum(Select.Operand.Ref.tmp0)]TempSpec = @splat(.unused),
dst_temps: [@intFromEnum(Select.Operand.Ref.src0) - @intFromEnum(Select.Operand.Ref.dst0)]TempSpec.Kind = @splat(.unused),
- clobbers: struct { eflags: bool = false, st: u3 = 0 } = .{},
+ clobbers: packed struct {
+ eflags: bool = false,
+ caller_preserved: enum(u2) { none, ccc, zigcc } = .none,
+ } = .{},
each: union(enum) {
once: []const Instruction,
},
@@ -30649,6 +31206,7 @@ const Select = struct {
scalar_signed_int: Memory.Size,
scalar_unsigned_int: Memory.Size,
scalar_remainder_int: struct { of: Memory.Size, is: Memory.Size },
+ float: Memory.Size,
scalar_float: struct { of: Memory.Size, is: Memory.Size },
scalar_exact_float: struct { of: Memory.Size, is: Memory.Size },
multiple_scalar_int: struct { of: Memory.Size, is: Memory.Size },
@@ -30716,6 +31274,7 @@ const Select = struct {
of_is.is.bitSize(cg.target) >= (int_info.bits - 1) % of_is.of.bitSize(cg.target) + 1
else
false,
+ .float => |size| if (cg.floatBits(ty)) |float_bits| size.bitSize(cg.target) == float_bits else false,
.scalar_float => |of_is| @divExact(of_is.of.bitSize(cg.target), 8) >= ty.abiSize(zcu) and
if (cg.floatBits(ty.scalarType(zcu))) |float_bits| of_is.is.bitSize(cg.target) >= float_bits else false,
.scalar_exact_float => |of_is| @divExact(of_is.of.bitSize(cg.target), 8) >= ty.abiSize(zcu) and
@@ -30787,13 +31346,14 @@ const Select = struct {
src: [2]Src,
commute: struct { u8, u8 } = .{ 0, 0 },
- const Src = enum {
+ const Src = union(enum) {
none,
any,
imm8,
imm16,
imm32,
simm32,
+ to_reg: Register,
mem,
to_mem,
mut_mem,
@@ -30846,6 +31406,7 @@ const Select = struct {
.mem => temp.tracking(cg).short.isMemory(),
.to_mem, .to_mut_mem => true,
.mut_mem => temp.isMut(cg) and temp.tracking(cg).short.isMemory(),
+ .to_reg => true,
.gpr => temp.typeOf(cg).abiSize(cg.pt.zcu) <= 8 and switch (temp.tracking(cg).short) {
.register => |reg| reg.class() == .general_purpose,
.register_offset => |reg_off| reg_off.reg.class() == .general_purpose and reg_off.off == 0,
@@ -30920,6 +31481,7 @@ const Select = struct {
.none => unreachable,
.any, .imm8, .imm16, .imm32, .simm32 => false,
.mem, .to_mem, .mut_mem, .to_mut_mem => try temp.toBase(cg),
+ .to_reg => |reg| try temp.toReg(reg, cg),
.gpr, .to_gpr => try temp.toRegClass(false, .general_purpose, cg),
.mut_gpr, .to_mut_gpr => try temp.toRegClass(true, .general_purpose, cg),
.x87, .to_x87 => try temp.toRegClass(false, .x87, cg),
@@ -30954,6 +31516,7 @@ const Select = struct {
ref: Select.Operand.Ref,
ref_mask: struct { ref: Select.Operand.Ref, info: MaskInfo },
mut_reg: struct { ref: Select.Operand.Ref, rc: Register.Class },
+ symbol: *const struct { lib: ?[]const u8 = null, name: []const u8 },
const ConstInfo = struct { ref: Select.Operand.Ref, vectorize: bool = false };
@@ -31048,6 +31611,11 @@ const Select = struct {
};
return try cg.tempAllocReg(spec.type, regSetForRegClass(ref_rc.rc));
},
+ .symbol => |symbol| if (cg.bin_file.cast(.elf)) |elf_file| try cg.tempInit(spec.type, .{ .lea_symbol = .{
+ .sym_index = try elf_file.getGlobalSymbol(symbol.name, symbol.lib),
+ } }) else if (cg.bin_file.cast(.macho)) |macho_file| try cg.tempInit(spec.type, .{ .lea_symbol = .{
+ .sym_index = try macho_file.getGlobalSymbol(symbol.name, symbol.lib),
+ } }) else cg.fail("external symbols unimplemented for {s}", .{@tagName(cg.bin_file.tag)}),
};
}
};
@@ -31566,6 +32134,7 @@ const Select = struct {
} },
else => |mcv| .{ .mem = try mcv.mem(s.cg, .{ .size = op.base.size }) },
.register => |reg| .{ .reg = s.lowerReg(registerAlias(reg, @intCast(@divExact(op.base.size.bitSize(s.cg.target), 8)))) },
+ .lea_symbol => |sym_off| .{ .imm = .rel(sym_off) },
},
.simm => .{ .imm = .s(op.adjustedImm(i32, s)) },
.uimm => .{ .imm = .u(@bitCast(op.adjustedImm(i64, s))) },
@@ -31601,6 +32170,7 @@ fn select(
src_temps: []Temp,
cases: []const Select.Case,
) !void {
+ @setEvalBranchQuota(33_600);
cases: for (cases) |case| {
for (case.required_features) |required_feature| if (required_feature) |feature| if (!cg.hasFeature(feature)) continue :cases;
for (case.dst_constraints[0..dst_temps.len], dst_tys) |dst_constraint, dst_ty| if (!dst_constraint.accepts(dst_ty, cg)) continue :cases;
@@ -31613,6 +32183,16 @@ fn select(
for (pattern.src[0..src_temps.len], src_temps) |src_pattern, src_temp| if (!src_pattern.matches(src_temp, cg)) continue :patterns;
if (std.debug.runtime_safety) for (pattern.src[src_temps.len..]) |src_pattern| assert(src_pattern == .none);
+ if (case.call_frame.alignment != .none) {
+ const frame_allocs_slice = cg.frame_allocs.slice();
+ const stack_frame_size =
+ &frame_allocs_slice.items(.abi_size)[@intFromEnum(FrameIndex.call_frame)];
+ stack_frame_size.* = @max(stack_frame_size.*, case.call_frame.size);
+ const stack_frame_align =
+ &frame_allocs_slice.items(.abi_align)[@intFromEnum(FrameIndex.call_frame)];
+ stack_frame_align.* = stack_frame_align.max(case.call_frame.alignment);
+ }
+
var s: Select = .{
.cg = cg,
.temps = undefined,
@@ -31623,10 +32203,19 @@ fn select(
const dst_slots = s.temps[@intFromEnum(Select.Operand.Ref.dst0)..@intFromEnum(Select.Operand.Ref.src0)];
const src_slots = s.temps[@intFromEnum(Select.Operand.Ref.src0)..@intFromEnum(Select.Operand.Ref.none)];
- for (0..case.clobbers.st -| 1) |i| {
- const tracked_index: RegisterManager.TrackedIndex = @intCast(RegisterManager.indexOfKnownRegIntoTracked(.st6).? - i);
- try cg.register_manager.getRegIndex(tracked_index, null);
- _ = cg.register_manager.lockRegIndexAssumeUnused(tracked_index);
+ caller_preserved: {
+ switch (switch (case.clobbers.caller_preserved) {
+ .none => break :caller_preserved,
+ .ccc => cg.target.cCallingConvention().?,
+ .zigcc => .auto,
+ }) {
+ else => unreachable,
+ inline .x86_64_sysv, .x86_64_win, .auto => |_, tag| inline for (comptime abi.getCallerPreservedRegs(tag)) |reg| {
+ const tracked_index = RegisterManager.indexOfKnownRegIntoTracked(reg) orelse continue;
+ try cg.register_manager.getRegIndex(tracked_index, null);
+ assert(cg.register_manager.lockRegIndexAssumeUnused(tracked_index).tracked_index == tracked_index);
+ },
+ }
}
@memcpy(src_slots[0..src_temps.len], src_temps);
@@ -31653,9 +32242,20 @@ fn select(
}
assert(s.top == 0);
- for (0..case.clobbers.st -| 1) |i| cg.register_manager.unlockReg(.{
- .tracked_index = @intCast(RegisterManager.indexOfKnownRegIntoTracked(.st6).? - i),
- });
+ caller_preserved: {
+ switch (switch (case.clobbers.caller_preserved) {
+ .none => break :caller_preserved,
+ .ccc => cg.target.cCallingConvention().?,
+ .zigcc => .auto,
+ }) {
+ else => unreachable,
+ inline .x86_64_sysv, .x86_64_win, .auto => |_, tag| inline for (comptime abi.getCallerPreservedRegs(tag)) |reg| {
+ cg.register_manager.unlockReg(.{
+ .tracked_index = RegisterManager.indexOfKnownRegIntoTracked(reg) orelse continue,
+ });
+ },
+ }
+ }
for (dst_temps, case.dst_temps[0..dst_temps.len]) |dst_temp, dst_kind| dst_kind.finish(dst_temp, &s);
for (case.extra_temps, tmp_slots) |spec, temp| if (spec.kind != .unused) try temp.die(cg);
return;
src/arch/x86_64/Encoding.zig
@@ -361,7 +361,7 @@ pub const Mnemonic = enum {
addps, addss,
andps,
andnps,
- cmpps, cmpss,
+ cmpps, cmpss, comiss,
cvtpi2ps, cvtps2pi, cvtsi2ss, cvtss2si, cvttps2pi, cvttss2si,
divps, divss,
fxrstor, fxrstor64, fxsave, fxsave64,
@@ -386,7 +386,7 @@ pub const Mnemonic = enum {
andpd,
andnpd,
cmppd, //cmpsd,
- comisd, comiss,
+ comisd,
cvtdq2pd, cvtdq2ps, cvtpd2dq, cvtpd2pi, cvtpd2ps, cvtpi2pd,
cvtps2dq, cvtps2pd, cvtsd2si, cvtsd2ss, cvtsi2sd, cvtss2sd,
cvttpd2dq, cvttpd2pi, cvttps2dq, cvttsd2si,
@@ -504,6 +504,7 @@ pub const Mnemonic = enum {
vstmxcsr,
vsubpd, vsubps, vsubsd, vsubss,
vtestpd, vtestps,
+ vucomisd, vucomiss,
vxorpd, vxorps,
// F16C
vcvtph2ps, vcvtps2ph,
src/arch/x86_64/encodings.zig
@@ -437,6 +437,7 @@ pub const table = [_]Entry{
.{ .jmp, .d, &.{ .rel32 }, &.{ 0xe9 }, 0, .none, .none },
.{ .jmp, .m, &.{ .rm64 }, &.{ 0xff }, 4, .none, .none },
+ .{ .lahf, .z, &.{}, &.{ 0x9f }, 0, .none, .@"32bit" },
.{ .lahf, .z, &.{}, &.{ 0x9f }, 0, .none, .sahf },
.{ .lar, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x02 }, 0, .none, .none },
@@ -744,6 +745,7 @@ pub const table = [_]Entry{
.{ .rsm, .z, &.{}, &.{ 0x0f, 0xaa }, 0, .none, .none },
+ .{ .sahf, .z, &.{}, &.{ 0x9e }, 0, .none, .@"32bit" },
.{ .sahf, .z, &.{}, &.{ 0x9e }, 0, .none, .sahf },
.{ .sal, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .none, .none },
@@ -2275,6 +2277,10 @@ pub const table = [_]Entry{
.{ .vtestpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x0f }, 0, .vex_128_w0, .avx },
.{ .vtestpd, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x38, 0x0f }, 0, .vex_256_w0, .avx },
+ .{ .vucomisd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0x66, 0x0f, 0x2e }, 0, .vex_lig_wig, .avx },
+
+ .{ .vucomiss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0x0f, 0x2e }, 0, .vex_lig_wig, .avx },
+
.{ .vxorpd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x57 }, 0, .vex_128_wig, .avx },
.{ .vxorpd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x57 }, 0, .vex_256_wig, .avx },
src/arch/x86_64/Mir.zig
@@ -354,6 +354,8 @@ pub const Inst = struct {
fn_env,
/// Float No Wait ___ status word
fn_sw,
+ /// Float Extended ___
+ fx_,
/// ___ in 32-bit and Compatibility Mode
_32,
@@ -817,8 +819,10 @@ pub const Inst = struct {
/// Round to integer
rndint,
/// Restore x87 FPU state
+ /// Restore x87 FPU, MMX, XMM, and MXCSR state
rstor,
/// Store x87 FPU state
+ /// Save x87 FPU, MMX technology, and MXCSR state
save,
/// Scale
scale,
@@ -923,10 +927,6 @@ pub const Inst = struct {
/// Extract doubleword
/// Extract quadword
extr,
- /// Restore x87 FPU, MMX, XMM, and MXCSR state
- fxrstor,
- /// Save x87 FPU, MMX technology, and MXCSR state
- fxsave,
/// Insert byte
/// Insert word
/// Insert doubleword
test/behavior/x86_64/math.zig
@@ -17,8 +17,23 @@ const Sse = if (std.Target.x86.featureSetHas(builtin.cpu.features, .avx))
else
@Vector(16, u8);
-inline fn sign(rhs: anytype) bool {
- return @call(.always_inline, math.signbit, .{rhs});
+inline fn sign(rhs: anytype) switch (@typeInfo(@TypeOf(rhs))) {
+ else => bool,
+ .vector => |vector| @Vector(vector.len, bool),
+} {
+ switch (@typeInfo(@TypeOf(rhs))) {
+ else => return @as(@Type(.{ .int = .{
+ .signedness = .signed,
+ .bits = @bitSizeOf(@TypeOf(rhs)),
+ } }), @bitCast(rhs)) < 0,
+ .vector => |vector| {
+ const V = @Vector(vector.len, @Type(.{ .int = .{
+ .signedness = .signed,
+ .bits = @bitSizeOf(vector.child),
+ } }));
+ return @as(V, @bitCast(rhs)) < @as(V, @splat(0));
+ },
+ }
}
inline fn boolAnd(lhs: anytype, rhs: @TypeOf(lhs)) @TypeOf(lhs) {
switch (@typeInfo(@TypeOf(lhs))) {
@@ -69,12 +84,40 @@ noinline fn checkExpected(expected: anytype, actual: @TypeOf(expected)) !void {
}) return error.Unexpected;
}
test checkExpected {
+ if (checkExpected(nan(f16), nan(f16)) == error.Unexpected) return error.Unexpected;
+ if (checkExpected(nan(f16), -nan(f16)) != error.Unexpected) return error.Unexpected;
+ if (checkExpected(@as(f16, 0.0), @as(f16, 0.0)) == error.Unexpected) return error.Unexpected;
+ if (checkExpected(@as(f16, -0.0), @as(f16, -0.0)) == error.Unexpected) return error.Unexpected;
+ if (checkExpected(@as(f16, -0.0), @as(f16, 0.0)) != error.Unexpected) return error.Unexpected;
+ if (checkExpected(@as(f16, 0.0), @as(f16, -0.0)) != error.Unexpected) return error.Unexpected;
+
if (checkExpected(nan(f32), nan(f32)) == error.Unexpected) return error.Unexpected;
if (checkExpected(nan(f32), -nan(f32)) != error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f32, 0.0), @as(f32, 0.0)) == error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f32, -0.0), @as(f32, -0.0)) == error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f32, -0.0), @as(f32, 0.0)) != error.Unexpected) return error.Unexpected;
if (checkExpected(@as(f32, 0.0), @as(f32, -0.0)) != error.Unexpected) return error.Unexpected;
+
+ if (checkExpected(nan(f64), nan(f64)) == error.Unexpected) return error.Unexpected;
+ if (checkExpected(nan(f64), -nan(f64)) != error.Unexpected) return error.Unexpected;
+ if (checkExpected(@as(f64, 0.0), @as(f64, 0.0)) == error.Unexpected) return error.Unexpected;
+ if (checkExpected(@as(f64, -0.0), @as(f64, -0.0)) == error.Unexpected) return error.Unexpected;
+ if (checkExpected(@as(f64, -0.0), @as(f64, 0.0)) != error.Unexpected) return error.Unexpected;
+ if (checkExpected(@as(f64, 0.0), @as(f64, -0.0)) != error.Unexpected) return error.Unexpected;
+
+ if (checkExpected(nan(f80), nan(f80)) == error.Unexpected) return error.Unexpected;
+ if (checkExpected(nan(f80), -nan(f80)) != error.Unexpected) return error.Unexpected;
+ if (checkExpected(@as(f80, 0.0), @as(f80, 0.0)) == error.Unexpected) return error.Unexpected;
+ if (checkExpected(@as(f80, -0.0), @as(f80, -0.0)) == error.Unexpected) return error.Unexpected;
+ if (checkExpected(@as(f80, -0.0), @as(f80, 0.0)) != error.Unexpected) return error.Unexpected;
+ if (checkExpected(@as(f80, 0.0), @as(f80, -0.0)) != error.Unexpected) return error.Unexpected;
+
+ if (checkExpected(nan(f128), nan(f128)) == error.Unexpected) return error.Unexpected;
+ if (checkExpected(nan(f128), -nan(f128)) != error.Unexpected) return error.Unexpected;
+ if (checkExpected(@as(f128, 0.0), @as(f128, 0.0)) == error.Unexpected) return error.Unexpected;
+ if (checkExpected(@as(f128, -0.0), @as(f128, -0.0)) == error.Unexpected) return error.Unexpected;
+ if (checkExpected(@as(f128, -0.0), @as(f128, 0.0)) != error.Unexpected) return error.Unexpected;
+ if (checkExpected(@as(f128, 0.0), @as(f128, -0.0)) != error.Unexpected) return error.Unexpected;
}
fn Unary(comptime op: anytype) type {