Skip to content

Commit 6fc1621

Browse files
authored
Merge pull request #14828 from jacobly0/fix-big-div
compiler_rt: fix rare case in udivei4
2 parents bbba701 + e33dfc3 commit 6fc1621

File tree

4 files changed

+105
-25
lines changed

4 files changed

+105
-25
lines changed

lib/compiler_rt/udivmodei4.zig

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,16 @@ fn divmod(q: ?[]u32, r: ?[]u32, u: []const u32, v: []const u32) !void {
7979
}
8080
break;
8181
}
82-
var carry: u64 = 0;
82+
var carry: i64 = 0;
8383
i = 0;
8484
while (i <= n) : (i += 1) {
8585
const p = qhat * limb(&vn, i);
8686
const t = limb(&un, i + j) - carry - @truncate(u32, p);
87-
limb_set(&un, i + j, @truncate(u32, t));
88-
carry = @intCast(u64, p >> 32) - @intCast(u64, t >> 32);
87+
limb_set(&un, i + j, @truncate(u32, @bitCast(u64, t)));
88+
carry = @intCast(i64, p >> 32) - @intCast(i64, t >> 32);
8989
}
90-
const t = limb(&un, j + n + 1) - carry;
91-
limb_set(&un, j + n + 1, @truncate(u32, t));
90+
const t = limb(&un, j + n + 1) -% carry;
91+
limb_set(&un, j + n + 1, @truncate(u32, @bitCast(u64, t)));
9292
if (q) |q_| limb_set(q_, j, @truncate(u32, qhat));
9393
if (t < 0) {
9494
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 {
9999
limb_set(&un, i + j, @truncate(u32, t2));
100100
carry2 = t2 >> 32;
101101
}
102-
limb_set(un, j + n + 1, @truncate(u32, limb(&un, j + n + 1) + carry2));
102+
limb_set(&un, j + n + 1, @truncate(u32, limb(&un, j + n + 1) + carry2));
103103
}
104104
if (j == 0) break;
105105
}

lib/zig.h

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,10 +190,17 @@ typedef char bool;
190190

191191
#if zig_has_builtin(trap)
192192
#define zig_trap() __builtin_trap()
193+
#elif _MSC_VER && (_M_IX86 || _M_X64)
194+
#define zig_trap() __ud2()
195+
#elif _MSC_VER
196+
#define zig_trap() __fastfail(0)
193197
#elif defined(__i386__) || defined(__x86_64__)
194198
#define zig_trap() __asm__ volatile("ud2");
199+
#elif defined(__arm__) || defined(__aarch64__)
200+
#define zig_breakpoint() __asm__ volatile("udf #0");
195201
#else
196-
#define zig_trap() raise(SIGTRAP)
202+
#include <stdlib.h>
203+
#define zig_trap() abort()
197204
#endif
198205

199206
#if zig_has_builtin(debugtrap)
@@ -202,8 +209,17 @@ typedef char bool;
202209
#define zig_breakpoint() __debugbreak()
203210
#elif defined(__i386__) || defined(__x86_64__)
204211
#define zig_breakpoint() __asm__ volatile("int $0x03");
212+
#elif defined(__arm__)
213+
#define zig_breakpoint() __asm__ volatile("bkpt #0");
214+
#elif defined(__aarch64__)
215+
#define zig_breakpoint() __asm__ volatile("brk #0");
205216
#else
217+
#include <signal.h>
218+
#if defined(SIGTRAP)
206219
#define zig_breakpoint() raise(SIGTRAP)
220+
#else
221+
#define zig_breakpoint() zig_breakpoint_unavailable
222+
#endif
207223
#endif
208224

209225
#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
23842400
(void)zig_subo_big(res, lhs, rhs, is_signed, bits);
23852401
}
23862402

2403+
zig_extern void __udivei4(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uintptr_t bits);
2404+
static inline void zig_div_trunc_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) {
2405+
if (!is_signed) {
2406+
__udivei4(res, lhs, rhs, bits);
2407+
return;
2408+
}
2409+
2410+
zig_trap();
2411+
}
2412+
2413+
static inline void zig_div_floor_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) {
2414+
if (!is_signed) {
2415+
zig_div_trunc_big(res, lhs, rhs, is_signed, bits);
2416+
return;
2417+
}
2418+
2419+
zig_trap();
2420+
}
2421+
2422+
zig_extern void __umodei4(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uintptr_t bits);
2423+
static inline void zig_rem_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) {
2424+
if (!is_signed) {
2425+
__umodei4(res, lhs, rhs, bits);
2426+
return;
2427+
}
2428+
2429+
zig_trap();
2430+
}
2431+
2432+
static inline void zig_mod_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) {
2433+
if (!is_signed) {
2434+
zig_rem_big(res, lhs, rhs, is_signed, bits);
2435+
return;
2436+
}
2437+
2438+
zig_trap();
2439+
}
2440+
23872441
static inline uint16_t zig_clz_big(const void *val, bool is_signed, uint16_t bits) {
23882442
const uint8_t *val_bytes = val;
23892443
uint16_t byte_offset = 0;

src/codegen/c.zig

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1885,25 +1885,28 @@ pub const DeclGen = struct {
18851885
}
18861886

18871887
fn renderBuiltinInfo(dg: *DeclGen, writer: anytype, ty: Type, info: BuiltinInfo) !void {
1888+
const cty = try dg.typeToCType(ty, .complete);
1889+
const is_big = cty.tag() == .array;
1890+
18881891
switch (info) {
1889-
.none => {},
1890-
.bits => {
1891-
const target = dg.module.getTarget();
1892-
const int_info = if (ty.isAbiInt()) ty.intInfo(target) else std.builtin.Type.Int{
1893-
.signedness = .unsigned,
1894-
.bits = @intCast(u16, ty.bitSize(target)),
1895-
};
1892+
.none => if (!is_big) return,
1893+
.bits => {},
1894+
}
18961895

1897-
const cty = try dg.typeToCType(ty, .complete);
1898-
if (cty.tag() == .array) try writer.print(", {}", .{int_info.signedness == .signed});
1896+
const target = dg.module.getTarget();
1897+
const int_info = if (ty.isAbiInt()) ty.intInfo(target) else std.builtin.Type.Int{
1898+
.signedness = .unsigned,
1899+
.bits = @intCast(u16, ty.bitSize(target)),
1900+
};
18991901

1900-
var bits_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = int_info.bits };
1901-
try writer.print(", {}", .{try dg.fmtIntLiteral(switch (cty.tag()) {
1902-
else => Type.u8,
1903-
.array => Type.u16,
1904-
}, Value.initPayload(&bits_pl.base), .FunctionArgument)});
1905-
},
1906-
}
1902+
if (is_big) try writer.print(", {}", .{int_info.signedness == .signed});
1903+
1904+
var bits_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = int_info.bits };
1905+
try writer.print(", {}", .{try dg.fmtIntLiteral(
1906+
if (is_big) Type.u16 else Type.u8,
1907+
Value.initPayload(&bits_pl.base),
1908+
.FunctionArgument,
1909+
)});
19071910
}
19081911

19091912
fn fmtIntLiteral(
@@ -6099,20 +6102,24 @@ fn airBinBuiltinCall(
60996102
return .none;
61006103
}
61016104

6105+
const operand_ty = f.air.typeOf(bin_op.lhs);
6106+
const operand_cty = try f.typeToCType(operand_ty, .complete);
6107+
const is_big = operand_cty.tag() == .array;
6108+
61026109
const lhs = try f.resolveInst(bin_op.lhs);
61036110
const rhs = try f.resolveInst(bin_op.rhs);
6104-
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
6111+
if (!is_big) try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
61056112

61066113
const inst_ty = f.air.typeOfIndex(inst);
61076114
const inst_scalar_ty = inst_ty.scalarType();
6108-
const operand_ty = f.air.typeOf(bin_op.lhs);
61096115
const scalar_ty = operand_ty.scalarType();
61106116

61116117
const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete);
61126118
const ref_ret = inst_scalar_cty.tag() == .array;
61136119

61146120
const writer = f.object.writer();
61156121
const local = try f.allocLocal(inst, inst_ty);
6122+
if (is_big) try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
61166123
const v = try Vectorizer.start(f, inst, writer, operand_ty);
61176124
if (!ref_ret) {
61186125
try f.writeCValue(writer, local, .Other);

test/behavior/int_div.zig

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,22 @@ fn mod(comptime T: type, a: T, b: T) T {
9191
fn rem(comptime T: type, a: T, b: T) T {
9292
return @rem(a, b);
9393
}
94+
95+
test "large integer division" {
96+
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
97+
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
98+
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
99+
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
100+
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
101+
102+
{
103+
var numerator: u256 = 99999999999999999997315645440;
104+
var divisor: u256 = 10000000000000000000000000000;
105+
try expect(numerator / divisor == 9);
106+
}
107+
{
108+
var numerator: u256 = 99999999999999999999000000000000000000000;
109+
var divisor: u256 = 10000000000000000000000000000000000000000;
110+
try expect(numerator / divisor == 9);
111+
}
112+
}

0 commit comments

Comments
 (0)