1const std = @import("std");
2const builtin = @import("builtin");
3const arch = builtin.cpu.arch;
4const os = builtin.os.tag;
5const abi = builtin.abi;
6const compiler_rt = @import("../compiler_rt.zig");
7const symbol = compiler_rt.symbol;
8
9comptime {
10 if (compiler_rt.want_windows_x86_msvc_abi) {
11 // Don't let LLVM apply the stdcall name mangling on those MSVC builtins
12 symbol(&_allrem, "\x01__allrem");
13 symbol(&_aullrem, "\x01__aullrem");
14 }
15}
16
17pub fn _allrem(a: i64, b: i64) callconv(.{ .x86_stdcall = .{} }) i64 {
18 const s_a = a >> (64 - 1);
19 const s_b = b >> (64 - 1);
20
21 const an = (a ^ s_a) -% s_a;
22 const bn = (b ^ s_b) -% s_b;
23
24 const r = @as(u64, @bitCast(an)) % @as(u64, @bitCast(bn));
25 const s = s_a ^ s_b;
26 return (@as(i64, @bitCast(r)) ^ s) -% s;
27}
28
29pub fn _aullrem() callconv(.naked) void {
30 @setRuntimeSafety(false);
31
32 // The stack layout is:
33 // ESP+16 divisor (hi)
34 // ESP+12 divisor (low)
35 // ESP+8 dividend (hi)
36 // ESP+4 dividend (low)
37 // ESP return address
38
39 asm volatile (
40 \\ push %%ebx
41 \\ mov 0x14(%%esp),%%eax
42 \\ or %%eax,%%eax
43 \\ jne 1f
44 \\ mov 0x10(%%esp),%%ecx
45 \\ mov 0xc(%%esp),%%eax
46 \\ xor %%edx,%%edx
47 \\ div %%ecx
48 \\ mov 0x8(%%esp),%%eax
49 \\ div %%ecx
50 \\ mov %%edx,%%eax
51 \\ xor %%edx,%%edx
52 \\ jmp 6f
53 \\ 1:
54 \\ mov %%eax,%%ecx
55 \\ mov 0x10(%%esp),%%ebx
56 \\ mov 0xc(%%esp),%%edx
57 \\ mov 0x8(%%esp),%%eax
58 \\ 2:
59 \\ shr %%ecx
60 \\ rcr %%ebx
61 \\ shr %%edx
62 \\ rcr %%eax
63 \\ or %%ecx,%%ecx
64 \\ jne 2b
65 \\ div %%ebx
66 \\ mov %%eax,%%ecx
67 \\ mull 0x14(%%esp)
68 \\ xchg %%eax,%%ecx
69 \\ mull 0x10(%%esp)
70 \\ add %%ecx,%%edx
71 \\ jb 3f
72 \\ cmp 0xc(%%esp),%%edx
73 \\ ja 3f
74 \\ jb 4f
75 \\ cmp 0x8(%%esp),%%eax
76 \\ jbe 4f
77 \\ 3:
78 \\ sub 0x10(%%esp),%%eax
79 \\ sbb 0x14(%%esp),%%edx
80 \\ 4:
81 \\ sub 0x8(%%esp),%%eax
82 \\ sbb 0xc(%%esp),%%edx
83 \\ neg %%edx
84 \\ neg %%eax
85 \\ sbb $0x0,%%edx
86 \\ 6:
87 \\ pop %%ebx
88 \\ ret $0x10
89 );
90}