1const builtin = @import("builtin");
2const endian = builtin.cpu.arch.endian();
3
4const std = @import("std");
5
6const compiler_rt = @import("../compiler_rt.zig");
7const udivmod = @import("udivmodei4.zig").divmod;
8const symbol = compiler_rt.symbol;
9
10comptime {
11 symbol(&__divei4, "__divei4");
12 symbol(&__modei4, "__modei4");
13 symbol(&__divei5, "__divei5");
14 symbol(&__modei5, "__modei5");
15}
16
17inline fn limb(i: usize, len: usize) usize {
18 return if (endian == .little) i else len - 1 - i;
19}
20
21inline fn neg(out: []u32, in: []const u32) void {
22 var ov: u1 = 1;
23 for (0..in.len) |limb_index| {
24 const new, ov = @addWithOverflow(~in[limb(limb_index, in.len)], ov);
25 out[limb(limb_index, out.len)] = new;
26 }
27}
28
29fn divmod(q: ?[]u32, r: ?[]u32, u: []const u32, v: []const u32, tu: []u32, tv: []u32) !void {
30 const u_sign: i32 = @bitCast(u[limb(u.len - 1, u.len)]);
31 const v_sign: i32 = @bitCast(v[limb(v.len - 1, v.len)]);
32 if (u_sign < 0) neg(tu, u);
33 if (v_sign < 0) neg(tv, v);
34 try @call(.always_inline, udivmod, .{ q, r, if (u_sign < 0) tu else u, if (v_sign < 0) tv else v });
35 if (q) |x| if (u_sign ^ v_sign < 0) neg(x, x);
36 if (r) |x| if (u_sign < 0) neg(x, x);
37}
38
39pub fn __divei4(q_p: [*]u8, u_p: [*]u8, v_p: [*]u8, bits: usize) callconv(.c) void {
40 @setRuntimeSafety(compiler_rt.test_safety);
41 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
42 const q: []u32 = @ptrCast(@alignCast(q_p[0..byte_size]));
43 const u: []u32 = @ptrCast(@alignCast(u_p[0..byte_size]));
44 const v: []u32 = @ptrCast(@alignCast(v_p[0..byte_size]));
45 @call(.always_inline, divmod, .{ q, null, u, v, u, v }) catch unreachable;
46}
47
48pub fn __modei4(r_p: [*]u8, u_p: [*]u8, v_p: [*]u8, bits: usize) callconv(.c) void {
49 @setRuntimeSafety(compiler_rt.test_safety);
50 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
51 const r: []u32 = @ptrCast(@alignCast(r_p[0..byte_size]));
52 const u: []u32 = @ptrCast(@alignCast(u_p[0..byte_size]));
53 const v: []u32 = @ptrCast(@alignCast(v_p[0..byte_size]));
54 @call(.always_inline, divmod, .{ null, r, u, v, u, v }) catch unreachable;
55}
56
57pub fn __divei5(q_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, t_p: [*]u8, bits: usize) callconv(.c) void {
58 @setRuntimeSafety(compiler_rt.test_safety);
59 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
60 const q: []u32 = @ptrCast(@alignCast(q_p[0..byte_size]));
61 const u: []const u32 = @ptrCast(@alignCast(u_p[0..byte_size]));
62 const v: []const u32 = @ptrCast(@alignCast(v_p[0..byte_size]));
63 const tu: []u32 = @ptrCast(@alignCast(t_p[0..byte_size]));
64 const tv: []u32 = @ptrCast(@alignCast(t_p[byte_size..][0..byte_size]));
65 @call(.always_inline, divmod, .{ q, null, u, v, tu, tv }) catch unreachable;
66}
67
68pub fn __modei5(r_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, t_p: [*]u8, bits: usize) callconv(.c) void {
69 @setRuntimeSafety(compiler_rt.test_safety);
70 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
71 const r: []u32 = @ptrCast(@alignCast(r_p[0..byte_size]));
72 const u: []const u32 = @ptrCast(@alignCast(u_p[0..byte_size]));
73 const v: []const u32 = @ptrCast(@alignCast(v_p[0..byte_size]));
74 const tu: []u32 = @ptrCast(@alignCast(t_p[0..byte_size]));
75 const tv: []u32 = @ptrCast(@alignCast(t_p[byte_size..][0..byte_size]));
76 @call(.always_inline, divmod, .{ null, r, u, v, tu, tv }) catch unreachable;
77}