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
15301530
15311531fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {
15321532 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)) {
1535 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
1536 }
1537
1538 const tag = self.air.instructions.items(.tag)[inst];
1539 const ty = self.air.typeOfIndex(inst);
1536 const tag = self.air.instructions.items(.tag)[inst];
1537 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);
1544 const rhs = try self.resolveInst(bin_op.rhs);
1543 try self.spillRegisters(2, .{ .rax, .rdx });
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 };
15481550 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
15491551}
15501552
......@@ -3288,10 +3290,10 @@ fn genMulDivBinOp(
32883290 rhs: MCValue,
32893291) !MCValue {
32903292 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()});
32923294 }
32933295 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()});
32953297 }
32963298 if (tag == .div_float) {
32973299 return self.fail("TODO implement genMulDivBinOp for div_float", .{});
......@@ -3516,11 +3518,31 @@ fn genBinOp(
35163518 switch (tag) {
35173519 .add,
35183520 .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
35213527 .sub,
35223528 .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
35253547 .ptr_add,
35263548 .ptr_sub,
......@@ -3547,54 +3569,66 @@ fn genBinOp(
35473569
35483570 .min,
35493571 .max,
3550 => {
3551 if (!lhs_ty.isAbiInt() or !rhs_ty.isAbiInt()) {
3552 return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) });
3553 }
3572 => switch (lhs_ty.zigTypeTag()) {
3573 .Int => {
3574 const mat_src_mcv = switch (src_mcv) {
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) {
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);
3584 try self.genBinOpMir(.cmp, lhs_ty, dst_mcv, mat_src_mcv);
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.*);
3568 const cc: Condition = switch (int_info.signedness) {
3569 .unsigned => switch (tag) {
3570 .min => .a,
3571 .max => .b,
3600 const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));
3601 switch (dst_mcv) {
3602 .register => |dst_reg| switch (mat_src_mcv) {
3603 .register => |src_reg| try self.asmCmovccRegisterRegister(
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 },
35723615 else => unreachable,
3573 },
3574 .signed => switch (tag) {
3575 .min => .g,
3576 .max => .l,
3616 }
3617 },
3618 .Float => try self.genBinOpMir(switch (lhs_ty.tag()) {
3619 .f32 => switch (tag) {
3620 .min => .minss,
3621 .max => .maxss,
35773622 else => unreachable,
35783623 },
3579 };
3580
3581 const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*));
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 ),
3624 .f64 => switch (tag) {
3625 .min => .minsd,
3626 .max => .maxsd,
35943627 else => unreachable,
35953628 },
3596 else => unreachable,
3597 }
3629 else => return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) }),
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.?) }),
35983632 },
35993633
36003634 else => unreachable,
......@@ -3626,29 +3660,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
36263660 .register => |src_reg| switch (dst_ty.zigTypeTag()) {
36273661 .Float => {
36283662 if (intrinsicsAllowed(self.target.*, dst_ty)) {
3629 const actual_tag: Mir.Inst.Tag = switch (dst_ty.tag()) {
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());
3663 return self.asmRegisterRegister(mir_tag, dst_reg.to128(), src_reg.to128());
36523664 }
36533665
36543666 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 {
43074319 };
43084320 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
43124328 break :result switch (signedness) {
43134329 .signed => MCValue{ .eflags = Condition.fromCompareOperatorSigned(op) },
src/arch/x86_64/Emit.zig+10
......@@ -110,11 +110,21 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
110110
111111 .addss,
112112 .cmpss,
113 .divss,
114 .maxss,
115 .minss,
113116 .movss,
117 .mulss,
118 .subss,
114119 .ucomiss,
115120 .addsd,
116121 .cmpsd,
122 .divsd,
123 .maxsd,
124 .minsd,
117125 .movsd,
126 .mulsd,
127 .subsd,
118128 .ucomisd,
119129 => try emit.mirEncodeGeneric(tag, inst),
120130
src/arch/x86_64/Encoding.zig+8
......@@ -342,12 +342,20 @@ pub const Mnemonic = enum {
342342 // SSE
343343 addss,
344344 cmpss,
345 divss,
346 maxss, minss,
345347 movss,
348 mulss,
349 subss,
346350 ucomiss,
347351 // SSE2
348352 addsd,
349353 cmpsd,
354 divsd,
355 maxsd, minsd,
350356 movq, movsd,
357 mulsd,
358 subsd,
351359 ucomisd,
352360 // zig fmt: on
353361};
src/arch/x86_64/Mir.zig+22-2
......@@ -109,20 +109,40 @@ pub const Inst = struct {
109109 /// Logical exclusive-or
110110 xor,
111111
112 /// Add single precision floating point
112 /// Add single precision floating point values
113113 addss,
114114 /// Compare scalar single-precision floating-point values
115115 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,
116122 /// Move scalar single-precision floating-point value
117123 movss,
124 /// Multiply scalar single-precision floating-point values
125 mulss,
126 /// Subtract scalar single-precision floating-point values
127 subss,
118128 /// Unordered compare scalar single-precision floating-point values
119129 ucomiss,
120 /// Add double precision floating point
130 /// Add double precision floating point values
121131 addsd,
122132 /// Compare scalar double-precision floating-point values
123133 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,
124140 /// Move scalar double-precision floating-point value
125141 movsd,
142 /// Multiply scalar double-precision floating-point values
143 mulsd,
144 /// Subtract scalar double-precision floating-point values
145 subsd,
126146 /// Unordered compare scalar double-precision floating-point values
127147 ucomisd,
128148
src/arch/x86_64/encodings.zig+20
......@@ -599,9 +599,19 @@ pub const table = &[_]Entry{
599599
600600 .{ .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
602608 .{ .movss, .rm, .xmm, .xmm_m32, .none, .none, 3, 0xf3, 0x0f, 0x10, 0, .sse },
603609 .{ .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
605615 .{ .ucomiss, .rm, .xmm, .xmm_m32, .none, .none, 2, 0x0f, 0x2e, 0x00, 0, .sse },
606616
607617 // SSE2
......@@ -609,9 +619,19 @@ pub const table = &[_]Entry{
609619
610620 .{ .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
612628 .{ .movq, .rm, .xmm, .xmm_m64, .none, .none, 3, 0xf3, 0x0f, 0x7e, 0, .sse2 },
613629 .{ .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
615635 .{ .movsd, .rm, .xmm, .xmm_m64, .none, .none, 3, 0xf2, 0x0f, 0x10, 0, .sse2 },
616636 .{ .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;
55const expectEqual = std.testing.expectEqual;
66
77test "@max" {
8 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -52,7 +51,6 @@ test "@max on vectors" {
5251}
5352
5453test "@min" {
55 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
5654 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5755 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5856 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO