diff options
| author | Jacob Young <jacobly0@users.noreply.github.com> | 2023-03-17 22:07:32 -0400 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2023-03-21 08:49:54 +0100 |
| commit | 30e1daa7463c766e23f57e6a89e4e0ffd4918be5 (patch) | |
| tree | 39b7b2eb2288f1492c5bea004e2a46f973c0b84b | |
| parent | 29e6aedc95766f960d7dbc92c862a82bf40faafd (diff) | |
| download | zig-30e1daa7463c766e23f57e6a89e4e0ffd4918be5.tar.gz zig-30e1daa7463c766e23f57e6a89e4e0ffd4918be5.zip | |
x86_64: implement basic float ops
| -rw-r--r-- | src/arch/x86_64/CodeGen.zig | 172 | ||||
| -rw-r--r-- | src/arch/x86_64/Emit.zig | 10 | ||||
| -rw-r--r-- | src/arch/x86_64/Encoding.zig | 8 | ||||
| -rw-r--r-- | src/arch/x86_64/Mir.zig | 24 | ||||
| -rw-r--r-- | src/arch/x86_64/encodings.zig | 20 | ||||
| -rw-r--r-- | test/behavior/maximum_minimum.zig | 2 |
6 files changed, 154 insertions, 82 deletions
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 4e4fe8823f..d18f99923e 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/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) }, diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index 4e2c1db9af..e9d09a4ef6 100644 --- a/src/arch/x86_64/Emit.zig +++ b/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), diff --git a/src/arch/x86_64/Encoding.zig b/src/arch/x86_64/Encoding.zig index a51f954aed..d0ede962cb 100644 --- a/src/arch/x86_64/Encoding.zig +++ b/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 }; diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig index ed0606e87a..6f3bf6c745 100644 --- a/src/arch/x86_64/Mir.zig +++ b/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, diff --git a/src/arch/x86_64/encodings.zig b/src/arch/x86_64/encodings.zig index b008eb9f3e..dc7b51521d 100644 --- a/src/arch/x86_64/encodings.zig +++ b/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 }, diff --git a/test/behavior/maximum_minimum.zig b/test/behavior/maximum_minimum.zig index 34a7d0976a..d538e2db65 100644 --- a/test/behavior/maximum_minimum.zig +++ b/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 |
