authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-03-17 22:07:32-04:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-21 08:49:54+01:00
log30e1daa7463c766e23f57e6a89e4e0ffd4918be5
tree39b7b2eb2288f1492c5bea004e2a46f973c0b84b
parent29e6aedc95766f960d7dbc92c862a82bf40faafd

x86_64: implement basic float ops


6 files changed, 154 insertions(+), 82 deletions(-)

src/arch/x86_64/CodeGen.zig+94-78
...@@ -1530,21 +1530,23 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void...@@ -1530,21 +1530,23 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void
15301530
1531fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {1531fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {
1532 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1532 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1533 const result = result: {
1534 if (self.liveness.isUnused(inst)) break :result .dead;
15331535
1534 if (self.liveness.isUnused(inst)) {1536 const tag = self.air.instructions.items(.tag)[inst];
1535 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });1537 const ty = self.air.typeOfIndex(inst);
1536 }
1537
1538 const tag = self.air.instructions.items(.tag)[inst];
1539 const ty = self.air.typeOfIndex(inst);
15401538
1541 try self.spillRegisters(2, .{ .rax, .rdx });1539 if (ty.zigTypeTag() == .Float) {
1540 break :result try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs);
1541 }
15421542
1543 const lhs = try self.resolveInst(bin_op.lhs);1543 try self.spillRegisters(2, .{ .rax, .rdx });
1544 const rhs = try self.resolveInst(bin_op.rhs);
15451544
1546 const result = try self.genMulDivBinOp(tag, inst, ty, lhs, rhs);1545 const lhs = try self.resolveInst(bin_op.lhs);
1546 const rhs = try self.resolveInst(bin_op.rhs);
15471547
1548 break :result try self.genMulDivBinOp(tag, inst, ty, lhs, rhs);
1549 };
1548 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1550 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1549}1551}
15501552
...@@ -3288,10 +3290,10 @@ fn genMulDivBinOp(...@@ -3288,10 +3290,10 @@ fn genMulDivBinOp(
3288 rhs: MCValue,3290 rhs: MCValue,
3289) !MCValue {3291) !MCValue {
3290 if (ty.zigTypeTag() == .Vector or ty.zigTypeTag() == .Float) {3292 if (ty.zigTypeTag() == .Vector or ty.zigTypeTag() == .Float) {
3291 return self.fail("TODO implement genBinOp for {}", .{ty.fmtDebug()});3293 return self.fail("TODO implement genMulDivBinOp for {}", .{ty.fmtDebug()});
3292 }3294 }
3293 if (ty.abiSize(self.target.*) > 8) {3295 if (ty.abiSize(self.target.*) > 8) {
3294 return self.fail("TODO implement genBinOp for {}", .{ty.fmtDebug()});3296 return self.fail("TODO implement genMulDivBinOp for {}", .{ty.fmtDebug()});
3295 }3297 }
3296 if (tag == .div_float) {3298 if (tag == .div_float) {
3297 return self.fail("TODO implement genMulDivBinOp for div_float", .{});3299 return self.fail("TODO implement genMulDivBinOp for div_float", .{});
...@@ -3516,11 +3518,31 @@ fn genBinOp(...@@ -3516,11 +3518,31 @@ fn genBinOp(
3516 switch (tag) {3518 switch (tag) {
3517 .add,3519 .add,
3518 .addwrap,3520 .addwrap,
3519 => try self.genBinOpMir(.add, lhs_ty, dst_mcv, src_mcv),3521 => try self.genBinOpMir(switch (lhs_ty.tag()) {
3522 else => .add,
3523 .f32 => .addss,
3524 .f64 => .addsd,
3525 }, lhs_ty, dst_mcv, src_mcv),
35203526
3521 .sub,3527 .sub,
3522 .subwrap,3528 .subwrap,
3523 => try self.genBinOpMir(.sub, lhs_ty, dst_mcv, src_mcv),3529 => try self.genBinOpMir(switch (lhs_ty.tag()) {
3530 else => .sub,
3531 .f32 => .subss,
3532 .f64 => .subsd,
3533 }, lhs_ty, dst_mcv, src_mcv),
3534
3535 .mul => try self.genBinOpMir(switch (lhs_ty.tag()) {
3536 .f32 => .mulss,
3537 .f64 => .mulsd,
3538 else => return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) }),
3539 }, lhs_ty, dst_mcv, src_mcv),
3540
3541 .div_float => try self.genBinOpMir(switch (lhs_ty.tag()) {
3542 .f32 => .divss,
3543 .f64 => .divsd,
3544 else => return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) }),
3545 }, lhs_ty, dst_mcv, src_mcv),
35243546
3525 .ptr_add,3547 .ptr_add,
3526 .ptr_sub,3548 .ptr_sub,
...@@ -3547,54 +3569,66 @@ fn genBinOp(...@@ -3547,54 +3569,66 @@ fn genBinOp(
35473569
3548 .min,3570 .min,
3549 .max,3571 .max,
3550 => {3572 => switch (lhs_ty.zigTypeTag()) {
3551 if (!lhs_ty.isAbiInt() or !rhs_ty.isAbiInt()) {3573 .Int => {
3552 return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) });3574 const mat_src_mcv = switch (src_mcv) {
3553 }3575 .immediate => MCValue{ .register = try self.copyToTmpRegister(rhs_ty, src_mcv) },
3576 else => src_mcv,
3577 };
3578 const mat_mcv_lock = switch (mat_src_mcv) {
3579 .register => |reg| self.register_manager.lockReg(reg),
3580 else => null,
3581 };
3582 defer if (mat_mcv_lock) |lock| self.register_manager.unlockReg(lock);
35543583
3555 const mat_src_mcv = switch (src_mcv) {3584 try self.genBinOpMir(.cmp, lhs_ty, dst_mcv, mat_src_mcv);
3556 .immediate => MCValue{ .register = try self.copyToTmpRegister(rhs_ty, src_mcv) },
3557 else => src_mcv,
3558 };
3559 const mat_mcv_lock = switch (mat_src_mcv) {
3560 .register => |reg| self.register_manager.lockReg(reg),
3561 else => null,
3562 };
3563 defer if (mat_mcv_lock) |lock| self.register_manager.unlockReg(lock);
35643585
3565 try self.genBinOpMir(.cmp, lhs_ty, dst_mcv, mat_src_mcv);3586 const int_info = lhs_ty.intInfo(self.target.*);
3587 const cc: Condition = switch (int_info.signedness) {
3588 .unsigned => switch (tag) {
3589 .min => .a,
3590 .max => .b,
3591 else => unreachable,
3592 },
3593 .signed => switch (tag) {
3594 .min => .g,
3595 .max => .l,
3596 else => unreachable,
3597 },
3598 };
35663599
3567 const int_info = lhs_ty.intInfo(self.target.*);3600 const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));
3568 const cc: Condition = switch (int_info.signedness) {3601 switch (dst_mcv) {
3569 .unsigned => switch (tag) {3602 .register => |dst_reg| switch (mat_src_mcv) {
3570 .min => .a,3603 .register => |src_reg| try self.asmCmovccRegisterRegister(
3571 .max => .b,3604 registerAlias(dst_reg, abi_size),
3605 registerAlias(src_reg, abi_size),
3606 cc,
3607 ),
3608 .stack_offset => |off| try self.asmCmovccRegisterMemory(
3609 registerAlias(dst_reg, abi_size),
3610 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }),
3611 cc,
3612 ),
3613 else => unreachable,
3614 },
3572 else => unreachable,3615 else => unreachable,
3573 },3616 }
3574 .signed => switch (tag) {3617 },
3575 .min => .g,3618 .Float => try self.genBinOpMir(switch (lhs_ty.tag()) {
3576 .max => .l,3619 .f32 => switch (tag) {
3620 .min => .minss,
3621 .max => .maxss,
3577 else => unreachable,3622 else => unreachable,
3578 },3623 },
3579 };3624 .f64 => switch (tag) {
35803625 .min => .minsd,
3581 const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));3626 .max => .maxsd,
3582 switch (dst_mcv) {
3583 .register => |dst_reg| switch (mat_src_mcv) {
3584 .register => |src_reg| try self.asmCmovccRegisterRegister(
3585 registerAlias(dst_reg, abi_size),
3586 registerAlias(src_reg, abi_size),
3587 cc,
3588 ),
3589 .stack_offset => |off| try self.asmCmovccRegisterMemory(
3590 registerAlias(dst_reg, abi_size),
3591 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }),
3592 cc,
3593 ),
3594 else => unreachable,3627 else => unreachable,
3595 },3628 },
3596 else => unreachable,3629 else => return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) }),
3597 }3630 }, lhs_ty, dst_mcv, src_mcv),
3631 else => return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) }),
3598 },3632 },
35993633
3600 else => unreachable,3634 else => unreachable,
...@@ -3626,29 +3660,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -3626,29 +3660,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
3626 .register => |src_reg| switch (dst_ty.zigTypeTag()) {3660 .register => |src_reg| switch (dst_ty.zigTypeTag()) {
3627 .Float => {3661 .Float => {
3628 if (intrinsicsAllowed(self.target.*, dst_ty)) {3662 if (intrinsicsAllowed(self.target.*, dst_ty)) {
3629 const actual_tag: Mir.Inst.Tag = switch (dst_ty.tag()) {3663 return self.asmRegisterRegister(mir_tag, dst_reg.to128(), src_reg.to128());
3630 .f32 => switch (mir_tag) {
3631 .add => .addss,
3632 .cmp => .ucomiss,
3633 else => return self.fail(
3634 "TODO genBinOpMir for f32 register-register with MIR tag {}",
3635 .{mir_tag},
3636 ),
3637 },
3638 .f64 => switch (mir_tag) {
3639 .add => .addsd,
3640 .cmp => .ucomisd,
3641 else => return self.fail(
3642 "TODO genBinOpMir for f64 register-register with MIR tag {}",
3643 .{mir_tag},
3644 ),
3645 },
3646 else => return self.fail(
3647 "TODO genBinOpMir for float register-register and type {}",
3648 .{dst_ty.fmtDebug()},
3649 ),
3650 };
3651 return self.asmRegisterRegister(actual_tag, dst_reg.to128(), src_reg.to128());
3652 }3664 }
36533665
3654 return self.fail("TODO genBinOpMir for float register-register and no intrinsics", .{});3666 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 {...@@ -4307,7 +4319,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
4307 };4319 };
4308 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);4320 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
43094321
4310 try self.genBinOpMir(.cmp, ty, dst_mcv, src_mcv);4322 try self.genBinOpMir(switch (ty.tag()) {
4323 else => .cmp,
4324 .f32 => .ucomiss,
4325 .f64 => .ucomisd,
4326 }, ty, dst_mcv, src_mcv);
43114327
4312 break :result switch (signedness) {4328 break :result switch (signedness) {
4313 .signed => MCValue{ .eflags = Condition.fromCompareOperatorSigned(op) },4329 .signed => MCValue{ .eflags = Condition.fromCompareOperatorSigned(op) },
src/arch/x86_64/Emit.zig+10
...@@ -110,11 +110,21 @@ pub fn lowerMir(emit: *Emit) InnerError!void {...@@ -110,11 +110,21 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
110110
111 .addss,111 .addss,
112 .cmpss,112 .cmpss,
113 .divss,
114 .maxss,
115 .minss,
113 .movss,116 .movss,
117 .mulss,
118 .subss,
114 .ucomiss,119 .ucomiss,
115 .addsd,120 .addsd,
116 .cmpsd,121 .cmpsd,
122 .divsd,
123 .maxsd,
124 .minsd,
117 .movsd,125 .movsd,
126 .mulsd,
127 .subsd,
118 .ucomisd,128 .ucomisd,
119 => try emit.mirEncodeGeneric(tag, inst),129 => try emit.mirEncodeGeneric(tag, inst),
120130
src/arch/x86_64/Encoding.zig+8
...@@ -342,12 +342,20 @@ pub const Mnemonic = enum {...@@ -342,12 +342,20 @@ pub const Mnemonic = enum {
342 // SSE342 // SSE
343 addss,343 addss,
344 cmpss,344 cmpss,
345 divss,
346 maxss, minss,
345 movss,347 movss,
348 mulss,
349 subss,
346 ucomiss,350 ucomiss,
347 // SSE2351 // SSE2
348 addsd,352 addsd,
349 cmpsd,353 cmpsd,
354 divsd,
355 maxsd, minsd,
350 movq, movsd,356 movq, movsd,
357 mulsd,
358 subsd,
351 ucomisd,359 ucomisd,
352 // zig fmt: on360 // zig fmt: on
353};361};
src/arch/x86_64/Mir.zig+22-2
...@@ -109,20 +109,40 @@ pub const Inst = struct {...@@ -109,20 +109,40 @@ pub const Inst = struct {
109 /// Logical exclusive-or109 /// Logical exclusive-or
110 xor,110 xor,
111111
112 /// Add single precision floating point112 /// Add single precision floating point values
113 addss,113 addss,
114 /// Compare scalar single-precision floating-point values114 /// Compare scalar single-precision floating-point values
115 cmpss,115 cmpss,
116 /// Divide scalar single-precision floating-point values
117 divss,
118 /// Return maximum single-precision floating-point value
119 maxss,
120 /// Return minimum single-precision floating-point value
121 minss,
116 /// Move scalar single-precision floating-point value122 /// Move scalar single-precision floating-point value
117 movss,123 movss,
124 /// Multiply scalar single-precision floating-point values
125 mulss,
126 /// Subtract scalar single-precision floating-point values
127 subss,
118 /// Unordered compare scalar single-precision floating-point values128 /// Unordered compare scalar single-precision floating-point values
119 ucomiss,129 ucomiss,
120 /// Add double precision floating point130 /// Add double precision floating point values
121 addsd,131 addsd,
122 /// Compare scalar double-precision floating-point values132 /// Compare scalar double-precision floating-point values
123 cmpsd,133 cmpsd,
134 /// Divide scalar double-precision floating-point values
135 divsd,
136 /// Return maximum double-precision floating-point value
137 maxsd,
138 /// Return minimum double-precision floating-point value
139 minsd,
124 /// Move scalar double-precision floating-point value140 /// Move scalar double-precision floating-point value
125 movsd,141 movsd,
142 /// Multiply scalar double-precision floating-point values
143 mulsd,
144 /// Subtract scalar double-precision floating-point values
145 subsd,
126 /// Unordered compare scalar double-precision floating-point values146 /// Unordered compare scalar double-precision floating-point values
127 ucomisd,147 ucomisd,
128148
src/arch/x86_64/encodings.zig+20
...@@ -599,9 +599,19 @@ pub const table = &[_]Entry{...@@ -599,9 +599,19 @@ pub const table = &[_]Entry{
599599
600 .{ .cmpss, .rmi, .xmm, .xmm_m32, .imm8, .none, 3, 0xf3, 0x0f, 0xc2, 0, .sse },600 .{ .cmpss, .rmi, .xmm, .xmm_m32, .imm8, .none, 3, 0xf3, 0x0f, 0xc2, 0, .sse },
601601
602 .{ .divss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x5e, 0, .sse },
603
604 .{ .maxss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x5f, 0, .sse },
605
606 .{ .minss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x5d, 0, .sse },
607
602 .{ .movss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x10, 0, .sse },608 .{ .movss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x10, 0, .sse },
603 .{ .movss, .mr, .xmm_m32, .xmm, .none, .none, 3, 0xf3, 0x0f, 0x11, 0, .sse },609 .{ .movss, .mr, .xmm_m32, .xmm, .none, .none, 3, 0xf3, 0x0f, 0x11, 0, .sse },
604610
611 .{ .mulss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x59, 0, .sse },
612
613 .{ .subss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x5c, 0, .sse },
614
605 .{ .ucomiss, .rm, .xmm, .xmm_m32, .none, .none, 2, 0x0f, 0x2e, 0x00, 0, .sse },615 .{ .ucomiss, .rm, .xmm, .xmm_m32, .none, .none, 2, 0x0f, 0x2e, 0x00, 0, .sse },
606616
607 // SSE2617 // SSE2
...@@ -609,9 +619,19 @@ pub const table = &[_]Entry{...@@ -609,9 +619,19 @@ pub const table = &[_]Entry{
609619
610 .{ .cmpsd, .rmi, .xmm, .xmm_m64, .imm8, .none, 3, 0xf2, 0x0f, 0xc2, 0, .sse2 },620 .{ .cmpsd, .rmi, .xmm, .xmm_m64, .imm8, .none, 3, 0xf2, 0x0f, 0xc2, 0, .sse2 },
611621
622 .{ .divsd, .rm, .xmm, .xmm_m64, .none, .none, 3, 0xf2, 0x0f, 0x5e, 0, .sse2 },
623
624 .{ .maxsd, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf2, 0x0f, 0x5f, 0, .sse2 },
625
626 .{ .minsd, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf2, 0x0f, 0x5d, 0, .sse2 },
627
612 .{ .movq, .rm, .xmm, .xmm_m64, .none, .none, 3, 0xf3, 0x0f, 0x7e, 0, .sse2 },628 .{ .movq, .rm, .xmm, .xmm_m64, .none, .none, 3, 0xf3, 0x0f, 0x7e, 0, .sse2 },
613 .{ .movq, .mr, .xmm_m64, .xmm, .none, .none, 3, 0x66, 0x0f, 0xd6, 0, .sse2 },629 .{ .movq, .mr, .xmm_m64, .xmm, .none, .none, 3, 0x66, 0x0f, 0xd6, 0, .sse2 },
614630
631 .{ .mulsd, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf2, 0x0f, 0x59, 0, .sse2 },
632
633 .{ .subsd, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf2, 0x0f, 0x5c, 0, .sse2 },
634
615 .{ .movsd, .rm, .xmm, .xmm_m64, .none, .none, 3, 0xf2, 0x0f, 0x10, 0, .sse2 },635 .{ .movsd, .rm, .xmm, .xmm_m64, .none, .none, 3, 0xf2, 0x0f, 0x10, 0, .sse2 },
616 .{ .movsd, .mr, .xmm_m64, .xmm, .none, .none, 3, 0xf2, 0x0f, 0x11, 0, .sse2 },636 .{ .movsd, .mr, .xmm_m64, .xmm, .none, .none, 3, 0xf2, 0x0f, 0x11, 0, .sse2 },
617637
test/behavior/maximum_minimum.zig-2
...@@ -5,7 +5,6 @@ const expect = std.testing.expect;...@@ -5,7 +5,6 @@ const expect = std.testing.expect;
5const expectEqual = std.testing.expectEqual;5const expectEqual = std.testing.expectEqual;
66
7test "@max" {7test "@max" {
8 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -52,7 +51,6 @@ test "@max on vectors" {...@@ -52,7 +51,6 @@ test "@max on vectors" {
52}51}
5352
54test "@min" {53test "@min" {
55 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
56 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO54 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
57 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO55 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
58 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO56 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO