diff --git a/lib/compiler_rt/udivmodei4.zig b/lib/compiler_rt/udivmodei4.zig index de2427b79f4f..38a9b66b78a5 100644 --- a/lib/compiler_rt/udivmodei4.zig +++ b/lib/compiler_rt/udivmodei4.zig @@ -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; } diff --git a/lib/zig.h b/lib/zig.h index 65fb21f99a45..59c3ddd69544 100644 --- a/lib/zig.h +++ b/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 +#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 +#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; diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 3d059adc1598..519b2b45d522 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -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 => { - 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)), - }; + .none => if (!is_big) return, + .bits => {}, + } - const cty = try dg.typeToCType(ty, .complete); - if (cty.tag() == .array) try writer.print(", {}", .{int_info.signedness == .signed}); + 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)), + }; - 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)}); - }, - } + 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( + 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); diff --git a/test/behavior/int_div.zig b/test/behavior/int_div.zig index 6ae794d3776e..954f6be22017 100644 --- a/test/behavior/int_div.zig +++ b/test/behavior/int_div.zig @@ -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); + } +}