| author | |
| committer | |
| log | 6fc1621cbd33f388388844bfc176a10c062779cc |
| tree | 6db39614fdc8322bab87280df0cd6892066d4afa |
| parent | bbba701a41443cdca454e65e58e5dda2f4d3188a |
| parent | e33dfc300e144dcf3323f96b38d8c67163259bb1 |
| signature |
compiler_rt: fix rare case in udivei44 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 | 79 | } |
| 80 | 80 | break; |
| 81 | 81 | } |
| 82 | var carry: u64 = 0; | |
| 82 | var carry: i64 = 0; | |
| 83 | 83 | i = 0; |
| 84 | 84 | while (i <= n) : (i += 1) { |
| 85 | 85 | const p = qhat * limb(&vn, i); |
| 86 | 86 | 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); | |
| 89 | 89 | } |
| 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))); | |
| 92 | 92 | if (q) |q_| limb_set(q_, j, @truncate(u32, qhat)); |
| 93 | 93 | if (t < 0) { |
| 94 | 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 | 99 | limb_set(&un, i + j, @truncate(u32, t2)); |
| 100 | 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 | 104 | if (j == 0) break; |
| 105 | 105 | } |
lib/zig.h+55-1| ... | ... | @@ -190,10 +190,17 @@ typedef char bool; |
| 190 | 190 | |
| 191 | 191 | #if zig_has_builtin(trap) |
| 192 | 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 | 197 | #elif defined(__i386__) || defined(__x86_64__) |
| 194 | 198 | #define zig_trap() __asm__ volatile("ud2"); |
| 199 | #elif defined(__arm__) || defined(__aarch64__) | |
| 200 | #define zig_breakpoint() __asm__ volatile("udf #0"); | |
| 195 | 201 | #else |
| 196 | #define zig_trap() raise(SIGTRAP) | |
| 202 | #include <stdlib.h> | |
| 203 | #define zig_trap() abort() | |
| 197 | 204 | #endif |
| 198 | 205 | |
| 199 | 206 | #if zig_has_builtin(debugtrap) |
| ... | ... | @@ -202,8 +209,17 @@ typedef char bool; |
| 202 | 209 | #define zig_breakpoint() __debugbreak() |
| 203 | 210 | #elif defined(__i386__) || defined(__x86_64__) |
| 204 | 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 | 216 | #else |
| 217 | #include <signal.h> | |
| 218 | #if defined(SIGTRAP) | |
| 206 | 219 | #define zig_breakpoint() raise(SIGTRAP) |
| 220 | #else | |
| 221 | #define zig_breakpoint() zig_breakpoint_unavailable | |
| 222 | #endif | |
| 207 | 223 | #endif |
| 208 | 224 | |
| 209 | 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 | 2400 | (void)zig_subo_big(res, lhs, rhs, is_signed, bits); |
| 2385 | 2401 | } |
| 2386 | 2402 | |
| 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 | ||
| 2387 | 2441 | static inline uint16_t zig_clz_big(const void *val, bool is_signed, uint16_t bits) { |
| 2388 | 2442 | const uint8_t *val_bytes = val; |
| 2389 | 2443 | uint16_t byte_offset = 0; |
src/codegen/c.zig+25-18| ... | ... | @@ -1885,25 +1885,28 @@ pub const DeclGen = struct { |
| 1885 | 1885 | } |
| 1886 | 1886 | |
| 1887 | 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 | 1891 | 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 | } | |
| 1896 | 1895 | |
| 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 | }; | |
| 1899 | 1901 | |
| 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 | )}); | |
| 1907 | 1910 | } |
| 1908 | 1911 | |
| 1909 | 1912 | fn fmtIntLiteral( |
| ... | ... | @@ -6099,13 +6102,16 @@ fn airBinBuiltinCall( |
| 6099 | 6102 | return .none; |
| 6100 | 6103 | } |
| 6101 | 6104 | |
| 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 | 6109 | const lhs = try f.resolveInst(bin_op.lhs); |
| 6103 | 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 }); | |
| 6105 | 6112 | |
| 6106 | 6113 | const inst_ty = f.air.typeOfIndex(inst); |
| 6107 | 6114 | const inst_scalar_ty = inst_ty.scalarType(); |
| 6108 | const operand_ty = f.air.typeOf(bin_op.lhs); | |
| 6109 | 6115 | const scalar_ty = operand_ty.scalarType(); |
| 6110 | 6116 | |
| 6111 | 6117 | const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete); |
| ... | ... | @@ -6113,6 +6119,7 @@ fn airBinBuiltinCall( |
| 6113 | 6119 | |
| 6114 | 6120 | const writer = f.object.writer(); |
| 6115 | 6121 | const local = try f.allocLocal(inst, inst_ty); |
| 6122 | if (is_big) try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); | |
| 6116 | 6123 | const v = try Vectorizer.start(f, inst, writer, operand_ty); |
| 6117 | 6124 | if (!ref_ret) { |
| 6118 | 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 | 91 | fn rem(comptime T: type, a: T, b: T) T { |
| 92 | 92 | return @rem(a, b); |
| 93 | 93 | } |
| 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 | } |