comptime { _ = @import("comparetf2.zig"); _ = @import("fixunsdfdi.zig"); _ = @import("fixunsdfsi.zig"); _ = @import("fixunsdfti.zig"); _ = @import("fixunssfdi.zig"); _ = @import("fixunssfsi.zig"); _ = @import("fixunssfti.zig"); _ = @import("fixunstfdi.zig"); _ = @import("fixunstfsi.zig"); _ = @import("fixunstfti.zig"); _ = @import("udivmoddi4.zig"); _ = @import("udivmodti4.zig"); _ = @import("udivti3.zig"); _ = @import("umodti3.zig"); _ = @import("aulldiv.zig"); _ = @import("aullrem.zig"); } const builtin = @import("builtin"); const is_test = builtin.is_test; const assert = @import("../../debug.zig").assert; const win32 = builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386; const win64 = builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.x86_64; const win32_nocrt = win32 and !builtin.link_libc; const win64_nocrt = win64 and !builtin.link_libc; pub const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak; const strong_linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong; const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4; // Avoid dragging in the debug safety mechanisms into this .o file, // unless we're trying to test this file. pub coldcc fn panic(msg: []const u8) -> noreturn { if (is_test) { @import("std").debug.panic("{}", msg); } else { unreachable; } } export fn __udivdi3(a: u64, b: u64) -> u64 { @setDebugSafety(this, is_test); @setGlobalLinkage(__udivdi3, linkage); return __udivmoddi4(a, b, null); } export fn __umoddi3(a: u64, b: u64) -> u64 { @setDebugSafety(this, is_test); @setGlobalLinkage(__umoddi3, linkage); var r: u64 = undefined; _ = __udivmoddi4(a, b, &r); return r; } const AeabiUlDivModResult = extern struct { quot: u64, rem: u64, }; export fn __aeabi_uldivmod(numerator: u64, denominator: u64) -> AeabiUlDivModResult { @setDebugSafety(this, is_test); if (comptime isArmArch()) { @setGlobalLinkage(__aeabi_uldivmod, linkage); var result: AeabiUlDivModResult = undefined; result.quot = __udivmoddi4(numerator, denominator, &result.rem); return result; } @setGlobalLinkage(__aeabi_uldivmod, builtin.GlobalLinkage.Internal); unreachable; } fn isArmArch() -> bool { return switch (builtin.arch) { builtin.Arch.armv8_2a, builtin.Arch.armv8_1a, builtin.Arch.armv8, builtin.Arch.armv8r, builtin.Arch.armv8m_baseline, builtin.Arch.armv8m_mainline, builtin.Arch.armv7, builtin.Arch.armv7em, builtin.Arch.armv7m, builtin.Arch.armv7s, builtin.Arch.armv7k, builtin.Arch.armv6, builtin.Arch.armv6m, builtin.Arch.armv6k, builtin.Arch.armv6t2, builtin.Arch.armv5, builtin.Arch.armv5te, builtin.Arch.armv4t, builtin.Arch.armeb => true, else => false, }; } export nakedcc fn __aeabi_uidivmod() { @setDebugSafety(this, false); if (comptime isArmArch()) { @setGlobalLinkage(__aeabi_uidivmod, linkage); asm volatile ( \\ push { lr } \\ sub sp, sp, #4 \\ mov r2, sp \\ bl __udivmodsi4 \\ ldr r1, [sp] \\ add sp, sp, #4 \\ pop { pc } ::: "r2", "r1"); unreachable; } @setGlobalLinkage(__aeabi_uidivmod, builtin.GlobalLinkage.Internal); } // _chkstk (_alloca) routine - probe stack between %esp and (%esp-%eax) in 4k increments, // then decrement %esp by %eax. Preserves all registers except %esp and flags. // This routine is windows specific // http://msdn.microsoft.com/en-us/library/ms648426.aspx export nakedcc fn _chkstk() align(4) { @setDebugSafety(this, false); if (win32_nocrt) { @setGlobalLinkage(_chkstk, strong_linkage); asm volatile ( \\ push %%ecx \\ push %%eax \\ cmp $0x1000,%%eax \\ lea 12(%%esp),%%ecx \\ jb 1f \\ 2: \\ sub $0x1000,%%ecx \\ test %%ecx,(%%ecx) \\ sub $0x1000,%%eax \\ cmp $0x1000,%%eax \\ ja 2b \\ 1: \\ sub %%eax,%%ecx \\ test %%ecx,(%%ecx) \\ pop %%eax \\ pop %%ecx \\ ret ); unreachable; } @setGlobalLinkage(_chkstk, builtin.GlobalLinkage.Internal); } export nakedcc fn __chkstk() align(4) { @setDebugSafety(this, false); if (win64_nocrt) { @setGlobalLinkage(__chkstk, strong_linkage); asm volatile ( \\ push %%rcx \\ push %%rax \\ cmp $0x1000,%%rax \\ lea 24(%%rsp),%%rcx \\ jb 1f \\2: \\ sub $0x1000,%%rcx \\ test %%rcx,(%%rcx) \\ sub $0x1000,%%rax \\ cmp $0x1000,%%rax \\ ja 2b \\1: \\ sub %%rax,%%rcx \\ test %%rcx,(%%rcx) \\ pop %%rax \\ pop %%rcx \\ ret ); unreachable; } @setGlobalLinkage(__chkstk, builtin.GlobalLinkage.Internal); } // _chkstk routine // This routine is windows specific // http://msdn.microsoft.com/en-us/library/ms648426.aspx export nakedcc fn __chkstk_ms() align(4) { @setDebugSafety(this, false); if (win32_nocrt) { @setGlobalLinkage(__chkstk_ms, linkage); asm volatile ( \\ push %%ecx \\ push %%eax \\ cmp $0x1000,%%eax \\ lea 12(%%esp),%%ecx \\ jb 1f \\ 2: \\ sub $0x1000,%%ecx \\ test %%ecx,(%%ecx) \\ sub $0x1000,%%eax \\ cmp $0x1000,%%eax \\ ja 2b \\ 1: \\ sub %%eax,%%ecx \\ test %%ecx,(%%ecx) \\ pop %%eax \\ pop %%ecx \\ ret ); unreachable; } @setGlobalLinkage(__chkstk_ms, builtin.GlobalLinkage.Internal); } export nakedcc fn ___chkstk_ms() align(4) { @setDebugSafety(this, false); if (win64_nocrt) { @setGlobalLinkage(___chkstk_ms, linkage); asm volatile ( \\ push %%rcx \\ push %%rax \\ cmp $0x1000,%%rax \\ lea 24(%%rsp),%%rcx \\ jb 1f \\2: \\ sub $0x1000,%%rcx \\ test %%rcx,(%%rcx) \\ sub $0x1000,%%rax \\ cmp $0x1000,%%rax \\ ja 2b \\1: \\ sub %%rax,%%rcx \\ test %%rcx,(%%rcx) \\ pop %%rax \\ pop %%rcx \\ ret ); unreachable; } @setGlobalLinkage(___chkstk_ms, builtin.GlobalLinkage.Internal); } export fn __udivmodsi4(a: u32, b: u32, rem: &u32) -> u32 { @setDebugSafety(this, is_test); @setGlobalLinkage(__udivmodsi4, linkage); const d = __udivsi3(a, b); *rem = u32(i32(a) -% (i32(d) * i32(b))); return d; } // TODO make this an alias instead of an extra function call // https://github.com/andrewrk/zig/issues/256 export fn __aeabi_uidiv(n: u32, d: u32) -> u32 { @setDebugSafety(this, is_test); @setGlobalLinkage(__aeabi_uidiv, linkage); return __udivsi3(n, d); } export fn __udivsi3(n: u32, d: u32) -> u32 { @setDebugSafety(this, is_test); @setGlobalLinkage(__udivsi3, linkage); const n_uword_bits: c_uint = u32.bit_count; // special cases if (d == 0) return 0; // ?! if (n == 0) return 0; var sr = @bitCast(c_uint, c_int(@clz(d)) - c_int(@clz(n))); // 0 <= sr <= n_uword_bits - 1 or sr large if (sr > n_uword_bits - 1) // d > r return 0; if (sr == n_uword_bits - 1) // d == 1 return n; sr += 1; // 1 <= sr <= n_uword_bits - 1 // Not a special case var q: u32 = n << u5(n_uword_bits - sr); var r: u32 = n >> u5(sr); var carry: u32 = 0; while (sr > 0) : (sr -= 1) { // r:q = ((r:q) << 1) | carry r = (r << 1) | (q >> u5(n_uword_bits - 1)); q = (q << 1) | carry; // carry = 0; // if (r.all >= d.all) // { // r.all -= d.all; // carry = 1; // } const s = i32(d -% r -% 1) >> u5(n_uword_bits - 1); carry = u32(s & 1); r -= d & @bitCast(u32, s); } q = (q << 1) | carry; return q; } test "test_umoddi3" { test_one_umoddi3(0, 1, 0); test_one_umoddi3(2, 1, 0); test_one_umoddi3(0x8000000000000000, 1, 0x0); test_one_umoddi3(0x8000000000000000, 2, 0x0); test_one_umoddi3(0xFFFFFFFFFFFFFFFF, 2, 0x1); } fn test_one_umoddi3(a: u64, b: u64, expected_r: u64) { const r = __umoddi3(a, b); assert(r == expected_r); } test "test_udivsi3" { const cases = [][3]u32 { []u32{0x00000000, 0x00000001, 0x00000000}, []u32{0x00000000, 0x00000002, 0x00000000}, []u32{0x00000000, 0x00000003, 0x00000000}, []u32{0x00000000, 0x00000010, 0x00000000}, []u32{0x00000000, 0x078644FA, 0x00000000}, []u32{0x00000000, 0x0747AE14, 0x00000000}, []u32{0x00000000, 0x7FFFFFFF, 0x00000000}, []u32{0x00000000, 0x80000000, 0x00000000}, []u32{0x00000000, 0xFFFFFFFD, 0x00000000}, []u32{0x00000000, 0xFFFFFFFE, 0x00000000}, []u32{0x00000000, 0xFFFFFFFF, 0x00000000}, []u32{0x00000001, 0x00000001, 0x00000001}, []u32{0x00000001, 0x00000002, 0x00000000}, []u32{0x00000001, 0x00000003, 0x00000000}, []u32{0x00000001, 0x00000010, 0x00000000}, []u32{0x00000001, 0x078644FA, 0x00000000}, []u32{0x00000001, 0x0747AE14, 0x00000000}, []u32{0x00000001, 0x7FFFFFFF, 0x00000000}, []u32{0x00000001, 0x80000000, 0x00000000}, []u32{0x00000001, 0xFFFFFFFD, 0x00000000}, []u32{0x00000001, 0xFFFFFFFE, 0x00000000}, []u32{0x00000001, 0xFFFFFFFF, 0x00000000}, []u32{0x00000002, 0x00000001, 0x00000002}, []u32{0x00000002, 0x00000002, 0x00000001}, []u32{0x00000002, 0x00000003, 0x00000000}, []u32{0x00000002, 0x00000010, 0x00000000}, []u32{0x00000002, 0x078644FA, 0x00000000}, []u32{0x00000002, 0x0747AE14, 0x00000000}, []u32{0x00000002, 0x7FFFFFFF, 0x00000000}, []u32{0x00000002, 0x80000000, 0x00000000}, []u32{0x00000002, 0xFFFFFFFD, 0x00000000}, []u32{0x00000002, 0xFFFFFFFE, 0x00000000}, []u32{0x00000002, 0xFFFFFFFF, 0x00000000}, []u32{0x00000003, 0x00000001, 0x00000003}, []u32{0x00000003, 0x00000002, 0x00000001}, []u32{0x00000003, 0x00000003, 0x00000001}, []u32{0x00000003, 0x00000010, 0x00000000}, []u32{0x00000003, 0x078644FA, 0x00000000}, []u32{0x00000003, 0x0747AE14, 0x00000000}, []u32{0x00000003, 0x7FFFFFFF, 0x00000000}, []u32{0x00000003, 0x80000000, 0x00000000}, []u32{0x00000003, 0xFFFFFFFD, 0x00000000}, []u32{0x00000003, 0xFFFFFFFE, 0x00000000}, []u32{0x00000003, 0xFFFFFFFF, 0x00000000}, []u32{0x00000010, 0x00000001, 0x00000010}, []u32{0x00000010, 0x00000002, 0x00000008}, []u32{0x00000010, 0x00000003, 0x00000005}, []u32{0x00000010, 0x00000010, 0x00000001}, []u32{0x00000010, 0x078644FA, 0x00000000}, []u32{0x00000010, 0x0747AE14, 0x00000000}, []u32{0x00000010, 0x7FFFFFFF, 0x00000000}, []u32{0x00000010, 0x80000000, 0x00000000}, []u32{0x00000010, 0xFFFFFFFD, 0x00000000}, []u32{0x00000010, 0xFFFFFFFE, 0x00000000}, []u32{0x00000010, 0xFFFFFFFF, 0x00000000}, []u32{0x078644FA, 0x00000001, 0x078644FA}, []u32{0x078644FA, 0x00000002, 0x03C3227D}, []u32{0x078644FA, 0x00000003, 0x028216FE}, []u32{0x078644FA, 0x00000010, 0x0078644F}, []u32{0x078644FA, 0x078644FA, 0x00000001}, []u32{0x078644FA, 0x0747AE14, 0x00000001}, []u32{0x078644FA, 0x7FFFFFFF, 0x00000000}, []u32{0x078644FA, 0x80000000, 0x00000000}, []u32{0x078644FA, 0xFFFFFFFD, 0x00000000}, []u32{0x078644FA, 0xFFFFFFFE, 0x00000000}, []u32{0x078644FA, 0xFFFFFFFF, 0x00000000}, []u32{0x0747AE14, 0x00000001, 0x0747AE14}, []u32{0x0747AE14, 0x00000002, 0x03A3D70A}, []u32{0x0747AE14, 0x00000003, 0x026D3A06}, []u32{0x0747AE14, 0x00000010, 0x00747AE1}, []u32{0x0747AE14, 0x078644FA, 0x00000000}, []u32{0x0747AE14, 0x0747AE14, 0x00000001}, []u32{0x0747AE14, 0x7FFFFFFF, 0x00000000}, []u32{0x0747AE14, 0x80000000, 0x00000000}, []u32{0x0747AE14, 0xFFFFFFFD, 0x00000000}, []u32{0x0747AE14, 0xFFFFFFFE, 0x00000000}, []u32{0x0747AE14, 0xFFFFFFFF, 0x00000000}, []u32{0x7FFFFFFF, 0x00000001, 0x7FFFFFFF}, []u32{0x7FFFFFFF, 0x00000002, 0x3FFFFFFF}, []u32{0x7FFFFFFF, 0x00000003, 0x2AAAAAAA}, []u32{0x7FFFFFFF, 0x00000010, 0x07FFFFFF}, []u32{0x7FFFFFFF, 0x078644FA, 0x00000011}, []u32{0x7FFFFFFF, 0x0747AE14, 0x00000011}, []u32{0x7FFFFFFF, 0x7FFFFFFF, 0x00000001}, []u32{0x7FFFFFFF, 0x80000000, 0x00000000}, []u32{0x7FFFFFFF, 0xFFFFFFFD, 0x00000000}, []u32{0x7FFFFFFF, 0xFFFFFFFE, 0x00000000}, []u32{0x7FFFFFFF, 0xFFFFFFFF, 0x00000000}, []u32{0x80000000, 0x00000001, 0x80000000}, []u32{0x80000000, 0x00000002, 0x40000000}, []u32{0x80000000, 0x00000003, 0x2AAAAAAA}, []u32{0x80000000, 0x00000010, 0x08000000}, []u32{0x80000000, 0x078644FA, 0x00000011}, []u32{0x80000000, 0x0747AE14, 0x00000011}, []u32{0x80000000, 0x7FFFFFFF, 0x00000001}, []u32{0x80000000, 0x80000000, 0x00000001}, []u32{0x80000000, 0xFFFFFFFD, 0x00000000}, []u32{0x80000000, 0xFFFFFFFE, 0x00000000}, []u32{0x80000000, 0xFFFFFFFF, 0x00000000}, []u32{0xFFFFFFFD, 0x00000001, 0xFFFFFFFD}, []u32{0xFFFFFFFD, 0x00000002, 0x7FFFFFFE}, []u32{0xFFFFFFFD, 0x00000003, 0x55555554}, []u32{0xFFFFFFFD, 0x00000010, 0x0FFFFFFF}, []u32{0xFFFFFFFD, 0x078644FA, 0x00000022}, []u32{0xFFFFFFFD, 0x0747AE14, 0x00000023}, []u32{0xFFFFFFFD, 0x7FFFFFFF, 0x00000001}, []u32{0xFFFFFFFD, 0x80000000, 0x00000001}, []u32{0xFFFFFFFD, 0xFFFFFFFD, 0x00000001}, []u32{0xFFFFFFFD, 0xFFFFFFFE, 0x00000000}, []u32{0xFFFFFFFD, 0xFFFFFFFF, 0x00000000}, []u32{0xFFFFFFFE, 0x00000001, 0xFFFFFFFE}, []u32{0xFFFFFFFE, 0x00000002, 0x7FFFFFFF}, []u32{0xFFFFFFFE, 0x00000003, 0x55555554}, []u32{0xFFFFFFFE, 0x00000010, 0x0FFFFFFF}, []u32{0xFFFFFFFE, 0x078644FA, 0x00000022}, []u32{0xFFFFFFFE, 0x0747AE14, 0x00000023}, []u32{0xFFFFFFFE, 0x7FFFFFFF, 0x00000002}, []u32{0xFFFFFFFE, 0x80000000, 0x00000001}, []u32{0xFFFFFFFE, 0xFFFFFFFD, 0x00000001}, []u32{0xFFFFFFFE, 0xFFFFFFFE, 0x00000001}, []u32{0xFFFFFFFE, 0xFFFFFFFF, 0x00000000}, []u32{0xFFFFFFFF, 0x00000001, 0xFFFFFFFF}, []u32{0xFFFFFFFF, 0x00000002, 0x7FFFFFFF}, []u32{0xFFFFFFFF, 0x00000003, 0x55555555}, []u32{0xFFFFFFFF, 0x00000010, 0x0FFFFFFF}, []u32{0xFFFFFFFF, 0x078644FA, 0x00000022}, []u32{0xFFFFFFFF, 0x0747AE14, 0x00000023}, []u32{0xFFFFFFFF, 0x7FFFFFFF, 0x00000002}, []u32{0xFFFFFFFF, 0x80000000, 0x00000001}, []u32{0xFFFFFFFF, 0xFFFFFFFD, 0x00000001}, []u32{0xFFFFFFFF, 0xFFFFFFFE, 0x00000001}, []u32{0xFFFFFFFF, 0xFFFFFFFF, 0x00000001}, }; for (cases) |case| { test_one_udivsi3(case[0], case[1], case[2]); } } fn test_one_udivsi3(a: u32, b: u32, expected_q: u32) { const q: u32 = __udivsi3(a, b); assert(q == expected_q); }