x86_64: implement @divFloor and @mod for i128
This commit is contained in:
@@ -3248,9 +3248,7 @@ test {
|
||||
_ = &makeDirAbsolute;
|
||||
_ = &makeDirAbsoluteZ;
|
||||
_ = ©FileAbsolute;
|
||||
if (builtin.zig_backend != .stage2_x86_64) {
|
||||
_ = &updateFileAbsolute;
|
||||
}
|
||||
_ = &updateFileAbsolute;
|
||||
}
|
||||
_ = &Dir.copyFile;
|
||||
_ = @import("fs/test.zig");
|
||||
|
||||
@@ -1460,8 +1460,6 @@ test "walker without fully iterating" {
|
||||
test ". and .. in fs.Dir functions" {
|
||||
if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest;
|
||||
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
if (builtin.os.tag == .windows and builtin.cpu.arch == .aarch64) {
|
||||
// https://github.com/ziglang/zig/issues/17134
|
||||
return error.SkipZigTest;
|
||||
@@ -1502,8 +1500,6 @@ test ". and .. in fs.Dir functions" {
|
||||
test ". and .. in absolute functions" {
|
||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
||||
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
var tmp = tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
|
||||
|
||||
@@ -161,8 +161,6 @@ test "setEndPos" {
|
||||
}
|
||||
|
||||
test "updateTimes" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
var tmp = tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
|
||||
|
||||
@@ -1182,8 +1182,6 @@ test "big.int div single-single with rem" {
|
||||
}
|
||||
|
||||
test "big.int div multi-single no rem" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
var op1: u128 = 0xffffeeeeddddcccc;
|
||||
var op2: u128 = 34;
|
||||
|
||||
@@ -1203,8 +1201,6 @@ test "big.int div multi-single no rem" {
|
||||
}
|
||||
|
||||
test "big.int div multi-single with rem" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
var op1: u128 = 0xffffeeeeddddcccf;
|
||||
var op2: u128 = 34;
|
||||
|
||||
@@ -1224,8 +1220,6 @@ test "big.int div multi-single with rem" {
|
||||
}
|
||||
|
||||
test "big.int div multi>2-single" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
var op1: u128 = 0xfefefefefefefefefefefefefefefefe;
|
||||
var op2: u128 = 0xefab8;
|
||||
|
||||
@@ -1405,8 +1399,6 @@ test "big.int div trunc single-single -/-" {
|
||||
}
|
||||
|
||||
test "big.int divTrunc #15535" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
var one = try Managed.initSet(testing.allocator, 1);
|
||||
defer one.deinit();
|
||||
var x = try Managed.initSet(testing.allocator, std.math.pow(u128, 2, 64));
|
||||
@@ -1949,8 +1941,6 @@ test "big.int truncate multi to multi signed" {
|
||||
}
|
||||
|
||||
test "big.int truncate negative multi to single" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
var a = try Managed.initSet(testing.allocator, -@as(SignedDoubleLimb, maxInt(Limb) + 1));
|
||||
defer a.deinit();
|
||||
|
||||
@@ -2362,8 +2352,6 @@ test "big.int bitwise xor simple" {
|
||||
}
|
||||
|
||||
test "big.int bitwise xor multi-limb" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
var x: DoubleLimb = maxInt(Limb) + 1;
|
||||
var y: DoubleLimb = maxInt(Limb);
|
||||
var a = try Managed.initSet(testing.allocator, x);
|
||||
@@ -2538,8 +2526,6 @@ test "big.int var args" {
|
||||
}
|
||||
|
||||
test "big.int gcd non-one small" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
var a = try Managed.initSet(testing.allocator, 17);
|
||||
defer a.deinit();
|
||||
var b = try Managed.initSet(testing.allocator, 97);
|
||||
@@ -2553,8 +2539,6 @@ test "big.int gcd non-one small" {
|
||||
}
|
||||
|
||||
test "big.int gcd non-one medium" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
var a = try Managed.initSet(testing.allocator, 4864);
|
||||
defer a.deinit();
|
||||
var b = try Managed.initSet(testing.allocator, 3458);
|
||||
@@ -2568,8 +2552,6 @@ test "big.int gcd non-one medium" {
|
||||
}
|
||||
|
||||
test "big.int gcd non-one large" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
var a = try Managed.initSet(testing.allocator, 0xffffffffffffffff);
|
||||
defer a.deinit();
|
||||
var b = try Managed.initSet(testing.allocator, 0xffffffffffffffff7777);
|
||||
@@ -2602,8 +2584,6 @@ test "big.int gcd large multi-limb result" {
|
||||
}
|
||||
|
||||
test "big.int gcd one large" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
var a = try Managed.initSet(testing.allocator, 1897056385327307);
|
||||
defer a.deinit();
|
||||
var b = try Managed.initSet(testing.allocator, 2251799813685248);
|
||||
|
||||
@@ -514,8 +514,6 @@ test "big.rational extractLowBits" {
|
||||
}
|
||||
|
||||
test "big.rational set" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
var a = try Rational.init(testing.allocator);
|
||||
defer a.deinit();
|
||||
|
||||
@@ -615,8 +613,6 @@ test "big.rational set/to Float round-trip" {
|
||||
}
|
||||
|
||||
test "big.rational copy" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
var a = try Rational.init(testing.allocator);
|
||||
defer a.deinit();
|
||||
|
||||
@@ -681,8 +677,6 @@ test "big.rational abs" {
|
||||
}
|
||||
|
||||
test "big.rational swap" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
var a = try Rational.init(testing.allocator);
|
||||
defer a.deinit();
|
||||
var b = try Rational.init(testing.allocator);
|
||||
@@ -707,8 +701,6 @@ test "big.rational swap" {
|
||||
}
|
||||
|
||||
test "big.rational order" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
var a = try Rational.init(testing.allocator);
|
||||
defer a.deinit();
|
||||
var b = try Rational.init(testing.allocator);
|
||||
@@ -724,8 +716,6 @@ test "big.rational order" {
|
||||
}
|
||||
|
||||
test "big.rational order/orderAbs with negative" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
var a = try Rational.init(testing.allocator);
|
||||
defer a.deinit();
|
||||
var b = try Rational.init(testing.allocator);
|
||||
@@ -738,8 +728,6 @@ test "big.rational order/orderAbs with negative" {
|
||||
}
|
||||
|
||||
test "big.rational add single-limb" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
var a = try Rational.init(testing.allocator);
|
||||
defer a.deinit();
|
||||
var b = try Rational.init(testing.allocator);
|
||||
@@ -755,8 +743,6 @@ test "big.rational add single-limb" {
|
||||
}
|
||||
|
||||
test "big.rational add" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
var a = try Rational.init(testing.allocator);
|
||||
defer a.deinit();
|
||||
var b = try Rational.init(testing.allocator);
|
||||
@@ -773,8 +759,6 @@ test "big.rational add" {
|
||||
}
|
||||
|
||||
test "big.rational sub" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
var a = try Rational.init(testing.allocator);
|
||||
defer a.deinit();
|
||||
var b = try Rational.init(testing.allocator);
|
||||
@@ -791,8 +775,6 @@ test "big.rational sub" {
|
||||
}
|
||||
|
||||
test "big.rational mul" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
var a = try Rational.init(testing.allocator);
|
||||
defer a.deinit();
|
||||
var b = try Rational.init(testing.allocator);
|
||||
@@ -809,8 +791,6 @@ test "big.rational mul" {
|
||||
}
|
||||
|
||||
test "big.rational div" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
{
|
||||
var a = try Rational.init(testing.allocator);
|
||||
defer a.deinit();
|
||||
|
||||
@@ -2204,8 +2204,6 @@ test "sendmsg/recvmsg" {
|
||||
test "timeout (after a relative time)" {
|
||||
if (builtin.os.tag != .linux) return error.SkipZigTest;
|
||||
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
var ring = IO_Uring.init(1, 0) catch |err| switch (err) {
|
||||
error.SystemOutdated => return error.SkipZigTest,
|
||||
error.PermissionDenied => return error.SkipZigTest,
|
||||
|
||||
@@ -122,8 +122,6 @@ pub fn nanoTimestamp() i128 {
|
||||
}
|
||||
|
||||
test "timestamp" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
const margin = ns_per_ms * 50;
|
||||
|
||||
const time_0 = milliTimestamp();
|
||||
|
||||
@@ -3221,6 +3221,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {
|
||||
.Float, .Vector => break :result try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs),
|
||||
else => {},
|
||||
}
|
||||
const dst_abi_size: u32 = @intCast(dst_ty.abiSize(mod));
|
||||
|
||||
const dst_info = dst_ty.intInfo(mod);
|
||||
const src_ty = try mod.intType(dst_info.signedness, switch (tag) {
|
||||
@@ -3232,12 +3233,153 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {
|
||||
),
|
||||
.div_trunc, .div_floor, .div_exact, .rem, .mod => dst_info.bits,
|
||||
});
|
||||
const src_abi_size: u32 = @intCast(src_ty.abiSize(mod));
|
||||
|
||||
if (dst_abi_size == 16 and src_abi_size == 16) switch (tag) {
|
||||
else => unreachable,
|
||||
.mul, .mul_wrap => {},
|
||||
.div_trunc, .div_floor, .div_exact, .rem, .mod => {
|
||||
const signed = dst_ty.isSignedInt(mod);
|
||||
var callee_buf: ["__udiv?i3".len]u8 = undefined;
|
||||
const signed_div_floor_state: struct {
|
||||
frame_index: FrameIndex,
|
||||
reloc: Mir.Inst.Index,
|
||||
} = if (signed and tag == .div_floor) state: {
|
||||
const frame_index = try self.allocFrameIndex(FrameAlloc.initType(Type.usize, mod));
|
||||
try self.asmMemoryImmediate(
|
||||
.{ ._, .mov },
|
||||
Memory.sib(.qword, .{ .base = .{ .frame = frame_index } }),
|
||||
Immediate.u(0),
|
||||
);
|
||||
|
||||
const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
|
||||
const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
|
||||
defer self.register_manager.unlockReg(tmp_lock);
|
||||
|
||||
const lhs_mcv = try self.resolveInst(bin_op.lhs);
|
||||
if (lhs_mcv.isMemory()) try self.asmRegisterMemory(
|
||||
.{ ._, .mov },
|
||||
tmp_reg,
|
||||
lhs_mcv.address().offset(8).deref().mem(.qword),
|
||||
) else try self.asmRegisterRegister(
|
||||
.{ ._, .mov },
|
||||
tmp_reg,
|
||||
lhs_mcv.register_pair[1],
|
||||
);
|
||||
|
||||
const rhs_mcv = try self.resolveInst(bin_op.rhs);
|
||||
if (rhs_mcv.isMemory()) try self.asmRegisterMemory(
|
||||
.{ ._, .xor },
|
||||
tmp_reg,
|
||||
rhs_mcv.address().offset(8).deref().mem(.qword),
|
||||
) else try self.asmRegisterRegister(
|
||||
.{ ._, .xor },
|
||||
tmp_reg,
|
||||
rhs_mcv.register_pair[1],
|
||||
);
|
||||
const reloc = try self.asmJccReloc(.ns, undefined);
|
||||
|
||||
break :state .{ .frame_index = frame_index, .reloc = reloc };
|
||||
} else undefined;
|
||||
const call_mcv = try self.genCall(
|
||||
.{ .lib = .{
|
||||
.return_type = dst_ty.toIntern(),
|
||||
.param_types = &.{ src_ty.toIntern(), src_ty.toIntern() },
|
||||
.callee = std.fmt.bufPrint(&callee_buf, "__{s}{s}{c}i3", .{
|
||||
if (signed) "" else "u",
|
||||
switch (tag) {
|
||||
.div_trunc, .div_exact => "div",
|
||||
.div_floor => if (signed) "mod" else "div",
|
||||
.rem, .mod => "mod",
|
||||
else => unreachable,
|
||||
},
|
||||
intCompilerRtAbiName(@intCast(dst_ty.bitSize(mod))),
|
||||
}) catch unreachable,
|
||||
} },
|
||||
&.{ src_ty, src_ty },
|
||||
&.{ .{ .air_ref = bin_op.lhs }, .{ .air_ref = bin_op.rhs } },
|
||||
);
|
||||
break :result if (signed) switch (tag) {
|
||||
.div_floor => {
|
||||
try self.asmRegisterRegister(
|
||||
.{ ._, .@"or" },
|
||||
call_mcv.register_pair[0],
|
||||
call_mcv.register_pair[1],
|
||||
);
|
||||
try self.asmSetccMemory(.nz, Memory.sib(.byte, .{
|
||||
.base = .{ .frame = signed_div_floor_state.frame_index },
|
||||
}));
|
||||
try self.performReloc(signed_div_floor_state.reloc);
|
||||
const dst_mcv = try self.genCall(
|
||||
.{ .lib = .{
|
||||
.return_type = dst_ty.toIntern(),
|
||||
.param_types = &.{ src_ty.toIntern(), src_ty.toIntern() },
|
||||
.callee = std.fmt.bufPrint(&callee_buf, "__div{c}i3", .{
|
||||
intCompilerRtAbiName(@intCast(dst_ty.bitSize(mod))),
|
||||
}) catch unreachable,
|
||||
} },
|
||||
&.{ src_ty, src_ty },
|
||||
&.{ .{ .air_ref = bin_op.lhs }, .{ .air_ref = bin_op.rhs } },
|
||||
);
|
||||
try self.asmRegisterMemory(
|
||||
.{ ._, .sub },
|
||||
dst_mcv.register_pair[0],
|
||||
Memory.sib(.qword, .{
|
||||
.base = .{ .frame = signed_div_floor_state.frame_index },
|
||||
}),
|
||||
);
|
||||
try self.asmRegisterImmediate(
|
||||
.{ ._, .sbb },
|
||||
dst_mcv.register_pair[1],
|
||||
Immediate.u(0),
|
||||
);
|
||||
try self.freeValue(
|
||||
.{ .load_frame = .{ .index = signed_div_floor_state.frame_index } },
|
||||
);
|
||||
break :result dst_mcv;
|
||||
},
|
||||
.mod => {
|
||||
const dst_regs = call_mcv.register_pair;
|
||||
const dst_locks = self.register_manager.lockRegsAssumeUnused(2, dst_regs);
|
||||
defer for (dst_locks) |lock| self.register_manager.unlockReg(lock);
|
||||
|
||||
const tmp_regs =
|
||||
try self.register_manager.allocRegs(2, .{null} ** 2, abi.RegisterClass.gp);
|
||||
const tmp_locks = self.register_manager.lockRegsAssumeUnused(2, tmp_regs);
|
||||
defer for (tmp_locks) |lock| self.register_manager.unlockReg(lock);
|
||||
|
||||
const rhs_mcv = try self.resolveInst(bin_op.rhs);
|
||||
|
||||
for (tmp_regs, dst_regs) |tmp_reg, dst_reg|
|
||||
try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, dst_reg);
|
||||
if (rhs_mcv.isMemory()) {
|
||||
try self.asmRegisterMemory(.{ ._, .add }, tmp_regs[0], rhs_mcv.mem(.qword));
|
||||
try self.asmRegisterMemory(
|
||||
.{ ._, .adc },
|
||||
tmp_regs[1],
|
||||
rhs_mcv.address().offset(8).deref().mem(.qword),
|
||||
);
|
||||
} else for (
|
||||
[_]Mir.Inst.Tag{ .add, .adc },
|
||||
tmp_regs,
|
||||
rhs_mcv.register_pair,
|
||||
) |op, tmp_reg, rhs_reg|
|
||||
try self.asmRegisterRegister(.{ ._, op }, tmp_reg, rhs_reg);
|
||||
try self.asmRegisterRegister(.{ ._, .@"test" }, dst_regs[1], dst_regs[1]);
|
||||
for (dst_regs, tmp_regs) |dst_reg, tmp_reg|
|
||||
try self.asmCmovccRegisterRegister(.s, dst_reg, tmp_reg);
|
||||
break :result call_mcv;
|
||||
},
|
||||
else => call_mcv,
|
||||
} else call_mcv;
|
||||
},
|
||||
};
|
||||
|
||||
try self.spillEflagsIfOccupied();
|
||||
try self.spillRegisters(&.{ .rax, .rdx });
|
||||
const lhs = try self.resolveInst(bin_op.lhs);
|
||||
const rhs = try self.resolveInst(bin_op.rhs);
|
||||
break :result try self.genMulDivBinOp(tag, inst, dst_ty, src_ty, lhs, rhs);
|
||||
const lhs_mcv = try self.resolveInst(bin_op.lhs);
|
||||
const rhs_mcv = try self.resolveInst(bin_op.rhs);
|
||||
break :result try self.genMulDivBinOp(tag, inst, dst_ty, src_ty, lhs_mcv, rhs_mcv);
|
||||
};
|
||||
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||
}
|
||||
@@ -7201,37 +7343,7 @@ fn genMulDivBinOp(
|
||||
assert(self.eflags_inst == null);
|
||||
|
||||
if (dst_abi_size == 16 and src_abi_size == 16) {
|
||||
switch (tag) {
|
||||
else => unreachable,
|
||||
.mul, .mul_wrap => {},
|
||||
.div_trunc, .div_floor, .div_exact, .rem, .mod => {
|
||||
const signed = dst_ty.isSignedInt(mod);
|
||||
if (signed) switch (tag) {
|
||||
.div_floor, .mod => return self.fail(
|
||||
"TODO implement genMulDivBinOp for {s} from {} to {}",
|
||||
.{ @tagName(tag), src_ty.fmt(mod), dst_ty.fmt(mod) },
|
||||
),
|
||||
else => {},
|
||||
};
|
||||
var callee_buf: ["__udiv?i3".len]u8 = undefined;
|
||||
return try self.genCall(.{ .lib = .{
|
||||
.return_type = dst_ty.toIntern(),
|
||||
.param_types = &.{ src_ty.toIntern(), src_ty.toIntern() },
|
||||
.callee = std.fmt.bufPrint(&callee_buf, "__{s}{s}{c}i3", .{
|
||||
if (signed) "" else "u",
|
||||
switch (tag) {
|
||||
.div_trunc, .div_exact => "div",
|
||||
.div_floor => if (signed) unreachable else "div",
|
||||
.rem => "mod",
|
||||
.mod => if (signed) unreachable else "mod",
|
||||
else => unreachable,
|
||||
},
|
||||
intCompilerRtAbiName(@intCast(dst_ty.bitSize(mod))),
|
||||
}) catch unreachable,
|
||||
} }, &.{ src_ty, src_ty }, &.{ lhs_mcv, rhs_mcv });
|
||||
},
|
||||
}
|
||||
|
||||
assert(tag == .mul or tag == .mul_wrap);
|
||||
const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx });
|
||||
defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user