Commit 30e1daa746
Changed files (6)
src
test
behavior
src/arch/x86_64/CodeGen.zig
@@ -1530,21 +1530,23 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void
fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
+ const result = result: {
+ if (self.liveness.isUnused(inst)) break :result .dead;
- if (self.liveness.isUnused(inst)) {
- return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
- }
-
- const tag = self.air.instructions.items(.tag)[inst];
- const ty = self.air.typeOfIndex(inst);
+ const tag = self.air.instructions.items(.tag)[inst];
+ const ty = self.air.typeOfIndex(inst);
- try self.spillRegisters(2, .{ .rax, .rdx });
+ if (ty.zigTypeTag() == .Float) {
+ break :result try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs);
+ }
- const lhs = try self.resolveInst(bin_op.lhs);
- const rhs = try self.resolveInst(bin_op.rhs);
+ try self.spillRegisters(2, .{ .rax, .rdx });
- const result = try self.genMulDivBinOp(tag, inst, ty, lhs, rhs);
+ const lhs = try self.resolveInst(bin_op.lhs);
+ const rhs = try self.resolveInst(bin_op.rhs);
+ break :result try self.genMulDivBinOp(tag, inst, ty, lhs, rhs);
+ };
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}
@@ -3288,10 +3290,10 @@ fn genMulDivBinOp(
rhs: MCValue,
) !MCValue {
if (ty.zigTypeTag() == .Vector or ty.zigTypeTag() == .Float) {
- return self.fail("TODO implement genBinOp for {}", .{ty.fmtDebug()});
+ return self.fail("TODO implement genMulDivBinOp for {}", .{ty.fmtDebug()});
}
if (ty.abiSize(self.target.*) > 8) {
- return self.fail("TODO implement genBinOp for {}", .{ty.fmtDebug()});
+ return self.fail("TODO implement genMulDivBinOp for {}", .{ty.fmtDebug()});
}
if (tag == .div_float) {
return self.fail("TODO implement genMulDivBinOp for div_float", .{});
@@ -3516,11 +3518,31 @@ fn genBinOp(
switch (tag) {
.add,
.addwrap,
- => try self.genBinOpMir(.add, lhs_ty, dst_mcv, src_mcv),
+ => try self.genBinOpMir(switch (lhs_ty.tag()) {
+ else => .add,
+ .f32 => .addss,
+ .f64 => .addsd,
+ }, lhs_ty, dst_mcv, src_mcv),
.sub,
.subwrap,
- => try self.genBinOpMir(.sub, lhs_ty, dst_mcv, src_mcv),
+ => try self.genBinOpMir(switch (lhs_ty.tag()) {
+ else => .sub,
+ .f32 => .subss,
+ .f64 => .subsd,
+ }, lhs_ty, dst_mcv, src_mcv),
+
+ .mul => try self.genBinOpMir(switch (lhs_ty.tag()) {
+ .f32 => .mulss,
+ .f64 => .mulsd,
+ else => return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) }),
+ }, lhs_ty, dst_mcv, src_mcv),
+
+ .div_float => try self.genBinOpMir(switch (lhs_ty.tag()) {
+ .f32 => .divss,
+ .f64 => .divsd,
+ else => return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) }),
+ }, lhs_ty, dst_mcv, src_mcv),
.ptr_add,
.ptr_sub,
@@ -3547,54 +3569,66 @@ fn genBinOp(
.min,
.max,
- => {
- if (!lhs_ty.isAbiInt() or !rhs_ty.isAbiInt()) {
- return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) });
- }
+ => switch (lhs_ty.zigTypeTag()) {
+ .Int => {
+ const mat_src_mcv = switch (src_mcv) {
+ .immediate => MCValue{ .register = try self.copyToTmpRegister(rhs_ty, src_mcv) },
+ else => src_mcv,
+ };
+ const mat_mcv_lock = switch (mat_src_mcv) {
+ .register => |reg| self.register_manager.lockReg(reg),
+ else => null,
+ };
+ defer if (mat_mcv_lock) |lock| self.register_manager.unlockReg(lock);
- const mat_src_mcv = switch (src_mcv) {
- .immediate => MCValue{ .register = try self.copyToTmpRegister(rhs_ty, src_mcv) },
- else => src_mcv,
- };
- const mat_mcv_lock = switch (mat_src_mcv) {
- .register => |reg| self.register_manager.lockReg(reg),
- else => null,
- };
- defer if (mat_mcv_lock) |lock| self.register_manager.unlockReg(lock);
+ try self.genBinOpMir(.cmp, lhs_ty, dst_mcv, mat_src_mcv);
- try self.genBinOpMir(.cmp, lhs_ty, dst_mcv, mat_src_mcv);
+ const int_info = lhs_ty.intInfo(self.target.*);
+ const cc: Condition = switch (int_info.signedness) {
+ .unsigned => switch (tag) {
+ .min => .a,
+ .max => .b,
+ else => unreachable,
+ },
+ .signed => switch (tag) {
+ .min => .g,
+ .max => .l,
+ else => unreachable,
+ },
+ };
- const int_info = lhs_ty.intInfo(self.target.*);
- const cc: Condition = switch (int_info.signedness) {
- .unsigned => switch (tag) {
- .min => .a,
- .max => .b,
+ const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));
+ switch (dst_mcv) {
+ .register => |dst_reg| switch (mat_src_mcv) {
+ .register => |src_reg| try self.asmCmovccRegisterRegister(
+ registerAlias(dst_reg, abi_size),
+ registerAlias(src_reg, abi_size),
+ cc,
+ ),
+ .stack_offset => |off| try self.asmCmovccRegisterMemory(
+ registerAlias(dst_reg, abi_size),
+ Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }),
+ cc,
+ ),
+ else => unreachable,
+ },
else => unreachable,
- },
- .signed => switch (tag) {
- .min => .g,
- .max => .l,
+ }
+ },
+ .Float => try self.genBinOpMir(switch (lhs_ty.tag()) {
+ .f32 => switch (tag) {
+ .min => .minss,
+ .max => .maxss,
else => unreachable,
},
- };
-
- const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));
- switch (dst_mcv) {
- .register => |dst_reg| switch (mat_src_mcv) {
- .register => |src_reg| try self.asmCmovccRegisterRegister(
- registerAlias(dst_reg, abi_size),
- registerAlias(src_reg, abi_size),
- cc,
- ),
- .stack_offset => |off| try self.asmCmovccRegisterMemory(
- registerAlias(dst_reg, abi_size),
- Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }),
- cc,
- ),
+ .f64 => switch (tag) {
+ .min => .minsd,
+ .max => .maxsd,
else => unreachable,
},
- else => unreachable,
- }
+ else => return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) }),
+ }, lhs_ty, dst_mcv, src_mcv),
+ else => return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) }),
},
else => unreachable,
@@ -3626,29 +3660,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
.register => |src_reg| switch (dst_ty.zigTypeTag()) {
.Float => {
if (intrinsicsAllowed(self.target.*, dst_ty)) {
- const actual_tag: Mir.Inst.Tag = switch (dst_ty.tag()) {
- .f32 => switch (mir_tag) {
- .add => .addss,
- .cmp => .ucomiss,
- else => return self.fail(
- "TODO genBinOpMir for f32 register-register with MIR tag {}",
- .{mir_tag},
- ),
- },
- .f64 => switch (mir_tag) {
- .add => .addsd,
- .cmp => .ucomisd,
- else => return self.fail(
- "TODO genBinOpMir for f64 register-register with MIR tag {}",
- .{mir_tag},
- ),
- },
- else => return self.fail(
- "TODO genBinOpMir for float register-register and type {}",
- .{dst_ty.fmtDebug()},
- ),
- };
- return self.asmRegisterRegister(actual_tag, dst_reg.to128(), src_reg.to128());
+ return self.asmRegisterRegister(mir_tag, dst_reg.to128(), src_reg.to128());
}
return self.fail("TODO genBinOpMir for float register-register and no intrinsics", .{});
@@ -4307,7 +4319,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
};
defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
- try self.genBinOpMir(.cmp, ty, dst_mcv, src_mcv);
+ try self.genBinOpMir(switch (ty.tag()) {
+ else => .cmp,
+ .f32 => .ucomiss,
+ .f64 => .ucomisd,
+ }, ty, dst_mcv, src_mcv);
break :result switch (signedness) {
.signed => MCValue{ .eflags = Condition.fromCompareOperatorSigned(op) },
src/arch/x86_64/Emit.zig
@@ -110,11 +110,21 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
.addss,
.cmpss,
+ .divss,
+ .maxss,
+ .minss,
.movss,
+ .mulss,
+ .subss,
.ucomiss,
.addsd,
.cmpsd,
+ .divsd,
+ .maxsd,
+ .minsd,
.movsd,
+ .mulsd,
+ .subsd,
.ucomisd,
=> try emit.mirEncodeGeneric(tag, inst),
src/arch/x86_64/Encoding.zig
@@ -342,12 +342,20 @@ pub const Mnemonic = enum {
// SSE
addss,
cmpss,
+ divss,
+ maxss, minss,
movss,
+ mulss,
+ subss,
ucomiss,
// SSE2
addsd,
cmpsd,
+ divsd,
+ maxsd, minsd,
movq, movsd,
+ mulsd,
+ subsd,
ucomisd,
// zig fmt: on
};
src/arch/x86_64/encodings.zig
@@ -599,9 +599,19 @@ pub const table = &[_]Entry{
.{ .cmpss, .rmi, .xmm, .xmm_m32, .imm8, .none, 3, 0xf3, 0x0f, 0xc2, 0, .sse },
+ .{ .divss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x5e, 0, .sse },
+
+ .{ .maxss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x5f, 0, .sse },
+
+ .{ .minss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x5d, 0, .sse },
+
.{ .movss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x10, 0, .sse },
.{ .movss, .mr, .xmm_m32, .xmm, .none, .none, 3, 0xf3, 0x0f, 0x11, 0, .sse },
+ .{ .mulss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x59, 0, .sse },
+
+ .{ .subss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x5c, 0, .sse },
+
.{ .ucomiss, .rm, .xmm, .xmm_m32, .none, .none, 2, 0x0f, 0x2e, 0x00, 0, .sse },
// SSE2
@@ -609,9 +619,19 @@ pub const table = &[_]Entry{
.{ .cmpsd, .rmi, .xmm, .xmm_m64, .imm8, .none, 3, 0xf2, 0x0f, 0xc2, 0, .sse2 },
+ .{ .divsd, .rm, .xmm, .xmm_m64, .none, .none, 3, 0xf2, 0x0f, 0x5e, 0, .sse2 },
+
+ .{ .maxsd, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf2, 0x0f, 0x5f, 0, .sse2 },
+
+ .{ .minsd, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf2, 0x0f, 0x5d, 0, .sse2 },
+
.{ .movq, .rm, .xmm, .xmm_m64, .none, .none, 3, 0xf3, 0x0f, 0x7e, 0, .sse2 },
.{ .movq, .mr, .xmm_m64, .xmm, .none, .none, 3, 0x66, 0x0f, 0xd6, 0, .sse2 },
+ .{ .mulsd, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf2, 0x0f, 0x59, 0, .sse2 },
+
+ .{ .subsd, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf2, 0x0f, 0x5c, 0, .sse2 },
+
.{ .movsd, .rm, .xmm, .xmm_m64, .none, .none, 3, 0xf2, 0x0f, 0x10, 0, .sse2 },
.{ .movsd, .mr, .xmm_m64, .xmm, .none, .none, 3, 0xf2, 0x0f, 0x11, 0, .sse2 },
src/arch/x86_64/Mir.zig
@@ -109,20 +109,40 @@ pub const Inst = struct {
/// Logical exclusive-or
xor,
- /// Add single precision floating point
+ /// Add single precision floating point values
addss,
/// Compare scalar single-precision floating-point values
cmpss,
+ /// Divide scalar single-precision floating-point values
+ divss,
+ /// Return maximum single-precision floating-point value
+ maxss,
+ /// Return minimum single-precision floating-point value
+ minss,
/// Move scalar single-precision floating-point value
movss,
+ /// Multiply scalar single-precision floating-point values
+ mulss,
+ /// Subtract scalar single-precision floating-point values
+ subss,
/// Unordered compare scalar single-precision floating-point values
ucomiss,
- /// Add double precision floating point
+ /// Add double precision floating point values
addsd,
/// Compare scalar double-precision floating-point values
cmpsd,
+ /// Divide scalar double-precision floating-point values
+ divsd,
+ /// Return maximum double-precision floating-point value
+ maxsd,
+ /// Return minimum double-precision floating-point value
+ minsd,
/// Move scalar double-precision floating-point value
movsd,
+ /// Multiply scalar double-precision floating-point values
+ mulsd,
+ /// Subtract scalar double-precision floating-point values
+ subsd,
/// Unordered compare scalar double-precision floating-point values
ucomisd,
test/behavior/maximum_minimum.zig
@@ -5,7 +5,6 @@ const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
test "@max" {
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -52,7 +51,6 @@ test "@max on vectors" {
}
test "@min" {
- if (builtin.zig_backend == .stage2_x86_64) 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_sparc64) return error.SkipZigTest; // TODO