authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-03-07 19:32:32-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-03-07 19:32:32-05:00
log6fc1621cbd33f388388844bfc176a10c062779cc
tree6db39614fdc8322bab87280df0cd6892066d4afa
parentbbba701a41443cdca454e65e58e5dda2f4d3188a
parente33dfc300e144dcf3323f96b38d8c67163259bb1
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #14828 from jacobly0/fix-big-div

compiler_rt: fix rare case in udivei4

4 files changed, 105 insertions(+), 25 deletions(-)

lib/compiler_rt/udivmodei4.zig+6-6
...@@ -79,16 +79,16 @@ fn divmod(q: ?[]u32, r: ?[]u32, u: []const u32, v: []const u32) !void {...@@ -79,16 +79,16 @@ fn divmod(q: ?[]u32, r: ?[]u32, u: []const u32, v: []const u32) !void {
79 }79 }
80 break;80 break;
81 }81 }
82 var carry: u64 = 0;82 var carry: i64 = 0;
83 i = 0;83 i = 0;
84 while (i <= n) : (i += 1) {84 while (i <= n) : (i += 1) {
85 const p = qhat * limb(&vn, i);85 const p = qhat * limb(&vn, i);
86 const t = limb(&un, i + j) - carry - @truncate(u32, p);86 const t = limb(&un, i + j) - carry - @truncate(u32, p);
87 limb_set(&un, i + j, @truncate(u32, t));87 limb_set(&un, i + j, @truncate(u32, @bitCast(u64, t)));
88 carry = @intCast(u64, p >> 32) - @intCast(u64, t >> 32);88 carry = @intCast(i64, p >> 32) - @intCast(i64, t >> 32);
89 }89 }
90 const t = limb(&un, j + n + 1) - carry;90 const t = limb(&un, j + n + 1) -% carry;
91 limb_set(&un, j + n + 1, @truncate(u32, t));91 limb_set(&un, j + n + 1, @truncate(u32, @bitCast(u64, t)));
92 if (q) |q_| limb_set(q_, j, @truncate(u32, qhat));92 if (q) |q_| limb_set(q_, j, @truncate(u32, qhat));
93 if (t < 0) {93 if (t < 0) {
94 if (q) |q_| limb_set(q_, j, limb(q_, j) - 1);94 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 {...@@ -99,7 +99,7 @@ fn divmod(q: ?[]u32, r: ?[]u32, u: []const u32, v: []const u32) !void {
99 limb_set(&un, i + j, @truncate(u32, t2));99 limb_set(&un, i + j, @truncate(u32, t2));
100 carry2 = t2 >> 32;100 carry2 = t2 >> 32;
101 }101 }
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));
103 }103 }
104 if (j == 0) break;104 if (j == 0) break;
105 }105 }
lib/zig.h+55-1
...@@ -190,10 +190,17 @@ typedef char bool;...@@ -190,10 +190,17 @@ typedef char bool;
190190
191#if zig_has_builtin(trap)191#if zig_has_builtin(trap)
192#define zig_trap() __builtin_trap()192#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)
193#elif defined(__i386__) || defined(__x86_64__)197#elif defined(__i386__) || defined(__x86_64__)
194#define zig_trap() __asm__ volatile("ud2");198#define zig_trap() __asm__ volatile("ud2");
199#elif defined(__arm__) || defined(__aarch64__)
200#define zig_breakpoint() __asm__ volatile("udf #0");
195#else201#else
196#define zig_trap() raise(SIGTRAP)202#include <stdlib.h>
203#define zig_trap() abort()
197#endif204#endif
198205
199#if zig_has_builtin(debugtrap)206#if zig_has_builtin(debugtrap)
...@@ -202,8 +209,17 @@ typedef char bool;...@@ -202,8 +209,17 @@ typedef char bool;
202#define zig_breakpoint() __debugbreak()209#define zig_breakpoint() __debugbreak()
203#elif defined(__i386__) || defined(__x86_64__)210#elif defined(__i386__) || defined(__x86_64__)
204#define zig_breakpoint() __asm__ volatile("int $0x03");211#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");
205#else216#else
217#include <signal.h>
218#if defined(SIGTRAP)
206#define zig_breakpoint() raise(SIGTRAP)219#define zig_breakpoint() raise(SIGTRAP)
220#else
221#define zig_breakpoint() zig_breakpoint_unavailable
222#endif
207#endif223#endif
208224
209#if zig_has_builtin(return_address) || defined(zig_gnuc)225#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...@@ -2384,6 +2400,44 @@ static inline void zig_subw_big(void *res, const void *lhs, const void *rhs, boo
2384 (void)zig_subo_big(res, lhs, rhs, is_signed, bits);2400 (void)zig_subo_big(res, lhs, rhs, is_signed, bits);
2385}2401}
23862402
2403zig_extern void __udivei4(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uintptr_t bits);
2404static 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
2413static 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
2422zig_extern void __umodei4(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uintptr_t bits);
2423static 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
2432static 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
2387static inline uint16_t zig_clz_big(const void *val, bool is_signed, uint16_t bits) {2441static inline uint16_t zig_clz_big(const void *val, bool is_signed, uint16_t bits) {
2388 const uint8_t *val_bytes = val;2442 const uint8_t *val_bytes = val;
2389 uint16_t byte_offset = 0;2443 uint16_t byte_offset = 0;
src/codegen/c.zig+25-18
...@@ -1885,25 +1885,28 @@ pub const DeclGen = struct {...@@ -1885,25 +1885,28 @@ pub const DeclGen = struct {
1885 }1885 }
18861886
1887 fn renderBuiltinInfo(dg: *DeclGen, writer: anytype, ty: Type, info: BuiltinInfo) !void {1887 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
1888 switch (info) {1891 switch (info) {
1889 .none => {},1892 .none => if (!is_big) return,
1890 .bits => {1893 .bits => {},
1891 const target = dg.module.getTarget();1894 }
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 };
18961895
1897 const cty = try dg.typeToCType(ty, .complete);1896 const target = dg.module.getTarget();
1898 if (cty.tag() == .array) try writer.print(", {}", .{int_info.signedness == .signed});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 };1902 if (is_big) try writer.print(", {}", .{int_info.signedness == .signed});
1901 try writer.print(", {}", .{try dg.fmtIntLiteral(switch (cty.tag()) {1903
1902 else => Type.u8,1904 var bits_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = int_info.bits };
1903 .array => Type.u16,1905 try writer.print(", {}", .{try dg.fmtIntLiteral(
1904 }, Value.initPayload(&bits_pl.base), .FunctionArgument)});1906 if (is_big) Type.u16 else Type.u8,
1905 },1907 Value.initPayload(&bits_pl.base),
1906 }1908 .FunctionArgument,
1909 )});
1907 }1910 }
19081911
1909 fn fmtIntLiteral(1912 fn fmtIntLiteral(
...@@ -6099,13 +6102,16 @@ fn airBinBuiltinCall(...@@ -6099,13 +6102,16 @@ fn airBinBuiltinCall(
6099 return .none;6102 return .none;
6100 }6103 }
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
6102 const lhs = try f.resolveInst(bin_op.lhs);6109 const lhs = try f.resolveInst(bin_op.lhs);
6103 const rhs = try f.resolveInst(bin_op.rhs);6110 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
6106 const inst_ty = f.air.typeOfIndex(inst);6113 const inst_ty = f.air.typeOfIndex(inst);
6107 const inst_scalar_ty = inst_ty.scalarType();6114 const inst_scalar_ty = inst_ty.scalarType();
6108 const operand_ty = f.air.typeOf(bin_op.lhs);
6109 const scalar_ty = operand_ty.scalarType();6115 const scalar_ty = operand_ty.scalarType();
61106116
6111 const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete);6117 const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete);
...@@ -6113,6 +6119,7 @@ fn airBinBuiltinCall(...@@ -6113,6 +6119,7 @@ fn airBinBuiltinCall(
61136119
6114 const writer = f.object.writer();6120 const writer = f.object.writer();
6115 const local = try f.allocLocal(inst, inst_ty);6121 const local = try f.allocLocal(inst, inst_ty);
6122 if (is_big) try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
6116 const v = try Vectorizer.start(f, inst, writer, operand_ty);6123 const v = try Vectorizer.start(f, inst, writer, operand_ty);
6117 if (!ref_ret) {6124 if (!ref_ret) {
6118 try f.writeCValue(writer, local, .Other);6125 try f.writeCValue(writer, local, .Other);
test/behavior/int_div.zig+19
...@@ -91,3 +91,22 @@ fn mod(comptime T: type, a: T, b: T) T {...@@ -91,3 +91,22 @@ fn mod(comptime T: type, a: T, b: T) T {
91fn rem(comptime T: type, a: T, b: T) T {91fn rem(comptime T: type, a: T, b: T) T {
92 return @rem(a, b);92 return @rem(a, b);
93}93}
94
95test "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}