mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
Merge pull request #14828 from jacobly0/fix-big-div
compiler_rt: fix rare case in udivei4
This commit is contained in:
commit
6fc1621cbd
@ -79,16 +79,16 @@ fn divmod(q: ?[]u32, r: ?[]u32, u: []const u32, v: []const u32) !void {
|
||||
}
|
||||
break;
|
||||
}
|
||||
var carry: u64 = 0;
|
||||
var carry: i64 = 0;
|
||||
i = 0;
|
||||
while (i <= n) : (i += 1) {
|
||||
const p = qhat * limb(&vn, i);
|
||||
const t = limb(&un, i + j) - carry - @truncate(u32, p);
|
||||
limb_set(&un, i + j, @truncate(u32, t));
|
||||
carry = @intCast(u64, p >> 32) - @intCast(u64, t >> 32);
|
||||
limb_set(&un, i + j, @truncate(u32, @bitCast(u64, t)));
|
||||
carry = @intCast(i64, p >> 32) - @intCast(i64, t >> 32);
|
||||
}
|
||||
const t = limb(&un, j + n + 1) - carry;
|
||||
limb_set(&un, j + n + 1, @truncate(u32, t));
|
||||
const t = limb(&un, j + n + 1) -% carry;
|
||||
limb_set(&un, j + n + 1, @truncate(u32, @bitCast(u64, t)));
|
||||
if (q) |q_| limb_set(q_, j, @truncate(u32, qhat));
|
||||
if (t < 0) {
|
||||
if (q) |q_| limb_set(q_, j, limb(q_, j) - 1);
|
||||
@ -99,7 +99,7 @@ fn divmod(q: ?[]u32, r: ?[]u32, u: []const u32, v: []const u32) !void {
|
||||
limb_set(&un, i + j, @truncate(u32, t2));
|
||||
carry2 = t2 >> 32;
|
||||
}
|
||||
limb_set(un, j + n + 1, @truncate(u32, limb(&un, j + n + 1) + carry2));
|
||||
limb_set(&un, j + n + 1, @truncate(u32, limb(&un, j + n + 1) + carry2));
|
||||
}
|
||||
if (j == 0) break;
|
||||
}
|
||||
|
||||
56
lib/zig.h
56
lib/zig.h
@ -190,10 +190,17 @@ typedef char bool;
|
||||
|
||||
#if zig_has_builtin(trap)
|
||||
#define zig_trap() __builtin_trap()
|
||||
#elif _MSC_VER && (_M_IX86 || _M_X64)
|
||||
#define zig_trap() __ud2()
|
||||
#elif _MSC_VER
|
||||
#define zig_trap() __fastfail(0)
|
||||
#elif defined(__i386__) || defined(__x86_64__)
|
||||
#define zig_trap() __asm__ volatile("ud2");
|
||||
#elif defined(__arm__) || defined(__aarch64__)
|
||||
#define zig_breakpoint() __asm__ volatile("udf #0");
|
||||
#else
|
||||
#define zig_trap() raise(SIGTRAP)
|
||||
#include <stdlib.h>
|
||||
#define zig_trap() abort()
|
||||
#endif
|
||||
|
||||
#if zig_has_builtin(debugtrap)
|
||||
@ -202,8 +209,17 @@ typedef char bool;
|
||||
#define zig_breakpoint() __debugbreak()
|
||||
#elif defined(__i386__) || defined(__x86_64__)
|
||||
#define zig_breakpoint() __asm__ volatile("int $0x03");
|
||||
#elif defined(__arm__)
|
||||
#define zig_breakpoint() __asm__ volatile("bkpt #0");
|
||||
#elif defined(__aarch64__)
|
||||
#define zig_breakpoint() __asm__ volatile("brk #0");
|
||||
#else
|
||||
#include <signal.h>
|
||||
#if defined(SIGTRAP)
|
||||
#define zig_breakpoint() raise(SIGTRAP)
|
||||
#else
|
||||
#define zig_breakpoint() zig_breakpoint_unavailable
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if zig_has_builtin(return_address) || defined(zig_gnuc)
|
||||
@ -2384,6 +2400,44 @@ static inline void zig_subw_big(void *res, const void *lhs, const void *rhs, boo
|
||||
(void)zig_subo_big(res, lhs, rhs, is_signed, bits);
|
||||
}
|
||||
|
||||
zig_extern void __udivei4(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uintptr_t bits);
|
||||
static inline void zig_div_trunc_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) {
|
||||
if (!is_signed) {
|
||||
__udivei4(res, lhs, rhs, bits);
|
||||
return;
|
||||
}
|
||||
|
||||
zig_trap();
|
||||
}
|
||||
|
||||
static inline void zig_div_floor_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) {
|
||||
if (!is_signed) {
|
||||
zig_div_trunc_big(res, lhs, rhs, is_signed, bits);
|
||||
return;
|
||||
}
|
||||
|
||||
zig_trap();
|
||||
}
|
||||
|
||||
zig_extern void __umodei4(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uintptr_t bits);
|
||||
static inline void zig_rem_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) {
|
||||
if (!is_signed) {
|
||||
__umodei4(res, lhs, rhs, bits);
|
||||
return;
|
||||
}
|
||||
|
||||
zig_trap();
|
||||
}
|
||||
|
||||
static inline void zig_mod_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) {
|
||||
if (!is_signed) {
|
||||
zig_rem_big(res, lhs, rhs, is_signed, bits);
|
||||
return;
|
||||
}
|
||||
|
||||
zig_trap();
|
||||
}
|
||||
|
||||
static inline uint16_t zig_clz_big(const void *val, bool is_signed, uint16_t bits) {
|
||||
const uint8_t *val_bytes = val;
|
||||
uint16_t byte_offset = 0;
|
||||
|
||||
@ -1885,25 +1885,28 @@ pub const DeclGen = struct {
|
||||
}
|
||||
|
||||
fn renderBuiltinInfo(dg: *DeclGen, writer: anytype, ty: Type, info: BuiltinInfo) !void {
|
||||
const cty = try dg.typeToCType(ty, .complete);
|
||||
const is_big = cty.tag() == .array;
|
||||
|
||||
switch (info) {
|
||||
.none => {},
|
||||
.bits => {
|
||||
.none => if (!is_big) return,
|
||||
.bits => {},
|
||||
}
|
||||
|
||||
const target = dg.module.getTarget();
|
||||
const int_info = if (ty.isAbiInt()) ty.intInfo(target) else std.builtin.Type.Int{
|
||||
.signedness = .unsigned,
|
||||
.bits = @intCast(u16, ty.bitSize(target)),
|
||||
};
|
||||
|
||||
const cty = try dg.typeToCType(ty, .complete);
|
||||
if (cty.tag() == .array) try writer.print(", {}", .{int_info.signedness == .signed});
|
||||
if (is_big) try writer.print(", {}", .{int_info.signedness == .signed});
|
||||
|
||||
var bits_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = int_info.bits };
|
||||
try writer.print(", {}", .{try dg.fmtIntLiteral(switch (cty.tag()) {
|
||||
else => Type.u8,
|
||||
.array => Type.u16,
|
||||
}, Value.initPayload(&bits_pl.base), .FunctionArgument)});
|
||||
},
|
||||
}
|
||||
try writer.print(", {}", .{try dg.fmtIntLiteral(
|
||||
if (is_big) Type.u16 else Type.u8,
|
||||
Value.initPayload(&bits_pl.base),
|
||||
.FunctionArgument,
|
||||
)});
|
||||
}
|
||||
|
||||
fn fmtIntLiteral(
|
||||
@ -6099,13 +6102,16 @@ fn airBinBuiltinCall(
|
||||
return .none;
|
||||
}
|
||||
|
||||
const operand_ty = f.air.typeOf(bin_op.lhs);
|
||||
const operand_cty = try f.typeToCType(operand_ty, .complete);
|
||||
const is_big = operand_cty.tag() == .array;
|
||||
|
||||
const lhs = try f.resolveInst(bin_op.lhs);
|
||||
const rhs = try f.resolveInst(bin_op.rhs);
|
||||
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
|
||||
if (!is_big) try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
|
||||
|
||||
const inst_ty = f.air.typeOfIndex(inst);
|
||||
const inst_scalar_ty = inst_ty.scalarType();
|
||||
const operand_ty = f.air.typeOf(bin_op.lhs);
|
||||
const scalar_ty = operand_ty.scalarType();
|
||||
|
||||
const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete);
|
||||
@ -6113,6 +6119,7 @@ fn airBinBuiltinCall(
|
||||
|
||||
const writer = f.object.writer();
|
||||
const local = try f.allocLocal(inst, inst_ty);
|
||||
if (is_big) try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
|
||||
const v = try Vectorizer.start(f, inst, writer, operand_ty);
|
||||
if (!ref_ret) {
|
||||
try f.writeCValue(writer, local, .Other);
|
||||
|
||||
@ -91,3 +91,22 @@ fn mod(comptime T: type, a: T, b: T) T {
|
||||
fn rem(comptime T: type, a: T, b: T) T {
|
||||
return @rem(a, b);
|
||||
}
|
||||
|
||||
test "large integer division" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
{
|
||||
var numerator: u256 = 99999999999999999997315645440;
|
||||
var divisor: u256 = 10000000000000000000000000000;
|
||||
try expect(numerator / divisor == 9);
|
||||
}
|
||||
{
|
||||
var numerator: u256 = 99999999999999999999000000000000000000000;
|
||||
var divisor: u256 = 10000000000000000000000000000000000000000;
|
||||
try expect(numerator / divisor == 9);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user