authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-04-29 17:56:48-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-01 19:22:52-04:00
logc81878978a41f117818ac5b4918cd952f123bad7
tree980a9508ada90c904f1fd04aa990c4d3f14af39d
parent3c2636a83dbb964f80f93131b30222ad3889a7e9

x86_64: optimize wide mul with overflow


1 files changed, 36 insertions(+), 25 deletions(-)

src/arch/x86_64/CodeGen.zig+36-25
...@@ -2520,7 +2520,7 @@ fn genSetFrameTruncatedOverflowCompare(...@@ -2520,7 +2520,7 @@ fn genSetFrameTruncatedOverflowCompare(
2520 tuple_ty: Type,2520 tuple_ty: Type,
2521 frame_index: FrameIndex,2521 frame_index: FrameIndex,
2522 src_mcv: MCValue,2522 src_mcv: MCValue,
2523 cc: Condition,2523 overflow_cc: ?Condition,
2524) !void {2524) !void {
2525 const src_lock = switch (src_mcv) {2525 const src_lock = switch (src_mcv) {
2526 .register => |reg| self.register_manager.lockReg(reg),2526 .register => |reg| self.register_manager.lockReg(reg),
...@@ -2551,7 +2551,7 @@ fn genSetFrameTruncatedOverflowCompare(...@@ -2551,7 +2551,7 @@ fn genSetFrameTruncatedOverflowCompare(
2551 defer for (temp_locks) |lock| self.register_manager.unlockReg(lock);2551 defer for (temp_locks) |lock| self.register_manager.unlockReg(lock);
25522552
2553 const overflow_reg = temp_regs[0];2553 const overflow_reg = temp_regs[0];
2554 try self.asmSetccRegister(overflow_reg.to8(), cc);2554 if (overflow_cc) |cc| try self.asmSetccRegister(overflow_reg.to8(), cc);
25552555
2556 const scratch_reg = temp_regs[1];2556 const scratch_reg = temp_regs[1];
2557 const hi_limb_off = if (int_info.bits <= 64) 0 else (int_info.bits - 1) / 64 * 8;2557 const hi_limb_off = if (int_info.bits <= 64) 0 else (int_info.bits - 1) / 64 * 8;
...@@ -2564,8 +2564,10 @@ fn genSetFrameTruncatedOverflowCompare(...@@ -2564,8 +2564,10 @@ fn genSetFrameTruncatedOverflowCompare(
2564 try self.genBinOpMir(.cmp, hi_limb_ty, .{ .register = scratch_reg }, hi_limb_mcv);2564 try self.genBinOpMir(.cmp, hi_limb_ty, .{ .register = scratch_reg }, hi_limb_mcv);
25652565
2566 const eq_reg = temp_regs[2];2566 const eq_reg = temp_regs[2];
2567 try self.asmSetccRegister(eq_reg.to8(), .ne);2567 if (overflow_cc) |_| {
2568 try self.genBinOpMir(.@"or", Type.u8, .{ .register = overflow_reg }, .{ .register = eq_reg });2568 try self.asmSetccRegister(eq_reg.to8(), .ne);
2569 try self.genBinOpMir(.@"or", Type.u8, .{ .register = overflow_reg }, .{ .register = eq_reg });
2570 }
25692571
2570 const payload_off = @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*));2572 const payload_off = @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*));
2571 if (hi_limb_off > 0) try self.genSetMem(.{ .frame = frame_index }, payload_off, rest_ty, src_mcv);2573 if (hi_limb_off > 0) try self.genSetMem(.{ .frame = frame_index }, payload_off, rest_ty, src_mcv);
...@@ -2579,7 +2581,7 @@ fn genSetFrameTruncatedOverflowCompare(...@@ -2579,7 +2581,7 @@ fn genSetFrameTruncatedOverflowCompare(
2579 .{ .frame = frame_index },2581 .{ .frame = frame_index },
2580 @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)),2582 @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)),
2581 tuple_ty.structFieldType(1),2583 tuple_ty.structFieldType(1),
2582 .{ .register = overflow_reg.to8() },2584 if (overflow_cc) |_| .{ .register = overflow_reg.to8() } else .{ .eflags = .ne },
2583 );2585 );
2584}2586}
25852587
...@@ -2654,27 +2656,36 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2654,27 +2656,36 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2654 try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc);2656 try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc);
2655 break :result .{ .load_frame = .{ .index = frame_index } };2657 break :result .{ .load_frame = .{ .index = frame_index } };
2656 },2658 },
2657 // For now, this is the only supported multiply that doesn't fit in a register.2659 else => {
2658 else => assert(dst_info.bits <= 128 and src_pl.data == 64),2660 // For now, this is the only supported multiply that doesn't fit in a register,
2659 }2661 // so cc being set is impossible.
26602662
2661 const frame_index =2663 assert(dst_info.bits <= 128 and src_pl.data == 64);
2662 try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*));2664
2663 if (dst_info.bits >= lhs_active_bits + rhs_active_bits) {2665 const frame_index =
2664 try self.genSetMem(2666 try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*));
2665 .{ .frame = frame_index },2667 if (dst_info.bits >= lhs_active_bits + rhs_active_bits) {
2666 @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)),2668 try self.genSetMem(
2667 tuple_ty.structFieldType(0),2669 .{ .frame = frame_index },
2668 partial_mcv,2670 @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)),
2669 );2671 tuple_ty.structFieldType(0),
2670 try self.genSetMem(2672 partial_mcv,
2671 .{ .frame = frame_index },2673 );
2672 @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)),2674 try self.genSetMem(
2673 tuple_ty.structFieldType(1),2675 .{ .frame = frame_index },
2674 .{ .immediate = 0 }, // overflow is impossible for 64-bit*64-bit -> 128-bit2676 @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)),
2675 );2677 tuple_ty.structFieldType(1),
2676 } else try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc);2678 .{ .immediate = 0 },
2677 break :result .{ .load_frame = .{ .index = frame_index } };2679 );
2680 } else try self.genSetFrameTruncatedOverflowCompare(
2681 tuple_ty,
2682 frame_index,
2683 partial_mcv,
2684 null,
2685 );
2686 break :result .{ .load_frame = .{ .index = frame_index } };
2687 },
2688 }
2678 },2689 },
2679 else => unreachable,2690 else => unreachable,
2680 };2691 };