diff options
author | Alexey Samsonov <samsonov@google.com> | 2014-02-14 09:20:33 +0000 |
---|---|---|
committer | Alexey Samsonov <samsonov@google.com> | 2014-02-14 09:20:33 +0000 |
commit | 53aa4fda49f94920139300227786ac47c393f1ce (patch) | |
tree | 6d022d04ee279fe1afd89668f346e28a9e3e1559 /lib/builtins | |
parent | 6d999e478fecb10dc43f20b85385d25cc239db0a (diff) |
Move original compiler-rt functions (libgcc replacement) to lib/builtins directory
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@201393 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/builtins')
237 files changed, 13730 insertions, 0 deletions
diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt new file mode 100644 index 000000000..81ae21f7d --- /dev/null +++ b/lib/builtins/CMakeLists.txt @@ -0,0 +1,233 @@ +# This directory contains a large amount of C code which provides +# generic implementations of the core runtime library along with optimized +# architecture-specific code in various subdirectories. + +set(GENERIC_SOURCES + absvdi2.c + absvsi2.c + absvti2.c + adddf3.c + addsf3.c + addvdi3.c + addvsi3.c + addvti3.c + apple_versioning.c + ashldi3.c + ashlti3.c + ashrdi3.c + ashrti3.c + # FIXME: atomic.c may only be compiled if host compiler understands _Atomic + # atomic.c + clear_cache.c + clzdi2.c + clzsi2.c + clzti2.c + cmpdi2.c + cmpti2.c + comparedf2.c + comparesf2.c + ctzdi2.c + ctzsi2.c + ctzti2.c + divdc3.c + divdf3.c + divdi3.c + divmoddi4.c + divmodsi4.c + divsc3.c + divsf3.c + divsi3.c + divti3.c + divxc3.c + enable_execute_stack.c + eprintf.c + extendsfdf2.c + ffsdi2.c + ffsti2.c + fixdfdi.c + fixdfsi.c + fixdfti.c + fixsfdi.c + fixsfsi.c + fixsfti.c + fixunsdfdi.c + fixunsdfsi.c + fixunsdfti.c + fixunssfdi.c + fixunssfsi.c + fixunssfti.c + fixunsxfdi.c + fixunsxfsi.c + fixunsxfti.c + fixxfdi.c + fixxfti.c + floatdidf.c + floatdisf.c + floatdixf.c + floatsidf.c + floatsisf.c + floattidf.c + floattisf.c + floattixf.c + floatundidf.c + floatundisf.c + floatundixf.c + floatunsidf.c + floatunsisf.c + floatuntidf.c + floatuntisf.c + floatuntixf.c + gcc_personality_v0.c + int_util.c + lshrdi3.c + lshrti3.c + moddi3.c + modsi3.c + modti3.c + muldc3.c + muldf3.c + muldi3.c + mulodi4.c + mulosi4.c + muloti4.c + mulsc3.c + mulsf3.c + multi3.c + mulvdi3.c + mulvsi3.c + mulvti3.c + mulxc3.c + negdf2.c + negdi2.c + negsf2.c + negti2.c + negvdi2.c + negvsi2.c + negvti2.c + paritydi2.c + paritysi2.c + parityti2.c + popcountdi2.c + popcountsi2.c + popcountti2.c + powidf2.c + powisf2.c + powitf2.c + powixf2.c + subdf3.c + subsf3.c + subvdi3.c + subvsi3.c + subvti3.c + trampoline_setup.c + truncdfsf2.c + ucmpdi2.c + ucmpti2.c + udivdi3.c + udivmoddi4.c + udivmodsi4.c + udivmodti4.c + udivsi3.c + udivti3.c + umoddi3.c + umodsi3.c + umodti3.c) + +set(x86_64_SOURCES + x86_64/floatdidf.c + x86_64/floatdisf.c + x86_64/floatdixf.c + x86_64/floatundidf.S + x86_64/floatundisf.S + x86_64/floatundixf.S + ${GENERIC_SOURCES}) + +set(i386_SOURCES + i386/ashldi3.S + i386/ashrdi3.S + i386/divdi3.S + i386/floatdidf.S + i386/floatdisf.S + i386/floatdixf.S + i386/floatundidf.S + i386/floatundisf.S + i386/floatundixf.S + i386/lshrdi3.S + i386/moddi3.S + i386/muldi3.S + i386/udivdi3.S + i386/umoddi3.S + ${GENERIC_SOURCES}) + +set(arm_SOURCES + arm/adddf3vfp.S + arm/addsf3vfp.S + arm/aeabi_dcmp.S + arm/aeabi_fcmp.S + arm/aeabi_idivmod.S + arm/aeabi_ldivmod.S + arm/aeabi_memcmp.S + arm/aeabi_memcpy.S + arm/aeabi_memmove.S + arm/aeabi_memset.S + arm/aeabi_uidivmod.S + arm/aeabi_uldivmod.S + arm/bswapdi2.S + arm/bswapsi2.S + arm/comparesf2.S + arm/divdf3vfp.S + arm/divmodsi4.S + arm/divsf3vfp.S + arm/divsi3.S + arm/eqdf2vfp.S + arm/eqsf2vfp.S + arm/extendsfdf2vfp.S + arm/fixdfsivfp.S + arm/fixsfsivfp.S + arm/fixunsdfsivfp.S + arm/fixunssfsivfp.S + arm/floatsidfvfp.S + arm/floatsisfvfp.S + arm/floatunssidfvfp.S + arm/floatunssisfvfp.S + arm/gedf2vfp.S + arm/gesf2vfp.S + arm/gtdf2vfp.S + arm/gtsf2vfp.S + arm/ledf2vfp.S + arm/lesf2vfp.S + arm/ltdf2vfp.S + arm/ltsf2vfp.S + arm/modsi3.S + arm/muldf3vfp.S + arm/mulsf3vfp.S + arm/nedf2vfp.S + arm/negdf2vfp.S + arm/negsf2vfp.S + arm/nesf2vfp.S + arm/restore_vfp_d8_d15_regs.S + arm/save_vfp_d8_d15_regs.S + arm/subdf3vfp.S + arm/subsf3vfp.S + arm/switch16.S + arm/switch32.S + arm/switch8.S + arm/switchu8.S + arm/sync_synchronize.S + arm/truncdfsf2vfp.S + arm/udivmodsi4.S + arm/udivsi3.S + arm/umodsi3.S + arm/unorddf2vfp.S + arm/unordsf2vfp.S + ${GENERIC_SOURCES}) + +if (NOT WIN32) + foreach(arch x86_64 i386 arm) + if(CAN_TARGET_${arch}) + add_compiler_rt_static_runtime(clang_rt.${arch} ${arch} + SOURCES ${${arch}_SOURCES} + CFLAGS "-std=c99") + endif() + endforeach() +endif() diff --git a/lib/builtins/Makefile.mk b/lib/builtins/Makefile.mk new file mode 100644 index 000000000..3143d91f0 --- /dev/null +++ b/lib/builtins/Makefile.mk @@ -0,0 +1,22 @@ +#===- lib/builtins/Makefile.mk -----------------------------*- Makefile -*--===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# + +ModuleName := builtins +SubDirs := + +# Add arch specific optimized implementations. +SubDirs += i386 ppc x86_64 arm + +# Define the variables for this specific directory. +Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file))) +ObjNames := $(Sources:%.c=%.o) +Implementation := Generic + +# FIXME: use automatic dependencies? +Dependencies := $(wildcard $(Dir)/*.h) diff --git a/lib/builtins/absvdi2.c b/lib/builtins/absvdi2.c new file mode 100644 index 000000000..682c2355d --- /dev/null +++ b/lib/builtins/absvdi2.c @@ -0,0 +1,29 @@ +/*===-- absvdi2.c - Implement __absvdi2 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + *===----------------------------------------------------------------------=== + * + * This file implements __absvdi2 for the compiler_rt library. + * + *===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: absolute value */ + +/* Effects: aborts if abs(x) < 0 */ + +COMPILER_RT_ABI di_int +__absvdi2(di_int a) +{ + const int N = (int)(sizeof(di_int) * CHAR_BIT); + if (a == ((di_int)1 << (N-1))) + compilerrt_abort(); + const di_int t = a >> (N - 1); + return (a ^ t) - t; +} diff --git a/lib/builtins/absvsi2.c b/lib/builtins/absvsi2.c new file mode 100644 index 000000000..4812af815 --- /dev/null +++ b/lib/builtins/absvsi2.c @@ -0,0 +1,29 @@ +/* ===-- absvsi2.c - Implement __absvsi2 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __absvsi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: absolute value */ + +/* Effects: aborts if abs(x) < 0 */ + +COMPILER_RT_ABI si_int +__absvsi2(si_int a) +{ + const int N = (int)(sizeof(si_int) * CHAR_BIT); + if (a == (1 << (N-1))) + compilerrt_abort(); + const si_int t = a >> (N - 1); + return (a ^ t) - t; +} diff --git a/lib/builtins/absvti2.c b/lib/builtins/absvti2.c new file mode 100644 index 000000000..c1c727798 --- /dev/null +++ b/lib/builtins/absvti2.c @@ -0,0 +1,33 @@ +/* ===-- absvti2.c - Implement __absvdi2 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __absvti2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: absolute value */ + +/* Effects: aborts if abs(x) < 0 */ + +ti_int +__absvti2(ti_int a) +{ + const int N = (int)(sizeof(ti_int) * CHAR_BIT); + if (a == ((ti_int)1 << (N-1))) + compilerrt_abort(); + const ti_int s = a >> (N - 1); + return (a ^ s) - s; +} + +#endif diff --git a/lib/builtins/adddf3.c b/lib/builtins/adddf3.c new file mode 100644 index 000000000..a55e82d21 --- /dev/null +++ b/lib/builtins/adddf3.c @@ -0,0 +1,152 @@ +//===-- lib/adddf3.c - Double-precision addition ------------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements double-precision soft-float addition with the IEEE-754 +// default rounding (to nearest, ties to even). +// +//===----------------------------------------------------------------------===// + +#define DOUBLE_PRECISION +#include "fp_lib.h" + +ARM_EABI_FNALIAS(dadd, adddf3) + +COMPILER_RT_ABI fp_t +__adddf3(fp_t a, fp_t b) { + + rep_t aRep = toRep(a); + rep_t bRep = toRep(b); + const rep_t aAbs = aRep & absMask; + const rep_t bAbs = bRep & absMask; + + // Detect if a or b is zero, infinity, or NaN. + if (aAbs - 1U >= infRep - 1U || bAbs - 1U >= infRep - 1U) { + + // NaN + anything = qNaN + if (aAbs > infRep) return fromRep(toRep(a) | quietBit); + // anything + NaN = qNaN + if (bAbs > infRep) return fromRep(toRep(b) | quietBit); + + if (aAbs == infRep) { + // +/-infinity + -/+infinity = qNaN + if ((toRep(a) ^ toRep(b)) == signBit) return fromRep(qnanRep); + // +/-infinity + anything remaining = +/- infinity + else return a; + } + + // anything remaining + +/-infinity = +/-infinity + if (bAbs == infRep) return b; + + // zero + anything = anything + if (!aAbs) { + // but we need to get the sign right for zero + zero + if (!bAbs) return fromRep(toRep(a) & toRep(b)); + else return b; + } + + // anything + zero = anything + if (!bAbs) return a; + } + + // Swap a and b if necessary so that a has the larger absolute value. + if (bAbs > aAbs) { + const rep_t temp = aRep; + aRep = bRep; + bRep = temp; + } + + // Extract the exponent and significand from the (possibly swapped) a and b. + int aExponent = aRep >> significandBits & maxExponent; + int bExponent = bRep >> significandBits & maxExponent; + rep_t aSignificand = aRep & significandMask; + rep_t bSignificand = bRep & significandMask; + + // Normalize any denormals, and adjust the exponent accordingly. + if (aExponent == 0) aExponent = normalize(&aSignificand); + if (bExponent == 0) bExponent = normalize(&bSignificand); + + // The sign of the result is the sign of the larger operand, a. If they + // have opposite signs, we are performing a subtraction; otherwise addition. + const rep_t resultSign = aRep & signBit; + const bool subtraction = (aRep ^ bRep) & signBit; + + // Shift the significands to give us round, guard and sticky, and or in the + // implicit significand bit. (If we fell through from the denormal path it + // was already set by normalize( ), but setting it twice won't hurt + // anything.) + aSignificand = (aSignificand | implicitBit) << 3; + bSignificand = (bSignificand | implicitBit) << 3; + + // Shift the significand of b by the difference in exponents, with a sticky + // bottom bit to get rounding correct. + const unsigned int align = aExponent - bExponent; + if (align) { + if (align < typeWidth) { + const bool sticky = bSignificand << (typeWidth - align); + bSignificand = bSignificand >> align | sticky; + } else { + bSignificand = 1; // sticky; b is known to be non-zero. + } + } + + if (subtraction) { + aSignificand -= bSignificand; + + // If a == -b, return +zero. + if (aSignificand == 0) return fromRep(0); + + // If partial cancellation occured, we need to left-shift the result + // and adjust the exponent: + if (aSignificand < implicitBit << 3) { + const int shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3); + aSignificand <<= shift; + aExponent -= shift; + } + } + + else /* addition */ { + aSignificand += bSignificand; + + // If the addition carried up, we need to right-shift the result and + // adjust the exponent: + if (aSignificand & implicitBit << 4) { + const bool sticky = aSignificand & 1; + aSignificand = aSignificand >> 1 | sticky; + aExponent += 1; + } + } + + // If we have overflowed the type, return +/- infinity: + if (aExponent >= maxExponent) return fromRep(infRep | resultSign); + + if (aExponent <= 0) { + // Result is denormal before rounding; the exponent is zero and we + // need to shift the significand. + const int shift = 1 - aExponent; + const bool sticky = aSignificand << (typeWidth - shift); + aSignificand = aSignificand >> shift | sticky; + aExponent = 0; + } + + // Low three bits are round, guard, and sticky. + const int roundGuardSticky = aSignificand & 0x7; + + // Shift the significand into place, and mask off the implicit bit. + rep_t result = aSignificand >> 3 & significandMask; + + // Insert the exponent and sign. + result |= (rep_t)aExponent << significandBits; + result |= resultSign; + + // Final rounding. The result may overflow to infinity, but that is the + // correct result in that case. + if (roundGuardSticky > 0x4) result++; + if (roundGuardSticky == 0x4) result += result & 1; + return fromRep(result); +} diff --git a/lib/builtins/addsf3.c b/lib/builtins/addsf3.c new file mode 100644 index 000000000..0268324de --- /dev/null +++ b/lib/builtins/addsf3.c @@ -0,0 +1,151 @@ +//===-- lib/addsf3.c - Single-precision addition ------------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements single-precision soft-float addition with the IEEE-754 +// default rounding (to nearest, ties to even). +// +//===----------------------------------------------------------------------===// + +#define SINGLE_PRECISION +#include "fp_lib.h" + +ARM_EABI_FNALIAS(fadd, addsf3) + +fp_t __addsf3(fp_t a, fp_t b) { + + rep_t aRep = toRep(a); + rep_t bRep = toRep(b); + const rep_t aAbs = aRep & absMask; + const rep_t bAbs = bRep & absMask; + + // Detect if a or b is zero, infinity, or NaN. + if (aAbs - 1U >= infRep - 1U || bAbs - 1U >= infRep - 1U) { + + // NaN + anything = qNaN + if (aAbs > infRep) return fromRep(toRep(a) | quietBit); + // anything + NaN = qNaN + if (bAbs > infRep) return fromRep(toRep(b) | quietBit); + + if (aAbs == infRep) { + // +/-infinity + -/+infinity = qNaN + if ((toRep(a) ^ toRep(b)) == signBit) return fromRep(qnanRep); + // +/-infinity + anything remaining = +/- infinity + else return a; + } + + // anything remaining + +/-infinity = +/-infinity + if (bAbs == infRep) return b; + + // zero + anything = anything + if (!aAbs) { + // but we need to get the sign right for zero + zero + if (!bAbs) return fromRep(toRep(a) & toRep(b)); + else return b; + } + + // anything + zero = anything + if (!bAbs) return a; + } + + // Swap a and b if necessary so that a has the larger absolute value. + if (bAbs > aAbs) { + const rep_t temp = aRep; + aRep = bRep; + bRep = temp; + } + + // Extract the exponent and significand from the (possibly swapped) a and b. + int aExponent = aRep >> significandBits & maxExponent; + int bExponent = bRep >> significandBits & maxExponent; + rep_t aSignificand = aRep & significandMask; + rep_t bSignificand = bRep & significandMask; + + // Normalize any denormals, and adjust the exponent accordingly. + if (aExponent == 0) aExponent = normalize(&aSignificand); + if (bExponent == 0) bExponent = normalize(&bSignificand); + + // The sign of the result is the sign of the larger operand, a. If they + // have opposite signs, we are performing a subtraction; otherwise addition. + const rep_t resultSign = aRep & signBit; + const bool subtraction = (aRep ^ bRep) & signBit; + + // Shift the significands to give us round, guard and sticky, and or in the + // implicit significand bit. (If we fell through from the denormal path it + // was already set by normalize( ), but setting it twice won't hurt + // anything.) + aSignificand = (aSignificand | implicitBit) << 3; + bSignificand = (bSignificand | implicitBit) << 3; + + // Shift the significand of b by the difference in exponents, with a sticky + // bottom bit to get rounding correct. + const unsigned int align = aExponent - bExponent; + if (align) { + if (align < typeWidth) { + const bool sticky = bSignificand << (typeWidth - align); + bSignificand = bSignificand >> align | sticky; + } else { + bSignificand = 1; // sticky; b is known to be non-zero. + } + } + + if (subtraction) { + aSignificand -= bSignificand; + + // If a == -b, return +zero. + if (aSignificand == 0) return fromRep(0); + + // If partial cancellation occured, we need to left-shift the result + // and adjust the exponent: + if (aSignificand < implicitBit << 3) { + const int shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3); + aSignificand <<= shift; + aExponent -= shift; + } + } + + else /* addition */ { + aSignificand += bSignificand; + + // If the addition carried up, we need to right-shift the result and + // adjust the exponent: + if (aSignificand & implicitBit << 4) { + const bool sticky = aSignificand & 1; + aSignificand = aSignificand >> 1 | sticky; + aExponent += 1; + } + } + + // If we have overflowed the type, return +/- infinity: + if (aExponent >= maxExponent) return fromRep(infRep | resultSign); + + if (aExponent <= 0) { + // Result is denormal before rounding; the exponent is zero and we + // need to shift the significand. + const int shift = 1 - aExponent; + const bool sticky = aSignificand << (typeWidth - shift); + aSignificand = aSignificand >> shift | sticky; + aExponent = 0; + } + + // Low three bits are round, guard, and sticky. + const int roundGuardSticky = aSignificand & 0x7; + + // Shift the significand into place, and mask off the implicit bit. + rep_t result = aSignificand >> 3 & significandMask; + + // Insert the exponent and sign. + result |= (rep_t)aExponent << significandBits; + result |= resultSign; + + // Final rounding. The result may overflow to infinity, but that is the + // correct result in that case. + if (roundGuardSticky > 0x4) result++; + if (roundGuardSticky == 0x4) result += result & 1; + return fromRep(result); +} diff --git a/lib/builtins/addvdi3.c b/lib/builtins/addvdi3.c new file mode 100644 index 000000000..db45a27f0 --- /dev/null +++ b/lib/builtins/addvdi3.c @@ -0,0 +1,36 @@ +/* ===-- addvdi3.c - Implement __addvdi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __addvdi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: a + b */ + +/* Effects: aborts if a + b overflows */ + +COMPILER_RT_ABI di_int +__addvdi3(di_int a, di_int b) +{ + di_int s = a + b; + if (b >= 0) + { + if (s < a) + compilerrt_abort(); + } + else + { + if (s >= a) + compilerrt_abort(); + } + return s; +} diff --git a/lib/builtins/addvsi3.c b/lib/builtins/addvsi3.c new file mode 100644 index 000000000..81f515cd7 --- /dev/null +++ b/lib/builtins/addvsi3.c @@ -0,0 +1,36 @@ +/* ===-- addvsi3.c - Implement __addvsi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __addvsi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: a + b */ + +/* Effects: aborts if a + b overflows */ + +COMPILER_RT_ABI si_int +__addvsi3(si_int a, si_int b) +{ + si_int s = a + b; + if (b >= 0) + { + if (s < a) + compilerrt_abort(); + } + else + { + if (s >= a) + compilerrt_abort(); + } + return s; +} diff --git a/lib/builtins/addvti3.c b/lib/builtins/addvti3.c new file mode 100644 index 000000000..2efcf3b40 --- /dev/null +++ b/lib/builtins/addvti3.c @@ -0,0 +1,40 @@ +/* ===-- addvti3.c - Implement __addvti3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __addvti3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: a + b */ + +/* Effects: aborts if a + b overflows */ + +ti_int +__addvti3(ti_int a, ti_int b) +{ + ti_int s = a + b; + if (b >= 0) + { + if (s < a) + compilerrt_abort(); + } + else + { + if (s >= a) + compilerrt_abort(); + } + return s; +} + +#endif diff --git a/lib/builtins/apple_versioning.c b/lib/builtins/apple_versioning.c new file mode 100644 index 000000000..3797a1ab0 --- /dev/null +++ b/lib/builtins/apple_versioning.c @@ -0,0 +1,350 @@ +/* ===-- apple_versioning.c - Adds versioning symbols for ld ---------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + */ + + +#if __APPLE__ + #include <Availability.h> + + #if __IPHONE_OS_VERSION_MIN_REQUIRED + #define NOT_HERE_BEFORE_10_6(sym) + #define NOT_HERE_IN_10_8_AND_EARLIER(sym) \ + extern const char sym##_tmp61 __asm("$ld$hide$os6.1$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp61 = 0; \ + extern const char sym##_tmp60 __asm("$ld$hide$os6.0$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp60 = 0; \ + extern const char sym##_tmp51 __asm("$ld$hide$os5.1$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp51 = 0; \ + extern const char sym##_tmp50 __asm("$ld$hide$os5.0$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp50 = 0; + #else + #define NOT_HERE_BEFORE_10_6(sym) \ + extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \ + extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp5 = 0; + #define NOT_HERE_IN_10_8_AND_EARLIER(sym) \ + extern const char sym##_tmp8 __asm("$ld$hide$os10.8$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp8 = 0; \ + extern const char sym##_tmp7 __asm("$ld$hide$os10.7$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp7 = 0; \ + extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp6 = 0; + #endif + + +/* Symbols in libSystem.dylib in 10.6 and later, + * but are in libgcc_s.dylib in earlier versions + */ + +NOT_HERE_BEFORE_10_6(__absvdi2) +NOT_HERE_BEFORE_10_6(__absvsi2) +NOT_HERE_BEFORE_10_6(__absvti2) +NOT_HERE_BEFORE_10_6(__addvdi3) +NOT_HERE_BEFORE_10_6(__addvsi3) +NOT_HERE_BEFORE_10_6(__addvti3) +NOT_HERE_BEFORE_10_6(__ashldi3) +NOT_HERE_BEFORE_10_6(__ashlti3) +NOT_HERE_BEFORE_10_6(__ashrdi3) +NOT_HERE_BEFORE_10_6(__ashrti3) +NOT_HERE_BEFORE_10_6(__clear_cache) +NOT_HERE_BEFORE_10_6(__clzdi2) +NOT_HERE_BEFORE_10_6(__clzsi2) +NOT_HERE_BEFORE_10_6(__clzti2) +NOT_HERE_BEFORE_10_6(__cmpdi2) +NOT_HERE_BEFORE_10_6(__cmpti2) +NOT_HERE_BEFORE_10_6(__ctzdi2) +NOT_HERE_BEFORE_10_6(__ctzsi2) +NOT_HERE_BEFORE_10_6(__ctzti2) +NOT_HERE_BEFORE_10_6(__divdc3) +NOT_HERE_BEFORE_10_6(__divdi3) +NOT_HERE_BEFORE_10_6(__divsc3) +NOT_HERE_BEFORE_10_6(__divtc3) +NOT_HERE_BEFORE_10_6(__divti3) +NOT_HERE_BEFORE_10_6(__divxc3) +NOT_HERE_BEFORE_10_6(__enable_execute_stack) +NOT_HERE_BEFORE_10_6(__ffsdi2) +NOT_HERE_BEFORE_10_6(__ffsti2) +NOT_HERE_BEFORE_10_6(__fixdfdi) +NOT_HERE_BEFORE_10_6(__fixdfti) +NOT_HERE_BEFORE_10_6(__fixsfdi) +NOT_HERE_BEFORE_10_6(__fixsfti) +NOT_HERE_BEFORE_10_6(__fixtfdi) +NOT_HERE_BEFORE_10_6(__fixunsdfdi) +NOT_HERE_BEFORE_10_6(__fixunsdfsi) +NOT_HERE_BEFORE_10_6(__fixunsdfti) +NOT_HERE_BEFORE_10_6(__fixunssfdi) +NOT_HERE_BEFORE_10_6(__fixunssfsi) +NOT_HERE_BEFORE_10_6(__fixunssfti) +NOT_HERE_BEFORE_10_6(__fixunstfdi) +NOT_HERE_BEFORE_10_6(__fixunsxfdi) +NOT_HERE_BEFORE_10_6(__fixunsxfsi) +NOT_HERE_BEFORE_10_6(__fixunsxfti) +NOT_HERE_BEFORE_10_6(__fixxfdi) +NOT_HERE_BEFORE_10_6(__fixxfti) +NOT_HERE_BEFORE_10_6(__floatdidf) +NOT_HERE_BEFORE_10_6(__floatdisf) +NOT_HERE_BEFORE_10_6(__floatditf) +NOT_HERE_BEFORE_10_6(__floatdixf) +NOT_HERE_BEFORE_10_6(__floattidf) +NOT_HERE_BEFORE_10_6(__floattisf) +NOT_HERE_BEFORE_10_6(__floattixf) +NOT_HERE_BEFORE_10_6(__floatundidf) +NOT_HERE_BEFORE_10_6(__floatundisf) +NOT_HERE_BEFORE_10_6(__floatunditf) +NOT_HERE_BEFORE_10_6(__floatundixf) +NOT_HERE_BEFORE_10_6(__floatuntidf) +NOT_HERE_BEFORE_10_6(__floatuntisf) +NOT_HERE_BEFORE_10_6(__floatuntixf) +NOT_HERE_BEFORE_10_6(__gcc_personality_v0) +NOT_HERE_BEFORE_10_6(__lshrdi3) +NOT_HERE_BEFORE_10_6(__lshrti3) +NOT_HERE_BEFORE_10_6(__moddi3) +NOT_HERE_BEFORE_10_6(__modti3) +NOT_HERE_BEFORE_10_6(__muldc3) +NOT_HERE_BEFORE_10_6(__muldi3) +NOT_HERE_BEFORE_10_6(__mulsc3) +NOT_HERE_BEFORE_10_6(__multc3) +NOT_HERE_BEFORE_10_6(__multi3) +NOT_HERE_BEFORE_10_6(__mulvdi3) +NOT_HERE_BEFORE_10_6(__mulvsi3) +NOT_HERE_BEFORE_10_6(__mulvti3) +NOT_HERE_BEFORE_10_6(__mulxc3) +NOT_HERE_BEFORE_10_6(__negdi2) +NOT_HERE_BEFORE_10_6(__negti2) +NOT_HERE_BEFORE_10_6(__negvdi2) +NOT_HERE_BEFORE_10_6(__negvsi2) +NOT_HERE_BEFORE_10_6(__negvti2) +NOT_HERE_BEFORE_10_6(__paritydi2) +NOT_HERE_BEFORE_10_6(__paritysi2) +NOT_HERE_BEFORE_10_6(__parityti2) +NOT_HERE_BEFORE_10_6(__popcountdi2) +NOT_HERE_BEFORE_10_6(__popcountsi2) +NOT_HERE_BEFORE_10_6(__popcountti2) +NOT_HERE_BEFORE_10_6(__powidf2) +NOT_HERE_BEFORE_10_6(__powisf2) +NOT_HERE_BEFORE_10_6(__powitf2) +NOT_HERE_BEFORE_10_6(__powixf2) +NOT_HERE_BEFORE_10_6(__subvdi3) +NOT_HERE_BEFORE_10_6(__subvsi3) +NOT_HERE_BEFORE_10_6(__subvti3) +NOT_HERE_BEFORE_10_6(__ucmpdi2) +NOT_HERE_BEFORE_10_6(__ucmpti2) +NOT_HERE_BEFORE_10_6(__udivdi3) +NOT_HERE_BEFORE_10_6(__udivmoddi4) +NOT_HERE_BEFORE_10_6(__udivmodti4) +NOT_HERE_BEFORE_10_6(__udivti3) +NOT_HERE_BEFORE_10_6(__umoddi3) +NOT_HERE_BEFORE_10_6(__umodti3) + + +#if __ppc__ +NOT_HERE_BEFORE_10_6(__gcc_qadd) +NOT_HERE_BEFORE_10_6(__gcc_qdiv) +NOT_HERE_BEFORE_10_6(__gcc_qmul) +NOT_HERE_BEFORE_10_6(__gcc_qsub) +NOT_HERE_BEFORE_10_6(__trampoline_setup) +#endif /* __ppc__ */ + +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange_1) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange_2) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange_4) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange_8) + +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_exchange) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_exchange_1) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_exchange_2) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_exchange_4) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_exchange_8) + +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_add_1) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_add_2) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_add_4) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_add_8) + +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_and_1) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_and_2) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_and_4) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_and_8) + +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_or_1) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_or_2) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_or_4) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_or_8) + +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_sub_1) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_sub_2) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_sub_4) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_sub_8) + +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_xor_1) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_xor_2) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_xor_4) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_fetch_xor_8) + +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_load) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_load_1) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_load_2) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_load_4) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_load_8) + +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store_1) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store_2) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store_4) +NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store_8) + + +#if __arm__ && __DYNAMIC__ + #define NOT_HERE_UNTIL_AFTER_4_3(sym) \ + extern const char sym##_tmp1 __asm("$ld$hide$os3.0$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp1 = 0; \ + extern const char sym##_tmp2 __asm("$ld$hide$os3.1$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp2 = 0; \ + extern const char sym##_tmp3 __asm("$ld$hide$os3.2$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp3 = 0; \ + extern const char sym##_tmp4 __asm("$ld$hide$os4.0$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \ + extern const char sym##_tmp5 __asm("$ld$hide$os4.1$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp5 = 0; \ + extern const char sym##_tmp6 __asm("$ld$hide$os4.2$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp6 = 0; \ + extern const char sym##_tmp7 __asm("$ld$hide$os4.3$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp7 = 0; + +NOT_HERE_UNTIL_AFTER_4_3(__absvdi2) +NOT_HERE_UNTIL_AFTER_4_3(__absvsi2) +NOT_HERE_UNTIL_AFTER_4_3(__adddf3) +NOT_HERE_UNTIL_AFTER_4_3(__adddf3vfp) +NOT_HERE_UNTIL_AFTER_4_3(__addsf3) +NOT_HERE_UNTIL_AFTER_4_3(__addsf3vfp) +NOT_HERE_UNTIL_AFTER_4_3(__addvdi3) +NOT_HERE_UNTIL_AFTER_4_3(__addvsi3) +NOT_HERE_UNTIL_AFTER_4_3(__ashldi3) +NOT_HERE_UNTIL_AFTER_4_3(__ashrdi3) +NOT_HERE_UNTIL_AFTER_4_3(__bswapdi2) +NOT_HERE_UNTIL_AFTER_4_3(__bswapsi2) +NOT_HERE_UNTIL_AFTER_4_3(__clzdi2) +NOT_HERE_UNTIL_AFTER_4_3(__clzsi2) +NOT_HERE_UNTIL_AFTER_4_3(__cmpdi2) +NOT_HERE_UNTIL_AFTER_4_3(__ctzdi2) +NOT_HERE_UNTIL_AFTER_4_3(__ctzsi2) +NOT_HERE_UNTIL_AFTER_4_3(__divdc3) +NOT_HERE_UNTIL_AFTER_4_3(__divdf3) +NOT_HERE_UNTIL_AFTER_4_3(__divdf3vfp) +NOT_HERE_UNTIL_AFTER_4_3(__divdi3) +NOT_HERE_UNTIL_AFTER_4_3(__divsc3) +NOT_HERE_UNTIL_AFTER_4_3(__divsf3) +NOT_HERE_UNTIL_AFTER_4_3(__divsf3vfp) +NOT_HERE_UNTIL_AFTER_4_3(__divsi3) +NOT_HERE_UNTIL_AFTER_4_3(__eqdf2) +NOT_HERE_UNTIL_AFTER_4_3(__eqdf2vfp) +NOT_HERE_UNTIL_AFTER_4_3(__eqsf2) +NOT_HERE_UNTIL_AFTER_4_3(__eqsf2vfp) +NOT_HERE_UNTIL_AFTER_4_3(__extendsfdf2) +NOT_HERE_UNTIL_AFTER_4_3(__extendsfdf2vfp) +NOT_HERE_UNTIL_AFTER_4_3(__ffsdi2) +NOT_HERE_UNTIL_AFTER_4_3(__fixdfdi) +NOT_HERE_UNTIL_AFTER_4_3(__fixdfsi) +NOT_HERE_UNTIL_AFTER_4_3(__fixdfsivfp) +NOT_HERE_UNTIL_AFTER_4_3(__fixsfdi) +NOT_HERE_UNTIL_AFTER_4_3(__fixsfsi) +NOT_HERE_UNTIL_AFTER_4_3(__fixsfsivfp) +NOT_HERE_UNTIL_AFTER_4_3(__fixunsdfdi) +NOT_HERE_UNTIL_AFTER_4_3(__fixunsdfsi) +NOT_HERE_UNTIL_AFTER_4_3(__fixunsdfsivfp) +NOT_HERE_UNTIL_AFTER_4_3(__fixunssfdi) +NOT_HERE_UNTIL_AFTER_4_3(__fixunssfsi) +NOT_HERE_UNTIL_AFTER_4_3(__fixunssfsivfp) +NOT_HERE_UNTIL_AFTER_4_3(__floatdidf) +NOT_HERE_UNTIL_AFTER_4_3(__floatdisf) +NOT_HERE_UNTIL_AFTER_4_3(__floatsidf) +NOT_HERE_UNTIL_AFTER_4_3(__floatsidfvfp) +NOT_HERE_UNTIL_AFTER_4_3(__floatsisf) +NOT_HERE_UNTIL_AFTER_4_3(__floatsisfvfp) +NOT_HERE_UNTIL_AFTER_4_3(__floatundidf) +NOT_HERE_UNTIL_AFTER_4_3(__floatundisf) +NOT_HERE_UNTIL_AFTER_4_3(__floatunsidf) +NOT_HERE_UNTIL_AFTER_4_3(__floatunsisf) +NOT_HERE_UNTIL_AFTER_4_3(__floatunssidfvfp) +NOT_HERE_UNTIL_AFTER_4_3(__floatunssisfvfp) +NOT_HERE_UNTIL_AFTER_4_3(__gedf2) +NOT_HERE_UNTIL_AFTER_4_3(__gedf2vfp) +NOT_HERE_UNTIL_AFTER_4_3(__gesf2) +NOT_HERE_UNTIL_AFTER_4_3(__gesf2vfp) +NOT_HERE_UNTIL_AFTER_4_3(__gtdf2) +NOT_HERE_UNTIL_AFTER_4_3(__gtdf2vfp) +NOT_HERE_UNTIL_AFTER_4_3(__gtsf2) +NOT_HERE_UNTIL_AFTER_4_3(__gtsf2vfp) +NOT_HERE_UNTIL_AFTER_4_3(__ledf2) +NOT_HERE_UNTIL_AFTER_4_3(__ledf2vfp) +NOT_HERE_UNTIL_AFTER_4_3(__lesf2) +NOT_HERE_UNTIL_AFTER_4_3(__lesf2vfp) +NOT_HERE_UNTIL_AFTER_4_3(__lshrdi3) +NOT_HERE_UNTIL_AFTER_4_3(__ltdf2) +NOT_HERE_UNTIL_AFTER_4_3(__ltdf2vfp) +NOT_HERE_UNTIL_AFTER_4_3(__ltsf2) +NOT_HERE_UNTIL_AFTER_4_3(__ltsf2vfp) +NOT_HERE_UNTIL_AFTER_4_3(__moddi3) +NOT_HERE_UNTIL_AFTER_4_3(__modsi3) +NOT_HERE_UNTIL_AFTER_4_3(__muldc3) +NOT_HERE_UNTIL_AFTER_4_3(__muldf3) +NOT_HERE_UNTIL_AFTER_4_3(__muldf3vfp) +NOT_HERE_UNTIL_AFTER_4_3(__muldi3) +NOT_HERE_UNTIL_AFTER_4_3(__mulsc3) +NOT_HERE_UNTIL_AFTER_4_3(__mulsf3) +NOT_HERE_UNTIL_AFTER_4_3(__mulsf3vfp) +NOT_HERE_UNTIL_AFTER_4_3(__mulvdi3) +NOT_HERE_UNTIL_AFTER_4_3(__mulvsi3) +NOT_HERE_UNTIL_AFTER_4_3(__nedf2) +NOT_HERE_UNTIL_AFTER_4_3(__nedf2vfp) +NOT_HERE_UNTIL_AFTER_4_3(__negdi2) +NOT_HERE_UNTIL_AFTER_4_3(__negvdi2) +NOT_HERE_UNTIL_AFTER_4_3(__negvsi2) +NOT_HERE_UNTIL_AFTER_4_3(__nesf2) +NOT_HERE_UNTIL_AFTER_4_3(__nesf2vfp) +NOT_HERE_UNTIL_AFTER_4_3(__paritydi2) +NOT_HERE_UNTIL_AFTER_4_3(__paritysi2) +NOT_HERE_UNTIL_AFTER_4_3(__popcountdi2) +NOT_HERE_UNTIL_AFTER_4_3(__popcountsi2) +NOT_HERE_UNTIL_AFTER_4_3(__powidf2) +NOT_HERE_UNTIL_AFTER_4_3(__powisf2) +NOT_HERE_UNTIL_AFTER_4_3(__subdf3) +NOT_HERE_UNTIL_AFTER_4_3(__subdf3vfp) +NOT_HERE_UNTIL_AFTER_4_3(__subsf3) +NOT_HERE_UNTIL_AFTER_4_3(__subsf3vfp) +NOT_HERE_UNTIL_AFTER_4_3(__subvdi3) +NOT_HERE_UNTIL_AFTER_4_3(__subvsi3) +NOT_HERE_UNTIL_AFTER_4_3(__truncdfsf2) +NOT_HERE_UNTIL_AFTER_4_3(__truncdfsf2vfp) +NOT_HERE_UNTIL_AFTER_4_3(__ucmpdi2) +NOT_HERE_UNTIL_AFTER_4_3(__udivdi3) +NOT_HERE_UNTIL_AFTER_4_3(__udivmoddi4) +NOT_HERE_UNTIL_AFTER_4_3(__udivsi3) +NOT_HERE_UNTIL_AFTER_4_3(__umoddi3) +NOT_HERE_UNTIL_AFTER_4_3(__umodsi3) +NOT_HERE_UNTIL_AFTER_4_3(__unorddf2) +NOT_HERE_UNTIL_AFTER_4_3(__unorddf2vfp) +NOT_HERE_UNTIL_AFTER_4_3(__unordsf2) +NOT_HERE_UNTIL_AFTER_4_3(__unordsf2vfp) + +NOT_HERE_UNTIL_AFTER_4_3(__divmodsi4) +NOT_HERE_UNTIL_AFTER_4_3(__udivmodsi4) +#endif // __arm__ && __DYNAMIC__ + + + + + +#else /* !__APPLE__ */ + +extern int avoid_empty_file; + +#endif /* !__APPLE__*/ diff --git a/lib/builtins/arm/Makefile.mk b/lib/builtins/arm/Makefile.mk new file mode 100644 index 000000000..ed2e8323e --- /dev/null +++ b/lib/builtins/arm/Makefile.mk @@ -0,0 +1,20 @@ +#===- lib/builtins/arm/Makefile.mk -------------------------*- Makefile -*--===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# + +ModuleName := builtins +SubDirs := +OnlyArchs := armv5 armv6 armv7 armv7k armv7m armv7em armv7s + +AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file))) +Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file))) +ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o) +Implementation := Optimized + +# FIXME: use automatic dependencies? +Dependencies := $(wildcard lib/*.h $(Dir)/*.h) diff --git a/lib/builtins/arm/adddf3vfp.S b/lib/builtins/arm/adddf3vfp.S new file mode 100644 index 000000000..4302b6ab3 --- /dev/null +++ b/lib/builtins/arm/adddf3vfp.S @@ -0,0 +1,26 @@ +//===-- adddf3vfp.S - Implement adddf3vfp ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// double __adddf3vfp(double a, double b) { return a + b; } +// +// Adds two double precision floating point numbers using the Darwin +// calling convention where double arguments are passsed in GPR pairs +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__adddf3vfp) + vmov d6, r0, r1 // move first param from r0/r1 pair into d6 + vmov d7, r2, r3 // move second param from r2/r3 pair into d7 + vadd.f64 d6, d6, d7 + vmov r0, r1, d6 // move result back to r0/r1 pair + bx lr +END_COMPILERRT_FUNCTION(__adddf3vfp) diff --git a/lib/builtins/arm/addsf3vfp.S b/lib/builtins/arm/addsf3vfp.S new file mode 100644 index 000000000..316328abe --- /dev/null +++ b/lib/builtins/arm/addsf3vfp.S @@ -0,0 +1,26 @@ +//===-- addsf3vfp.S - Implement addsf3vfp ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern float __addsf3vfp(float a, float b); +// +// Adds two single precision floating point numbers using the Darwin +// calling convention where single arguments are passsed in GPRs +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__addsf3vfp) + vmov s14, r0 // move first param from r0 into float register + vmov s15, r1 // move second param from r1 into float register + vadd.f32 s14, s14, s15 + vmov r0, s14 // move result back to r0 + bx lr +END_COMPILERRT_FUNCTION(__addsf3vfp) diff --git a/lib/builtins/arm/aeabi_dcmp.S b/lib/builtins/arm/aeabi_dcmp.S new file mode 100644 index 000000000..ee2946d2d --- /dev/null +++ b/lib/builtins/arm/aeabi_dcmp.S @@ -0,0 +1,40 @@ +//===-- aeabi_dcmp.S - EABI dcmp* implementation ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// int __aeabi_dcmp{eq,lt,le,ge,gt}(double a, double b) { +// int result = __{eq,lt,le,ge,gt}df2(a, b); +// if (result {==,<,<=,>=,>} 0) { +// return 1; +// } else { +// return 0; +// } +// } + +#define DEFINE_AEABI_DCMP(cond) \ + .syntax unified SEPARATOR \ + .align 2 SEPARATOR \ +DEFINE_COMPILERRT_FUNCTION(__aeabi_dcmp ## cond) \ + push { r4, lr } SEPARATOR \ + bl SYMBOL_NAME(__ ## cond ## df2) SEPARATOR \ + cmp r0, #0 SEPARATOR \ + b ## cond 1f SEPARATOR \ + mov r0, #0 SEPARATOR \ + pop { r4, pc } SEPARATOR \ +1: SEPARATOR \ + mov r0, #1 SEPARATOR \ + pop { r4, pc } SEPARATOR \ +END_COMPILERRT_FUNCTION(__aeabi_dcmp ## cond) + +DEFINE_AEABI_DCMP(eq) +DEFINE_AEABI_DCMP(lt) +DEFINE_AEABI_DCMP(le) +DEFINE_AEABI_DCMP(ge) +DEFINE_AEABI_DCMP(gt) diff --git a/lib/builtins/arm/aeabi_fcmp.S b/lib/builtins/arm/aeabi_fcmp.S new file mode 100644 index 000000000..ac3f54721 --- /dev/null +++ b/lib/builtins/arm/aeabi_fcmp.S @@ -0,0 +1,40 @@ +//===-- aeabi_fcmp.S - EABI fcmp* implementation ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// int __aeabi_fcmp{eq,lt,le,ge,gt}(float a, float b) { +// int result = __{eq,lt,le,ge,gt}sf2(a, b); +// if (result {==,<,<=,>=,>} 0) { +// return 1; +// } else { +// return 0; +// } +// } + +#define DEFINE_AEABI_FCMP(cond) \ + .syntax unified SEPARATOR \ + .align 2 SEPARATOR \ +DEFINE_COMPILERRT_FUNCTION(__aeabi_fcmp ## cond) \ + push { r4, lr } SEPARATOR \ + bl SYMBOL_NAME(__ ## cond ## sf2) SEPARATOR \ + cmp r0, #0 SEPARATOR \ + b ## cond 1f SEPARATOR \ + mov r0, #0 SEPARATOR \ + pop { r4, pc } SEPARATOR \ +1: SEPARATOR \ + mov r0, #1 SEPARATOR \ + pop { r4, pc } SEPARATOR \ +END_COMPILERRT_FUNCTION(__aeabi_fcmp ## cond) + +DEFINE_AEABI_FCMP(eq) +DEFINE_AEABI_FCMP(lt) +DEFINE_AEABI_FCMP(le) +DEFINE_AEABI_FCMP(ge) +DEFINE_AEABI_FCMP(gt) diff --git a/lib/builtins/arm/aeabi_idivmod.S b/lib/builtins/arm/aeabi_idivmod.S new file mode 100644 index 000000000..ac5dfcc22 --- /dev/null +++ b/lib/builtins/arm/aeabi_idivmod.S @@ -0,0 +1,28 @@ +//===-- aeabi_idivmod.S - EABI idivmod implementation ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// struct { int quot, int rem} __aeabi_idivmod(int numerator, int denominator) { +// int rem, quot; +// quot = __divmodsi4(numerator, denominator, &rem); +// return {quot, rem}; +// } + + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__aeabi_idivmod) + push { lr } + sub sp, sp, #4 + mov r2, sp + bl SYMBOL_NAME(__divmodsi4) + ldr r1, [sp] + add sp, sp, #4 + pop { pc } +END_COMPILERRT_FUNCTION(__aeabi_idivmod) diff --git a/lib/builtins/arm/aeabi_ldivmod.S b/lib/builtins/arm/aeabi_ldivmod.S new file mode 100644 index 000000000..684252571 --- /dev/null +++ b/lib/builtins/arm/aeabi_ldivmod.S @@ -0,0 +1,31 @@ +//===-- aeabi_ldivmod.S - EABI ldivmod implementation ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// struct { int64_t quot, int64_t rem} +// __aeabi_ldivmod(int64_t numerator, int64_t denominator) { +// int64_t rem, quot; +// quot = __divmoddi4(numerator, denominator, &rem); +// return {quot, rem}; +// } + + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__aeabi_ldivmod) + push {r11, lr} + sub sp, sp, #16 + add r12, sp, #8 + str r12, [sp] + bl SYMBOL_NAME(__divmoddi4) + ldr r2, [sp, #8] + ldr r3, [sp, #12] + add sp, sp, #16 + pop {r11, pc} +END_COMPILERRT_FUNCTION(__aeabi_ldivmod) diff --git a/lib/builtins/arm/aeabi_memcmp.S b/lib/builtins/arm/aeabi_memcmp.S new file mode 100644 index 000000000..fc20825f4 --- /dev/null +++ b/lib/builtins/arm/aeabi_memcmp.S @@ -0,0 +1,20 @@ +//===-- aeabi_memcmp.S - EABI memcmp implementation -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// void __aeabi_memcmp(void *dest, void *src, size_t n) { memcmp(dest, src, n); } + + .align 2 +DEFINE_COMPILERRT_FUNCTION(__aeabi_memcmp) + b memcmp +END_COMPILERRT_FUNCTION(__aeabi_memcmp) + +DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcmp4, __aeabi_memcmp) +DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcmp8, __aeabi_memcmp) diff --git a/lib/builtins/arm/aeabi_memcpy.S b/lib/builtins/arm/aeabi_memcpy.S new file mode 100644 index 000000000..f6184632e --- /dev/null +++ b/lib/builtins/arm/aeabi_memcpy.S @@ -0,0 +1,20 @@ +//===-- aeabi_memcpy.S - EABI memcpy implementation -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// void __aeabi_memcpy(void *dest, void *src, size_t n) { memcpy(dest, src, n); } + + .align 2 +DEFINE_COMPILERRT_FUNCTION(__aeabi_memcpy) + b memcpy +END_COMPILERRT_FUNCTION(__aeabi_memcpy) + +DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcpy4, __aeabi_memcpy) +DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcpy8, __aeabi_memcpy) diff --git a/lib/builtins/arm/aeabi_memmove.S b/lib/builtins/arm/aeabi_memmove.S new file mode 100644 index 000000000..f3d6b0e1a --- /dev/null +++ b/lib/builtins/arm/aeabi_memmove.S @@ -0,0 +1,20 @@ +//===-- aeabi_memmove.S - EABI memmove implementation --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#include "../assembly.h" + +// void __aeabi_memmove(void *dest, void *src, size_t n) { memmove(dest, src, n); } + + .align 2 +DEFINE_COMPILERRT_FUNCTION(__aeabi_memmove) + b memmove +END_COMPILERRT_FUNCTION(__aeabi_memmove) + +DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memmove4, __aeabi_memmove) +DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memmove8, __aeabi_memmove) diff --git a/lib/builtins/arm/aeabi_memset.S b/lib/builtins/arm/aeabi_memset.S new file mode 100644 index 000000000..43c085e26 --- /dev/null +++ b/lib/builtins/arm/aeabi_memset.S @@ -0,0 +1,34 @@ +//===-- aeabi_memset.S - EABI memset implementation -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// void __aeabi_memset(void *dest, size_t n, int c) { memset(dest, c, n); } +// void __aeabi_memclr(void *dest, size_t n) { __aeabi_memset(dest, n, 0); } + + .align 2 +DEFINE_COMPILERRT_FUNCTION(__aeabi_memset) + mov r3, r1 + mov r1, r2 + mov r2, r3 + b memset +END_COMPILERRT_FUNCTION(__aeabi_memset) + +DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memset4, __aeabi_memset) +DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memset8, __aeabi_memset) + +DEFINE_COMPILERRT_FUNCTION(__aeabi_memclr) + mov r2, r1 + mov r1, #0 + b memset +END_COMPILERRT_FUNCTION(__aeabi_memclr) + +DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memclr4, __aeabi_memclr) +DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memclr8, __aeabi_memclr) + diff --git a/lib/builtins/arm/aeabi_uidivmod.S b/lib/builtins/arm/aeabi_uidivmod.S new file mode 100644 index 000000000..4c1e818cb --- /dev/null +++ b/lib/builtins/arm/aeabi_uidivmod.S @@ -0,0 +1,29 @@ +//===-- aeabi_uidivmod.S - EABI uidivmod implementation -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// struct { unsigned quot, unsigned rem} +// __aeabi_uidivmod(unsigned numerator, unsigned denominator) { +// unsigned rem, quot; +// quot = __udivmodsi4(numerator, denominator, &rem); +// return {quot, rem}; +// } + + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__aeabi_uidivmod) + push { lr } + sub sp, sp, #4 + mov r2, sp + bl SYMBOL_NAME(__udivmodsi4) + ldr r1, [sp] + add sp, sp, #4 + pop { pc } +END_COMPILERRT_FUNCTION(__aeabi_uidivmod) diff --git a/lib/builtins/arm/aeabi_uldivmod.S b/lib/builtins/arm/aeabi_uldivmod.S new file mode 100644 index 000000000..62a2113cc --- /dev/null +++ b/lib/builtins/arm/aeabi_uldivmod.S @@ -0,0 +1,31 @@ +//===-- aeabi_uldivmod.S - EABI uldivmod implementation -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// struct { uint64_t quot, uint64_t rem} +// __aeabi_uldivmod(uint64_t numerator, uint64_t denominator) { +// uint64_t rem, quot; +// quot = __udivmoddi4(numerator, denominator, &rem); +// return {quot, rem}; +// } + + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__aeabi_uldivmod) + push {r11, lr} + sub sp, sp, #16 + add r12, sp, #8 + str r12, [sp] + bl SYMBOL_NAME(__udivmoddi4) + ldr r2, [sp, #8] + ldr r3, [sp, #12] + add sp, sp, #16 + pop {r11, pc} +END_COMPILERRT_FUNCTION(__aeabi_uldivmod) diff --git a/lib/builtins/arm/bswapdi2.S b/lib/builtins/arm/bswapdi2.S new file mode 100644 index 000000000..c6e1b79c6 --- /dev/null +++ b/lib/builtins/arm/bswapdi2.S @@ -0,0 +1,37 @@ +//===------- bswapdi2 - Implement bswapdi2 --------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern uint64_t __bswapdi2(uint64_t); +// +// Reverse all the bytes in a 64-bit integer. +// +.align 2 +DEFINE_COMPILERRT_FUNCTION(__bswapdi2) +#if __ARM_ARCH < 6 + // before armv6 does not have "rev" instruction + // r2 = rev(r0) + eor r2, r0, r0, ror #16 + bic r2, r2, #0xff0000 + mov r2, r2, lsr #8 + eor r2, r2, r0, ror #8 + // r0 = rev(r1) + eor r0, r1, r1, ror #16 + bic r0, r0, #0xff0000 + mov r0, r0, lsr #8 + eor r0, r0, r1, ror #8 +#else + rev r2, r0 // r2 = rev(r0) + rev r0, r1 // r0 = rev(r1) +#endif + mov r1, r2 // r1 = r2 = rev(r0) + JMP(lr) +END_COMPILERRT_FUNCTION(__bswapdi2) diff --git a/lib/builtins/arm/bswapsi2.S b/lib/builtins/arm/bswapsi2.S new file mode 100644 index 000000000..5842da263 --- /dev/null +++ b/lib/builtins/arm/bswapsi2.S @@ -0,0 +1,29 @@ +//===------- bswapsi2 - Implement bswapsi2 --------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern uint32_t __bswapsi2(uint32_t); +// +// Reverse all the bytes in a 32-bit integer. +// +.align 2 +DEFINE_COMPILERRT_FUNCTION(__bswapsi2) +#if __ARM_ARCH < 6 + // before armv6 does not have "rev" instruction + eor r1, r0, r0, ror #16 + bic r1, r1, #0xff0000 + mov r1, r1, lsr #8 + eor r0, r1, r0, ror #8 +#else + rev r0, r0 +#endif + JMP(lr) +END_COMPILERRT_FUNCTION(__bswapsi2) diff --git a/lib/builtins/arm/clzdi2.S b/lib/builtins/arm/clzdi2.S new file mode 100644 index 000000000..33284cd3a --- /dev/null +++ b/lib/builtins/arm/clzdi2.S @@ -0,0 +1,89 @@ +/* ===-- clzdi2.c - Implement __clzdi2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements count leading zeros for 64bit arguments. + * + * ===----------------------------------------------------------------------=== + */ +#include "../assembly.h" + + .syntax unified + + .text + .align 2 +DEFINE_COMPILERRT_FUNCTION(__clzdi2) +#ifdef __ARM_FEATURE_CLZ +#ifdef __ARMEB__ + cmp r0, 0 + itee ne + clzne r0, r0 + clzeq r0, r1 + addeq r0, r0, 32 +#else + cmp r1, 0 + itee ne + clzne r0, r1 + clzeq r0, r0 + addeq r0, r0, 32 +#endif + JMP(lr) +#else + /* Assumption: n != 0 */ + + /* + * r0: n + * r1: upper half of n, overwritten after check + * r1: count of leading zeros in n + 1 + * r2: scratch register for shifted r0 + */ +#ifdef __ARMEB__ + cmp r0, 0 + moveq r0, r1 +#else + cmp r1, 0 + movne r0, r1 +#endif + movne r1, 1 + moveq r1, 33 + + /* + * Basic block: + * if ((r0 >> SHIFT) == 0) + * r1 += SHIFT; + * else + * r0 >>= SHIFT; + * for descending powers of two as SHIFT. + */ +#define BLOCK(shift) \ + lsrs r2, r0, shift; \ + movne r0, r2; \ + addeq r1, shift \ + + BLOCK(16) + BLOCK(8) + BLOCK(4) + BLOCK(2) + + /* + * The basic block invariants at this point are (r0 >> 2) == 0 and + * r0 != 0. This means 1 <= r0 <= 3 and 0 <= (r0 >> 1) <= 1. + * + * r0 | (r0 >> 1) == 0 | (r0 >> 1) == 1 | -(r0 >> 1) | 1 - (r0 >> 1) + * ---+----------------+----------------+------------+-------------- + * 1 | 1 | 0 | 0 | 1 + * 2 | 0 | 1 | -1 | 0 + * 3 | 0 | 1 | -1 | 0 + * + * The r1's initial value of 1 compensates for the 1 here. + */ + sub r0, r1, r0, lsr #1 + + JMP(lr) +#endif // __ARM_FEATURE_CLZ +END_COMPILERRT_FUNCTION(__clzdi2) diff --git a/lib/builtins/arm/clzsi2.S b/lib/builtins/arm/clzsi2.S new file mode 100644 index 000000000..8081d3284 --- /dev/null +++ b/lib/builtins/arm/clzsi2.S @@ -0,0 +1,69 @@ +/* ===-- clzsi2.c - Implement __clzsi2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements count leading zeros for 32bit arguments. + * + * ===----------------------------------------------------------------------=== + */ +#include "../assembly.h" + + .syntax unified + + .text + .align 2 +DEFINE_COMPILERRT_FUNCTION(__clzsi2) +#ifdef __ARM_FEATURE_CLZ + clz r0, r0 + JMP(lr) +#else + /* Assumption: n != 0 */ + + /* + * r0: n + * r1: count of leading zeros in n + 1 + * r2: scratch register for shifted r0 + */ + mov r1, 1 + + /* + * Basic block: + * if ((r0 >> SHIFT) == 0) + * r1 += SHIFT; + * else + * r0 >>= SHIFT; + * for descending powers of two as SHIFT. + */ + +#define BLOCK(shift) \ + lsrs r2, r0, shift; \ + movne r0, r2; \ + addeq r1, shift \ + + BLOCK(16) + BLOCK(8) + BLOCK(4) + BLOCK(2) + + /* + * The basic block invariants at this point are (r0 >> 2) == 0 and + * r0 != 0. This means 1 <= r0 <= 3 and 0 <= (r0 >> 1) <= 1. + * + * r0 | (r0 >> 1) == 0 | (r0 >> 1) == 1 | -(r0 >> 1) | 1 - (r0 >> 1) + * ---+----------------+----------------+------------+-------------- + * 1 | 1 | 0 | 0 | 1 + * 2 | 0 | 1 | -1 | 0 + * 3 | 0 | 1 | -1 | 0 + * + * The r1's initial value of 1 compensates for the 1 here. + */ + sub r0, r1, r0, lsr #1 + + JMP(lr) +#endif // __ARM_FEATURE_CLZ +END_COMPILERRT_FUNCTION(__clzsi2) diff --git a/lib/builtins/arm/comparesf2.S b/lib/builtins/arm/comparesf2.S new file mode 100644 index 000000000..ad1b10a7f --- /dev/null +++ b/lib/builtins/arm/comparesf2.S @@ -0,0 +1,148 @@ +//===-- comparesf2.S - Implement single-precision soft-float comparisons --===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the following soft-fp_t comparison routines: +// +// __eqsf2 __gesf2 __unordsf2 +// __lesf2 __gtsf2 +// __ltsf2 +// __nesf2 +// +// The semantics of the routines grouped in each column are identical, so there +// is a single implementation for each, with multiple names. +// +// The routines behave as follows: +// +// __lesf2(a,b) returns -1 if a < b +// 0 if a == b +// 1 if a > b +// 1 if either a or b is NaN +// +// __gesf2(a,b) returns -1 if a < b +// 0 if a == b +// 1 if a > b +// -1 if either a or b is NaN +// +// __unordsf2(a,b) returns 0 if both a and b are numbers +// 1 if either a or b is NaN +// +// Note that __lesf2( ) and __gesf2( ) are identical except in their handling of +// NaN values. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" +.syntax unified + +.align 2 +DEFINE_COMPILERRT_FUNCTION(__eqsf2) + // Make copies of a and b with the sign bit shifted off the top. These will + // be used to detect zeros and NaNs. + mov r2, r0, lsl #1 + mov r3, r1, lsl #1 + + // We do the comparison in three stages (ignoring NaN values for the time + // being). First, we orr the absolute values of a and b; this sets the Z + // flag if both a and b are zero (of either sign). The shift of r3 doesn't + // effect this at all, but it *does* make sure that the C flag is clear for + // the subsequent operations. + orrs r12, r2, r3, lsr #1 + + // Next, we check if a and b have the same or different signs. If they have + // opposite signs, this eor will set the N flag. + it ne + eorsne r12, r0, r1 + + // If a and b are equal (either both zeros or bit identical; again, we're + // ignoring NaNs for now), this subtract will zero out r0. If they have the + // same sign, the flags are updated as they would be for a comparison of the + // absolute values of a and b. + it pl + subspl r0, r2, r3 + + // If a is smaller in magnitude than b and both have the same sign, place + // the negation of the sign of b in r0. Thus, if both are negative and + // a > b, this sets r0 to 0; if both are positive and a < b, this sets + // r0 to -1. + // + // This is also done if a and b have opposite signs and are not both zero, + // because in that case the subtract was not performed and the C flag is + // still clear from the shift argument in orrs; if a is positive and b + // negative, this places 0 in r0; if a is negative and b positive, -1 is + // placed in r0. + it lo + mvnlo r0, r1, asr #31 + + // If a is greater in magnitude than b and both have the same sign, place + // the sign of b in r0. Thus, if both are negative and a < b, -1 is placed + // in r0, which is the desired result. Conversely, if both are positive + // and a > b, zero is placed in r0. + it hi + movhi r0, r1, asr #31 + + // If you've been keeping track, at this point r0 contains -1 if a < b and + // 0 if a >= b. All that remains to be done is to set it to 1 if a > b. + // If a == b, then the Z flag is set, so we can get the correct final value + // into r0 by simply or'ing with 1 if Z is clear. + it ne + orrne r0, r0, #1 + + // Finally, we need to deal with NaNs. If either argument is NaN, replace + // the value in r0 with 1. + cmp r2, #0xff000000 + ite ls + cmpls r3, #0xff000000 + movhi r0, #1 + JMP(lr) +END_COMPILERRT_FUNCTION(__eqsf2) +DEFINE_COMPILERRT_FUNCTION_ALIAS(__lesf2, __eqsf2) +DEFINE_COMPILERRT_FUNCTION_ALIAS(__ltsf2, __eqsf2) +DEFINE_COMPILERRT_FUNCTION_ALIAS(__nesf2, __eqsf2) + +.align 2 +DEFINE_COMPILERRT_FUNCTION(__gtsf2) + // Identical to the preceeding except in that we return -1 for NaN values. + // Given that the two paths share so much code, one might be tempted to + // unify them; however, the extra code needed to do so makes the code size + // to performance tradeoff very hard to justify for such small functions. + mov r2, r0, lsl #1 + mov r3, r1, lsl #1 + orrs r12, r2, r3, lsr #1 + it ne + eorsne r12, r0, r1 + it pl + subspl r0, r2, r3 + it lo + mvnlo r0, r1, asr #31 + it hi + movhi r0, r1, asr #31 + it ne + orrne r0, r0, #1 + cmp r2, #0xff000000 + ite ls + cmpls r3, #0xff000000 + movhi r0, #-1 + JMP(lr) +END_COMPILERRT_FUNCTION(__gtsf2) +DEFINE_COMPILERRT_FUNCTION_ALIAS(__gesf2, __gtsf2) + +.align 2 +DEFINE_COMPILERRT_FUNCTION(__unordsf2) + // Return 1 for NaN values, 0 otherwise. + mov r2, r0, lsl #1 + mov r3, r1, lsl #1 + mov r0, #0 + cmp r2, #0xff000000 + ite ls + cmpls r3, #0xff000000 + movhi r0, #1 + JMP(lr) +END_COMPILERRT_FUNCTION(__unordsf2) + +DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_fcmpun, __unordsf2) diff --git a/lib/builtins/arm/divdf3vfp.S b/lib/builtins/arm/divdf3vfp.S new file mode 100644 index 000000000..ec2f99721 --- /dev/null +++ b/lib/builtins/arm/divdf3vfp.S @@ -0,0 +1,26 @@ +//===-- divdf3vfp.S - Implement divdf3vfp ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern double __divdf3vfp(double a, double b); +// +// Divides two double precision floating point numbers using the Darwin +// calling convention where double arguments are passsed in GPR pairs +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__divdf3vfp) + vmov d6, r0, r1 // move first param from r0/r1 pair into d6 + vmov d7, r2, r3 // move second param from r2/r3 pair into d7 + vdiv.f64 d5, d6, d7 + vmov r0, r1, d5 // move result back to r0/r1 pair + bx lr +END_COMPILERRT_FUNCTION(__divdf3vfp) diff --git a/lib/builtins/arm/divmodsi4.S b/lib/builtins/arm/divmodsi4.S new file mode 100644 index 000000000..24e3657dd --- /dev/null +++ b/lib/builtins/arm/divmodsi4.S @@ -0,0 +1,61 @@ +/*===-- divmodsi4.S - 32-bit signed integer divide and modulus ------------===// + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + *===----------------------------------------------------------------------===// + * + * This file implements the __divmodsi4 (32-bit signed integer divide and + * modulus) function for the ARM architecture. A naive digit-by-digit + * computation is employed for simplicity. + * + *===----------------------------------------------------------------------===*/ + +#include "../assembly.h" + +#define ESTABLISH_FRAME \ + push {r4-r7, lr} ;\ + add r7, sp, #12 +#define CLEAR_FRAME_AND_RETURN \ + pop {r4-r7, pc} + +.syntax unified +.align 3 +DEFINE_COMPILERRT_FUNCTION(__divmodsi4) +#if __ARM_ARCH_EXT_IDIV__ + tst r1, r1 + beq LOCAL_LABEL(divzero) + mov r3, r0 + sdiv r0, r3, r1 + mls r1, r0, r1, r3 + str r1, [r2] + bx lr +LOCAL_LABEL(divzero): + mov r0, #0 + bx lr +#else + ESTABLISH_FRAME +// Set aside the sign of the quotient and modulus, and the address for the +// modulus. + eor r4, r0, r1 + mov r5, r0 + mov r6, r2 +// Take the absolute value of a and b via abs(x) = (x^(x >> 31)) - (x >> 31). + eor ip, r0, r0, asr #31 + eor lr, r1, r1, asr #31 + sub r0, ip, r0, asr #31 + sub r1, lr, r1, asr #31 +// Unsigned divmod: + bl SYMBOL_NAME(__udivmodsi4) +// Apply the sign of quotient and modulus + ldr r1, [r6] + eor r0, r0, r4, asr #31 + eor r1, r1, r5, asr #31 + sub r0, r0, r4, asr #31 + sub r1, r1, r5, asr #31 + str r1, [r6] + CLEAR_FRAME_AND_RETURN +#endif +END_COMPILERRT_FUNCTION(__divmodsi4) diff --git a/lib/builtins/arm/divsf3vfp.S b/lib/builtins/arm/divsf3vfp.S new file mode 100644 index 000000000..a4e2f8148 --- /dev/null +++ b/lib/builtins/arm/divsf3vfp.S @@ -0,0 +1,26 @@ +//===-- divsf3vfp.S - Implement divsf3vfp ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern float __divsf3vfp(float a, float b); +// +// Divides two single precision floating point numbers using the Darwin +// calling convention where single arguments are passsed like 32-bit ints. +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__divsf3vfp) + vmov s14, r0 // move first param from r0 into float register + vmov s15, r1 // move second param from r1 into float register + vdiv.f32 s13, s14, s15 + vmov r0, s13 // move result back to r0 + bx lr +END_COMPILERRT_FUNCTION(__divsf3vfp) diff --git a/lib/builtins/arm/divsi3.S b/lib/builtins/arm/divsi3.S new file mode 100644 index 000000000..76b679352 --- /dev/null +++ b/lib/builtins/arm/divsi3.S @@ -0,0 +1,52 @@ +/*===-- divsi3.S - 32-bit signed integer divide ---------------------------===// + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + *===----------------------------------------------------------------------===// + * + * This file implements the __divsi3 (32-bit signed integer divide) function + * for the ARM architecture as a wrapper around the unsigned routine. + * + *===----------------------------------------------------------------------===*/ + +#include "../assembly.h" + +#define ESTABLISH_FRAME \ + push {r4, r7, lr} ;\ + add r7, sp, #4 +#define CLEAR_FRAME_AND_RETURN \ + pop {r4, r7, pc} + +.syntax unified +.align 3 +// Ok, APCS and AAPCS agree on 32 bit args, so it's safe to use the same routine. +DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_idiv, __divsi3) +DEFINE_COMPILERRT_FUNCTION(__divsi3) +#if __ARM_ARCH_EXT_IDIV__ + tst r1,r1 + beq LOCAL_LABEL(divzero) + sdiv r0, r0, r1 + bx lr +LOCAL_LABEL(divzero): + mov r0,#0 + bx lr +#else +ESTABLISH_FRAME +// Set aside the sign of the quotient. + eor r4, r0, r1 +// Take absolute value of a and b via abs(x) = (x^(x >> 31)) - (x >> 31). + eor r2, r0, r0, asr #31 + eor r3, r1, r1, asr #31 + sub r0, r2, r0, asr #31 + sub r1, r3, r1, asr #31 +// abs(a) / abs(b) + bl SYMBOL_NAME(__udivsi3) +// Apply sign of quotient to result and return. + eor r0, r0, r4, asr #31 + sub r0, r0, r4, asr #31 + CLEAR_FRAME_AND_RETURN +#endif +END_COMPILERRT_FUNCTION(__divsi3) diff --git a/lib/builtins/arm/eqdf2vfp.S b/lib/builtins/arm/eqdf2vfp.S new file mode 100644 index 000000000..198d42278 --- /dev/null +++ b/lib/builtins/arm/eqdf2vfp.S @@ -0,0 +1,29 @@ +//===-- eqdf2vfp.S - Implement eqdf2vfp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern int __eqdf2vfp(double a, double b); +// +// Returns one iff a == b and neither is NaN. +// Uses Darwin calling convention where double precision arguments are passsed +// like in GPR pairs. +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__eqdf2vfp) + vmov d6, r0, r1 // load r0/r1 pair in double register + vmov d7, r2, r3 // load r2/r3 pair in double register + vcmp.f64 d6, d7 + vmrs apsr_nzcv, fpscr + moveq r0, #1 // set result register to 1 if equal + movne r0, #0 + bx lr +END_COMPILERRT_FUNCTION(__eqdf2vfp) diff --git a/lib/builtins/arm/eqsf2vfp.S b/lib/builtins/arm/eqsf2vfp.S new file mode 100644 index 000000000..395187f47 --- /dev/null +++ b/lib/builtins/arm/eqsf2vfp.S @@ -0,0 +1,29 @@ +//===-- eqsf2vfp.S - Implement eqsf2vfp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern int __eqsf2vfp(float a, float b); +// +// Returns one iff a == b and neither is NaN. +// Uses Darwin calling convention where single precision arguments are passsed +// like 32-bit ints +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__eqsf2vfp) + vmov s14, r0 // move from GPR 0 to float register + vmov s15, r1 // move from GPR 1 to float register + vcmp.f32 s14, s15 + vmrs apsr_nzcv, fpscr + moveq r0, #1 // set result register to 1 if equal + movne r0, #0 + bx lr +END_COMPILERRT_FUNCTION(__eqsf2vfp) diff --git a/lib/builtins/arm/extendsfdf2vfp.S b/lib/builtins/arm/extendsfdf2vfp.S new file mode 100644 index 000000000..ba31f3e0c --- /dev/null +++ b/lib/builtins/arm/extendsfdf2vfp.S @@ -0,0 +1,26 @@ +//===-- extendsfdf2vfp.S - Implement extendsfdf2vfp -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern double __extendsfdf2vfp(float a); +// +// Converts single precision float to double precision result. +// Uses Darwin calling convention where a single precision parameter is +// passed in a GPR and a double precision result is returned in R0/R1 pair. +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__extendsfdf2vfp) + vmov s15, r0 // load float register from R0 + vcvt.f64.f32 d7, s15 // convert single to double + vmov r0, r1, d7 // return result in r0/r1 pair + bx lr +END_COMPILERRT_FUNCTION(__extendsfdf2vfp) diff --git a/lib/builtins/arm/fixdfsivfp.S b/lib/builtins/arm/fixdfsivfp.S new file mode 100644 index 000000000..26adbe389 --- /dev/null +++ b/lib/builtins/arm/fixdfsivfp.S @@ -0,0 +1,26 @@ +//===-- fixdfsivfp.S - Implement fixdfsivfp -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern int __fixdfsivfp(double a); +// +// Converts double precision float to a 32-bit int rounding towards zero. +// Uses Darwin calling convention where a double precision parameter is +// passed in GPR register pair. +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__fixdfsivfp) + vmov d7, r0, r1 // load double register from R0/R1 + vcvt.s32.f64 s15, d7 // convert double to 32-bit int into s15 + vmov r0, s15 // move s15 to result register + bx lr +END_COMPILERRT_FUNCTION(__fixdfsivfp) diff --git a/lib/builtins/arm/fixsfsivfp.S b/lib/builtins/arm/fixsfsivfp.S new file mode 100644 index 000000000..c1e0dadb7 --- /dev/null +++ b/lib/builtins/arm/fixsfsivfp.S @@ -0,0 +1,26 @@ +//===-- fixsfsivfp.S - Implement fixsfsivfp -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern int __fixsfsivfp(float a); +// +// Converts single precision float to a 32-bit int rounding towards zero. +// Uses Darwin calling convention where a single precision parameter is +// passed in a GPR.. +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__fixsfsivfp) + vmov s15, r0 // load float register from R0 + vcvt.s32.f32 s15, s15 // convert single to 32-bit int into s15 + vmov r0, s15 // move s15 to result register + bx lr +END_COMPILERRT_FUNCTION(__fixsfsivfp) diff --git a/lib/builtins/arm/fixunsdfsivfp.S b/lib/builtins/arm/fixunsdfsivfp.S new file mode 100644 index 000000000..fb91da752 --- /dev/null +++ b/lib/builtins/arm/fixunsdfsivfp.S @@ -0,0 +1,27 @@ +//===-- fixunsdfsivfp.S - Implement fixunsdfsivfp -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern unsigned int __fixunsdfsivfp(double a); +// +// Converts double precision float to a 32-bit unsigned int rounding towards +// zero. All negative values become zero. +// Uses Darwin calling convention where a double precision parameter is +// passed in GPR register pair. +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__fixunsdfsivfp) + vmov d7, r0, r1 // load double register from R0/R1 + vcvt.u32.f64 s15, d7 // convert double to 32-bit int into s15 + vmov r0, s15 // move s15 to result register + bx lr +END_COMPILERRT_FUNCTION(__fixunsdfsivfp) diff --git a/lib/builtins/arm/fixunssfsivfp.S b/lib/builtins/arm/fixunssfsivfp.S new file mode 100644 index 000000000..f12dff61a --- /dev/null +++ b/lib/builtins/arm/fixunssfsivfp.S @@ -0,0 +1,27 @@ +//===-- fixunssfsivfp.S - Implement fixunssfsivfp -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern unsigned int __fixunssfsivfp(float a); +// +// Converts single precision float to a 32-bit unsigned int rounding towards +// zero. All negative values become zero. +// Uses Darwin calling convention where a single precision parameter is +// passed in a GPR.. +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__fixunssfsivfp) + vmov s15, r0 // load float register from R0 + vcvt.u32.f32 s15, s15 // convert single to 32-bit unsigned into s15 + vmov r0, s15 // move s15 to result register + bx lr +END_COMPILERRT_FUNCTION(__fixunssfsivfp) diff --git a/lib/builtins/arm/floatsidfvfp.S b/lib/builtins/arm/floatsidfvfp.S new file mode 100644 index 000000000..ab48933b9 --- /dev/null +++ b/lib/builtins/arm/floatsidfvfp.S @@ -0,0 +1,26 @@ +//===-- floatsidfvfp.S - Implement floatsidfvfp ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern double __floatsidfvfp(int a); +// +// Converts a 32-bit int to a double precision float. +// Uses Darwin calling convention where a double precision result is +// return in GPR register pair. +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__floatsidfvfp) + vmov s15, r0 // move int to float register s15 + vcvt.f64.s32 d7, s15 // convert 32-bit int in s15 to double in d7 + vmov r0, r1, d7 // move d7 to result register pair r0/r1 + bx lr +END_COMPILERRT_FUNCTION(__floatsidfvfp) diff --git a/lib/builtins/arm/floatsisfvfp.S b/lib/builtins/arm/floatsisfvfp.S new file mode 100644 index 000000000..eb265e990 --- /dev/null +++ b/lib/builtins/arm/floatsisfvfp.S @@ -0,0 +1,26 @@ +//===-- floatsisfvfp.S - Implement floatsisfvfp ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern float __floatsisfvfp(int a); +// +// Converts single precision float to a 32-bit int rounding towards zero. +// Uses Darwin calling convention where a single precision result is +// return in a GPR.. +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__floatsisfvfp) + vmov s15, r0 // move int to float register s15 + vcvt.f32.s32 s15, s15 // convert 32-bit int in s15 to float in s15 + vmov r0, s15 // move s15 to result register + bx lr +END_COMPILERRT_FUNCTION(__floatsisfvfp) diff --git a/lib/builtins/arm/floatunssidfvfp.S b/lib/builtins/arm/floatunssidfvfp.S new file mode 100644 index 000000000..96e2eb21e --- /dev/null +++ b/lib/builtins/arm/floatunssidfvfp.S @@ -0,0 +1,26 @@ +//===-- floatunssidfvfp.S - Implement floatunssidfvfp ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern double __floatunssidfvfp(unsigned int a); +// +// Converts a 32-bit int to a double precision float. +// Uses Darwin calling convention where a double precision result is +// return in GPR register pair. +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__floatunssidfvfp) + vmov s15, r0 // move int to float register s15 + vcvt.f64.u32 d7, s15 // convert 32-bit int in s15 to double in d7 + vmov r0, r1, d7 // move d7 to result register pair r0/r1 + bx lr +END_COMPILERRT_FUNCTION(__floatunssidfvfp) diff --git a/lib/builtins/arm/floatunssisfvfp.S b/lib/builtins/arm/floatunssisfvfp.S new file mode 100644 index 000000000..05471c4a5 --- /dev/null +++ b/lib/builtins/arm/floatunssisfvfp.S @@ -0,0 +1,26 @@ +//===-- floatunssisfvfp.S - Implement floatunssisfvfp ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern float __floatunssisfvfp(unsigned int a); +// +// Converts single precision float to a 32-bit int rounding towards zero. +// Uses Darwin calling convention where a single precision result is +// return in a GPR.. +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__floatunssisfvfp) + vmov s15, r0 // move int to float register s15 + vcvt.f32.u32 s15, s15 // convert 32-bit int in s15 to float in s15 + vmov r0, s15 // move s15 to result register + bx lr +END_COMPILERRT_FUNCTION(__floatunssisfvfp) diff --git a/lib/builtins/arm/gedf2vfp.S b/lib/builtins/arm/gedf2vfp.S new file mode 100644 index 000000000..aa636aa14 --- /dev/null +++ b/lib/builtins/arm/gedf2vfp.S @@ -0,0 +1,29 @@ +//===-- gedf2vfp.S - Implement gedf2vfp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern int __gedf2vfp(double a, double b); +// +// Returns one iff a >= b and neither is NaN. +// Uses Darwin calling convention where double precision arguments are passsed +// like in GPR pairs. +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__gedf2vfp) + vmov d6, r0, r1 // load r0/r1 pair in double register + vmov d7, r2, r3 // load r2/r3 pair in double register + vcmp.f64 d6, d7 + vmrs apsr_nzcv, fpscr + movge r0, #1 // set result register to 1 if greater than or equal + movlt r0, #0 + bx lr +END_COMPILERRT_FUNCTION(__gedf2vfp) diff --git a/lib/builtins/arm/gesf2vfp.S b/lib/builtins/arm/gesf2vfp.S new file mode 100644 index 000000000..087ce15f1 --- /dev/null +++ b/lib/builtins/arm/gesf2vfp.S @@ -0,0 +1,29 @@ +//===-- gesf2vfp.S - Implement gesf2vfp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern int __gesf2vfp(float a, float b); +// +// Returns one iff a >= b and neither is NaN. +// Uses Darwin calling convention where single precision arguments are passsed +// like 32-bit ints +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__gesf2vfp) + vmov s14, r0 // move from GPR 0 to float register + vmov s15, r1 // move from GPR 1 to float register + vcmp.f32 s14, s15 + vmrs apsr_nzcv, fpscr + movge r0, #1 // set result register to 1 if greater than or equal + movlt r0, #0 + bx lr +END_COMPILERRT_FUNCTION(__gesf2vfp) diff --git a/lib/builtins/arm/gtdf2vfp.S b/lib/builtins/arm/gtdf2vfp.S new file mode 100644 index 000000000..230952a9f --- /dev/null +++ b/lib/builtins/arm/gtdf2vfp.S @@ -0,0 +1,29 @@ +//===-- gtdf2vfp.S - Implement gtdf2vfp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern double __gtdf2vfp(double a, double b); +// +// Returns one iff a > b and neither is NaN. +// Uses Darwin calling convention where double precision arguments are passsed +// like in GPR pairs. +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__gtdf2vfp) + vmov d6, r0, r1 // load r0/r1 pair in double register + vmov d7, r2, r3 // load r2/r3 pair in double register + vcmp.f64 d6, d7 + vmrs apsr_nzcv, fpscr + movgt r0, #1 // set result register to 1 if equal + movle r0, #0 + bx lr +END_COMPILERRT_FUNCTION(__gtdf2vfp) diff --git a/lib/builtins/arm/gtsf2vfp.S b/lib/builtins/arm/gtsf2vfp.S new file mode 100644 index 000000000..c1f5db053 --- /dev/null +++ b/lib/builtins/arm/gtsf2vfp.S @@ -0,0 +1,29 @@ +//===-- gtsf2vfp.S - Implement gtsf2vfp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern int __gtsf2vfp(float a, float b); +// +// Returns one iff a > b and neither is NaN. +// Uses Darwin calling convention where single precision arguments are passsed +// like 32-bit ints +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__gtsf2vfp) + vmov s14, r0 // move from GPR 0 to float register + vmov s15, r1 // move from GPR 1 to float register + vcmp.f32 s14, s15 + vmrs apsr_nzcv, fpscr + movgt r0, #1 // set result register to 1 if equal + movle r0, #0 + bx lr +END_COMPILERRT_FUNCTION(__gtsf2vfp) diff --git a/lib/builtins/arm/ledf2vfp.S b/lib/builtins/arm/ledf2vfp.S new file mode 100644 index 000000000..94980a2ef --- /dev/null +++ b/lib/builtins/arm/ledf2vfp.S @@ -0,0 +1,29 @@ +//===-- ledf2vfp.S - Implement ledf2vfp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern double __ledf2vfp(double a, double b); +// +// Returns one iff a <= b and neither is NaN. +// Uses Darwin calling convention where double precision arguments are passsed +// like in GPR pairs. +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__ledf2vfp) + vmov d6, r0, r1 // load r0/r1 pair in double register + vmov d7, r2, r3 // load r2/r3 pair in double register + vcmp.f64 d6, d7 + vmrs apsr_nzcv, fpscr + movls r0, #1 // set result register to 1 if equal + movhi r0, #0 + bx lr +END_COMPILERRT_FUNCTION(__ledf2vfp) diff --git a/lib/builtins/arm/lesf2vfp.S b/lib/builtins/arm/lesf2vfp.S new file mode 100644 index 000000000..362352a83 --- /dev/null +++ b/lib/builtins/arm/lesf2vfp.S @@ -0,0 +1,29 @@ +//===-- lesf2vfp.S - Implement lesf2vfp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern int __lesf2vfp(float a, float b); +// +// Returns one iff a <= b and neither is NaN. +// Uses Darwin calling convention where single precision arguments are passsed +// like 32-bit ints +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__lesf2vfp) + vmov s14, r0 // move from GPR 0 to float register + vmov s15, r1 // move from GPR 1 to float register + vcmp.f32 s14, s15 + vmrs apsr_nzcv, fpscr + movls r0, #1 // set result register to 1 if equal + movhi r0, #0 + bx lr +END_COMPILERRT_FUNCTION(__lesf2vfp) diff --git a/lib/builtins/arm/ltdf2vfp.S b/lib/builtins/arm/ltdf2vfp.S new file mode 100644 index 000000000..391ff2924 --- /dev/null +++ b/lib/builtins/arm/ltdf2vfp.S @@ -0,0 +1,29 @@ +//===-- ltdf2vfp.S - Implement ltdf2vfp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern double __ltdf2vfp(double a, double b); +// +// Returns one iff a < b and neither is NaN. +// Uses Darwin calling convention where double precision arguments are passsed +// like in GPR pairs. +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__ltdf2vfp) + vmov d6, r0, r1 // load r0/r1 pair in double register + vmov d7, r2, r3 // load r2/r3 pair in double register + vcmp.f64 d6, d7 + vmrs apsr_nzcv, fpscr + movmi r0, #1 // set result register to 1 if equal + movpl r0, #0 + bx lr +END_COMPILERRT_FUNCTION(__ltdf2vfp) diff --git a/lib/builtins/arm/ltsf2vfp.S b/lib/builtins/arm/ltsf2vfp.S new file mode 100644 index 000000000..dcaa03561 --- /dev/null +++ b/lib/builtins/arm/ltsf2vfp.S @@ -0,0 +1,29 @@ +//===-- ltsf2vfp.S - Implement ltsf2vfp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern int __ltsf2vfp(float a, float b); +// +// Returns one iff a < b and neither is NaN. +// Uses Darwin calling convention where single precision arguments are passsed +// like 32-bit ints +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__ltsf2vfp) + vmov s14, r0 // move from GPR 0 to float register + vmov s15, r1 // move from GPR 1 to float register + vcmp.f32 s14, s15 + vmrs apsr_nzcv, fpscr + movmi r0, #1 // set result register to 1 if equal + movpl r0, #0 + bx lr +END_COMPILERRT_FUNCTION(__ltsf2vfp) diff --git a/lib/builtins/arm/modsi3.S b/lib/builtins/arm/modsi3.S new file mode 100644 index 000000000..07c5f9381 --- /dev/null +++ b/lib/builtins/arm/modsi3.S @@ -0,0 +1,51 @@ +/*===-- modsi3.S - 32-bit signed integer modulus --------------------------===// + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + *===----------------------------------------------------------------------===// + * + * This file implements the __modsi3 (32-bit signed integer modulus) function + * for the ARM architecture as a wrapper around the unsigned routine. + * + *===----------------------------------------------------------------------===*/ + +#include "../assembly.h" + +#define ESTABLISH_FRAME \ + push {r4, r7, lr} ;\ + add r7, sp, #4 +#define CLEAR_FRAME_AND_RETURN \ + pop {r4, r7, pc} + +.syntax unified +.align 3 +DEFINE_COMPILERRT_FUNCTION(__modsi3) +#if __ARM_ARCH_EXT_IDIV__ + tst r1, r1 + beq LOCAL_LABEL(divzero) + sdiv r2, r0, r1 + mls r0, r2, r1, r0 + bx lr +LOCAL_LABEL(divzero): + mov r0, #0 + bx lr +#else + ESTABLISH_FRAME + // Set aside the sign of the dividend. + mov r4, r0 + // Take absolute value of a and b via abs(x) = (x^(x >> 31)) - (x >> 31). + eor r2, r0, r0, asr #31 + eor r3, r1, r1, asr #31 + sub r0, r2, r0, asr #31 + sub r1, r3, r1, asr #31 + // abs(a) % abs(b) + bl SYMBOL_NAME(__umodsi3) + // Apply sign of dividend to result and return. + eor r0, r0, r4, asr #31 + sub r0, r0, r4, asr #31 + CLEAR_FRAME_AND_RETURN +#endif +END_COMPILERRT_FUNCTION(__modsi3) diff --git a/lib/builtins/arm/muldf3vfp.S b/lib/builtins/arm/muldf3vfp.S new file mode 100644 index 000000000..2c1d70377 --- /dev/null +++ b/lib/builtins/arm/muldf3vfp.S @@ -0,0 +1,26 @@ +//===-- muldf3vfp.S - Implement muldf3vfp ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern double __muldf3vfp(double a, double b); +// +// Multiplies two double precision floating point numbers using the Darwin +// calling convention where double arguments are passsed in GPR pairs +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__muldf3vfp) + vmov d6, r0, r1 // move first param from r0/r1 pair into d6 + vmov d7, r2, r3 // move second param from r2/r3 pair into d7 + vmul.f64 d6, d6, d7 + vmov r0, r1, d6 // move result back to r0/r1 pair + bx lr +END_COMPILERRT_FUNCTION(__muldf3vfp) diff --git a/lib/builtins/arm/mulsf3vfp.S b/lib/builtins/arm/mulsf3vfp.S new file mode 100644 index 000000000..98af81d23 --- /dev/null +++ b/lib/builtins/arm/mulsf3vfp.S @@ -0,0 +1,26 @@ +//===-- mulsf3vfp.S - Implement mulsf3vfp ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern float __mulsf3vfp(float a, float b); +// +// Multiplies two single precision floating point numbers using the Darwin +// calling convention where single arguments are passsed like 32-bit ints. +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__mulsf3vfp) + vmov s14, r0 // move first param from r0 into float register + vmov s15, r1 // move second param from r1 into float register + vmul.f32 s13, s14, s15 + vmov r0, s13 // move result back to r0 + bx lr +END_COMPILERRT_FUNCTION(__mulsf3vfp) diff --git a/lib/builtins/arm/nedf2vfp.S b/lib/builtins/arm/nedf2vfp.S new file mode 100644 index 000000000..c1a832e1a --- /dev/null +++ b/lib/builtins/arm/nedf2vfp.S @@ -0,0 +1,29 @@ +//===-- nedf2vfp.S - Implement nedf2vfp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern double __nedf2vfp(double a, double b); +// +// Returns zero if a and b are unequal and neither is NaN. +// Uses Darwin calling convention where double precision arguments are passsed +// like in GPR pairs. +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__nedf2vfp) + vmov d6, r0, r1 // load r0/r1 pair in double register + vmov d7, r2, r3 // load r2/r3 pair in double register + vcmp.f64 d6, d7 + vmrs apsr_nzcv, fpscr + movne r0, #1 // set result register to 0 if unequal + moveq r0, #0 + bx lr +END_COMPILERRT_FUNCTION(__nedf2vfp) diff --git a/lib/builtins/arm/negdf2vfp.S b/lib/builtins/arm/negdf2vfp.S new file mode 100644 index 000000000..ad9b87418 --- /dev/null +++ b/lib/builtins/arm/negdf2vfp.S @@ -0,0 +1,23 @@ +//===-- negdf2vfp.S - Implement negdf2vfp ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern double __negdf2vfp(double a, double b); +// +// Returns the negation a double precision floating point numbers using the +// Darwin calling convention where double arguments are passsed in GPR pairs. +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__negdf2vfp) + eor r1, r1, #-2147483648 // flip sign bit on double in r0/r1 pair + bx lr +END_COMPILERRT_FUNCTION(__negdf2vfp) diff --git a/lib/builtins/arm/negsf2vfp.S b/lib/builtins/arm/negsf2vfp.S new file mode 100644 index 000000000..482eb2640 --- /dev/null +++ b/lib/builtins/arm/negsf2vfp.S @@ -0,0 +1,23 @@ +//===-- negsf2vfp.S - Implement negsf2vfp ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern float __negsf2vfp(float a); +// +// Returns the negation of a single precision floating point numbers using the +// Darwin calling convention where single arguments are passsed like 32-bit ints +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__negsf2vfp) + eor r0, r0, #-2147483648 // flip sign bit on float in r0 + bx lr +END_COMPILERRT_FUNCTION(__negsf2vfp) diff --git a/lib/builtins/arm/nesf2vfp.S b/lib/builtins/arm/nesf2vfp.S new file mode 100644 index 000000000..127145ec4 --- /dev/null +++ b/lib/builtins/arm/nesf2vfp.S @@ -0,0 +1,29 @@ +//===-- nesf2vfp.S - Implement nesf2vfp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern int __nesf2vfp(float a, float b); +// +// Returns one iff a != b and neither is NaN. +// Uses Darwin calling convention where single precision arguments are passsed +// like 32-bit ints +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__nesf2vfp) + vmov s14, r0 // move from GPR 0 to float register + vmov s15, r1 // move from GPR 1 to float register + vcmp.f32 s14, s15 + vmrs apsr_nzcv, fpscr + movne r0, #1 // set result register to 1 if unequal + moveq r0, #0 + bx lr +END_COMPILERRT_FUNCTION(__nesf2vfp) diff --git a/lib/builtins/arm/restore_vfp_d8_d15_regs.S b/lib/builtins/arm/restore_vfp_d8_d15_regs.S new file mode 100644 index 000000000..5d5547415 --- /dev/null +++ b/lib/builtins/arm/restore_vfp_d8_d15_regs.S @@ -0,0 +1,35 @@ +//===-- save_restore_regs.S - Implement save/restore* ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// When compiling C++ functions that need to handle thrown exceptions the +// compiler is required to save all registers and call __Unwind_SjLj_Register +// in the function prolog. But when compiling for thumb1, there are +// no instructions to access the floating point registers, so the +// compiler needs to add a call to the helper function _save_vfp_d8_d15_regs +// written in ARM to save the float registers. In the epilog, the compiler +// must also add a call to __restore_vfp_d8_d15_regs to restore those registers. +// + + .text + .syntax unified + +// +// Restore registers d8-d15 from stack +// + .align 2 +DEFINE_COMPILERRT_PRIVATE_FUNCTION(__restore_vfp_d8_d15_regs) + vldmia sp!, {d8-d15} // pop registers d8-d15 off stack + bx lr // return to prolog +END_COMPILERRT_FUNCTION(__restore_vfp_d8_d15_regs) + + // tell linker it can break up file at label boundaries + .subsections_via_symbols diff --git a/lib/builtins/arm/save_vfp_d8_d15_regs.S b/lib/builtins/arm/save_vfp_d8_d15_regs.S new file mode 100644 index 000000000..4be3ff3a5 --- /dev/null +++ b/lib/builtins/arm/save_vfp_d8_d15_regs.S @@ -0,0 +1,35 @@ +//===-- save_restore_regs.S - Implement save/restore* ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// When compiling C++ functions that need to handle thrown exceptions the +// compiler is required to save all registers and call __Unwind_SjLj_Register +// in the function prolog. But when compiling for thumb1, there are +// no instructions to access the floating point registers, so the +// compiler needs to add a call to the helper function _save_vfp_d8_d15_regs +// written in ARM to save the float registers. In the epilog, the compiler +// must also add a call to __restore_vfp_d8_d15_regs to restore those registers. +// + + .text + .syntax unified + +// +// Save registers d8-d15 onto stack +// + .align 2 +DEFINE_COMPILERRT_PRIVATE_FUNCTION(__save_vfp_d8_d15_regs) + vstmdb sp!, {d8-d15} // push registers d8-d15 onto stack + bx lr // return to prolog +END_COMPILERRT_FUNCTION(__save_vfp_d8_d15_regs) + + // tell linker it can break up file at label boundaries + .subsections_via_symbols diff --git a/lib/builtins/arm/softfloat-alias.list b/lib/builtins/arm/softfloat-alias.list new file mode 100644 index 000000000..cc6a4b3cd --- /dev/null +++ b/lib/builtins/arm/softfloat-alias.list @@ -0,0 +1,21 @@ +# +# These are soft float functions which can be +# aliased to the *vfp functions on arm processors +# that support floating point instructions. +# +___adddf3vfp ___adddf3 +___addsf3vfp ___addsf3 +___divdf3vfp ___divdf3 +___divsf3vfp ___divsf3 +___extendsfdf2vfp ___extendsfdf2 +___fixdfsivfp ___fixdfsi +___fixsfsivfp ___fixsfsi +___floatsidfvfp ___floatsidf +___floatsisfvfp ___floatsisf +___muldf3vfp ___muldf3 +___mulsf3vfp ___mulsf3 +___subdf3vfp ___subdf3 +___subsf3vfp ___subsf3 +___truncdfsf2vfp ___truncdfsf2 +___floatunssidfvfp ___floatunsidf +___floatunssisfvfp ___floatunsisf diff --git a/lib/builtins/arm/subdf3vfp.S b/lib/builtins/arm/subdf3vfp.S new file mode 100644 index 000000000..747d6596c --- /dev/null +++ b/lib/builtins/arm/subdf3vfp.S @@ -0,0 +1,26 @@ +//===-- subdf3vfp.S - Implement subdf3vfp ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern double __subdf3vfp(double a, double b); +// +// Returns difference between two double precision floating point numbers using +// the Darwin calling convention where double arguments are passsed in GPR pairs +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__subdf3vfp) + vmov d6, r0, r1 // move first param from r0/r1 pair into d6 + vmov d7, r2, r3 // move second param from r2/r3 pair into d7 + vsub.f64 d6, d6, d7 + vmov r0, r1, d6 // move result back to r0/r1 pair + bx lr +END_COMPILERRT_FUNCTION(__subdf3vfp) diff --git a/lib/builtins/arm/subsf3vfp.S b/lib/builtins/arm/subsf3vfp.S new file mode 100644 index 000000000..7cc63cccc --- /dev/null +++ b/lib/builtins/arm/subsf3vfp.S @@ -0,0 +1,27 @@ +//===-- subsf3vfp.S - Implement subsf3vfp ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern float __subsf3vfp(float a, float b); +// +// Returns the difference between two single precision floating point numbers +// using the Darwin calling convention where single arguments are passsed +// like 32-bit ints. +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__subsf3vfp) + vmov s14, r0 // move first param from r0 into float register + vmov s15, r1 // move second param from r1 into float register + vsub.f32 s14, s14, s15 + vmov r0, s14 // move result back to r0 + bx lr +END_COMPILERRT_FUNCTION(__subsf3vfp) diff --git a/lib/builtins/arm/switch16.S b/lib/builtins/arm/switch16.S new file mode 100644 index 000000000..0dedc598a --- /dev/null +++ b/lib/builtins/arm/switch16.S @@ -0,0 +1,46 @@ +//===-- switch.S - Implement switch* --------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// When compiling switch statements in thumb mode, the compiler +// can use these __switch* helper functions The compiler emits a blx to +// the __switch* function followed by a table of displacements for each +// case statement. On entry, R0 is the index into the table. The __switch* +// function uses the return address in lr to find the start of the table. +// The first entry in the table is the count of the entries in the table. +// It then uses R0 to index into the table and get the displacement of the +// address to jump to. If R0 is greater than the size of the table, it jumps +// to the last entry in the table. Each displacement in the table is actually +// the distance from lr to the label, thus making the tables PIC. + + + .text + .syntax unified + +// +// The table contains signed 2-byte sized elements which are 1/2 the distance +// from lr to the target label. +// + .align 2 +DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch16) + ldrh ip, [lr, #-1] // get first 16-bit word in table + cmp r0, ip // compare with index + add r0, lr, r0, lsl #1 // compute address of element in table + add ip, lr, ip, lsl #1 // compute address of last element in table + ite lo + ldrshlo r0, [r0, #1] // load 16-bit element if r0 is in range + ldrshhs r0, [ip, #1] // load 16-bit element if r0 out of range + add ip, lr, r0, lsl #1 // compute label = lr + element*2 + bx ip // jump to computed label +END_COMPILERRT_FUNCTION(__switch16) + + // tell linker it can break up file at label boundaries + .subsections_via_symbols diff --git a/lib/builtins/arm/switch32.S b/lib/builtins/arm/switch32.S new file mode 100644 index 000000000..64d558eb8 --- /dev/null +++ b/lib/builtins/arm/switch32.S @@ -0,0 +1,47 @@ +//===-- switch.S - Implement switch* --------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// When compiling switch statements in thumb mode, the compiler +// can use these __switch* helper functions The compiler emits a blx to +// the __switch* function followed by a table of displacements for each +// case statement. On entry, R0 is the index into the table. The __switch* +// function uses the return address in lr to find the start of the table. +// The first entry in the table is the count of the entries in the table. +// It then uses R0 to index into the table and get the displacement of the +// address to jump to. If R0 is greater than the size of the table, it jumps +// to the last entry in the table. Each displacement in the table is actually +// the distance from lr to the label, thus making the tables PIC. + + + .text + .syntax unified + +// +// The table contains signed 4-byte sized elements which are the distance +// from lr to the target label. +// + .align 2 +DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch32) + ldr ip, [lr, #-1] // get first 32-bit word in table + cmp r0, ip // compare with index + add r0, lr, r0, lsl #2 // compute address of element in table + add ip, lr, ip, lsl #2 // compute address of last element in table + ite lo + ldrlo r0, [r0, #3] // load 32-bit element if r0 is in range + ldrhs r0, [ip, #3] // load 32-bit element if r0 out of range + add ip, lr, r0 // compute label = lr + element + bx ip // jump to computed label +END_COMPILERRT_FUNCTION(__switch32) + + // tell linker it can break up file at label boundaries + .subsections_via_symbols + diff --git a/lib/builtins/arm/switch8.S b/lib/builtins/arm/switch8.S new file mode 100644 index 000000000..b5008849a --- /dev/null +++ b/lib/builtins/arm/switch8.S @@ -0,0 +1,45 @@ +//===-- switch.S - Implement switch* --------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// When compiling switch statements in thumb mode, the compiler +// can use these __switch* helper functions The compiler emits a blx to +// the __switch* function followed by a table of displacements for each +// case statement. On entry, R0 is the index into the table. The __switch* +// function uses the return address in lr to find the start of the table. +// The first entry in the table is the count of the entries in the table. +// It then uses R0 to index into the table and get the displacement of the +// address to jump to. If R0 is greater than the size of the table, it jumps +// to the last entry in the table. Each displacement in the table is actually +// the distance from lr to the label, thus making the tables PIC. + + + .text + .syntax unified + +// +// The table contains signed byte sized elements which are 1/2 the distance +// from lr to the target label. +// + .align 2 +DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch8) + ldrb ip, [lr, #-1] // get first byte in table + cmp r0, ip // signed compare with index + ite lo + ldrsblo r0, [lr, r0] // get indexed byte out of table + ldrsbhs r0, [lr, ip] // if out of range, use last entry in table + add ip, lr, r0, lsl #1 // compute label = lr + element*2 + bx ip // jump to computed label +END_COMPILERRT_FUNCTION(__switch8) + + // tell linker it can break up file at label boundaries + .subsections_via_symbols + diff --git a/lib/builtins/arm/switchu8.S b/lib/builtins/arm/switchu8.S new file mode 100644 index 000000000..488d4e74e --- /dev/null +++ b/lib/builtins/arm/switchu8.S @@ -0,0 +1,45 @@ +//===-- switch.S - Implement switch* --------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// When compiling switch statements in thumb mode, the compiler +// can use these __switch* helper functions The compiler emits a blx to +// the __switch* function followed by a table of displacements for each +// case statement. On entry, R0 is the index into the table. The __switch* +// function uses the return address in lr to find the start of the table. +// The first entry in the table is the count of the entries in the table. +// It then uses R0 to index into the table and get the displacement of the +// address to jump to. If R0 is greater than the size of the table, it jumps +// to the last entry in the table. Each displacement in the table is actually +// the distance from lr to the label, thus making the tables PIC. + + + .text + .syntax unified + +// +// The table contains unsigned byte sized elements which are 1/2 the distance +// from lr to the target label. +// + .align 2 +DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switchu8) + ldrb ip, [lr, #-1] // get first byte in table + cmp r0, ip // compare with index + ite lo + ldrblo r0, [lr, r0] // get indexed byte out of table + ldrbhs r0, [lr, ip] // if out of range, use last entry in table + add ip, lr, r0, lsl #1 // compute label = lr + element*2 + bx ip // jump to computed label +END_COMPILERRT_FUNCTION(__switchu8) + + // tell linker it can break up file at label boundaries + .subsections_via_symbols + diff --git a/lib/builtins/arm/sync_synchronize.S b/lib/builtins/arm/sync_synchronize.S new file mode 100644 index 000000000..aa18f04fb --- /dev/null +++ b/lib/builtins/arm/sync_synchronize.S @@ -0,0 +1,35 @@ +//===-- sync_synchronize - Implement memory barrier * ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// When compiling a use of the gcc built-in __sync_synchronize() in thumb1 mode +// the compiler may emit a call to __sync_synchronize. +// On Darwin the implementation jumps to an OS supplied function named +// OSMemoryBarrier +// + + .text + .syntax unified + +#if __APPLE__ + + .align 2 +DEFINE_COMPILERRT_PRIVATE_FUNCTION(__sync_synchronize) + stmfd sp!, {r7, lr} + add r7, sp, #0 + bl _OSMemoryBarrier + ldmfd sp!, {r7, pc} +END_COMPILERRT_FUNCTION(__sync_synchronize) + + // tell linker it can break up file at label boundaries + .subsections_via_symbols + +#endif diff --git a/lib/builtins/arm/truncdfsf2vfp.S b/lib/builtins/arm/truncdfsf2vfp.S new file mode 100644 index 000000000..55bf324cc --- /dev/null +++ b/lib/builtins/arm/truncdfsf2vfp.S @@ -0,0 +1,26 @@ +//===-- truncdfsf2vfp.S - Implement truncdfsf2vfp -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern float __truncdfsf2vfp(double a); +// +// Converts double precision float to signle precision result. +// Uses Darwin calling convention where a double precision parameter is +// passed in a R0/R1 pair and a signle precision result is returned in R0. +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__truncdfsf2vfp) + vmov d7, r0, r1 // load double from r0/r1 pair + vcvt.f32.f64 s15, d7 // convert double to single (trucate precision) + vmov r0, s15 // return result in r0 + bx lr +END_COMPILERRT_FUNCTION(__truncdfsf2vfp) diff --git a/lib/builtins/arm/udivmodsi4.S b/lib/builtins/arm/udivmodsi4.S new file mode 100644 index 000000000..bb5d29c03 --- /dev/null +++ b/lib/builtins/arm/udivmodsi4.S @@ -0,0 +1,161 @@ +/*===-- udivmodsi4.S - 32-bit unsigned integer divide and modulus ---------===// + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + *===----------------------------------------------------------------------===// + * + * This file implements the __udivmodsi4 (32-bit unsigned integer divide and + * modulus) function for the ARM 32-bit architecture. + * + *===----------------------------------------------------------------------===*/ + +#include "../assembly.h" + + .syntax unified + + .text + .p2align 2 +DEFINE_COMPILERRT_FUNCTION(__udivmodsi4) +#if __ARM_ARCH_EXT_IDIV__ + tst r1, r1 + beq LOCAL_LABEL(divby0) + mov r3, r0 + udiv r0, r3, r1 + mls r1, r0, r1, r3 + str r1, [r2] + bx lr +#else + cmp r1, #1 + bcc LOCAL_LABEL(divby0) + beq LOCAL_LABEL(divby1) + cmp r0, r1 + bcc LOCAL_LABEL(quotient0) + /* + * Implement division using binary long division algorithm. + * + * r0 is the numerator, r1 the denominator. + * + * The code before JMP computes the correct shift I, so that + * r0 and (r1 << I) have the highest bit set in the same position. + * At the time of JMP, ip := .Ldiv0block - 12 * I. + * This depends on the fixed instruction size of block. + * + * block(shift) implements the test-and-update-quotient core. + * It assumes (r0 << shift) can be computed without overflow and + * that (r0 << shift) < 2 * r1. The quotient is stored in r3. + */ + +# ifdef __ARM_FEATURE_CLZ + clz ip, r0 + clz r3, r1 + /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */ + sub r3, r3, ip + adr ip, LOCAL_LABEL(div0block) + sub ip, ip, r3, lsl #2 + sub ip, ip, r3, lsl #3 + mov r3, #0 + bx ip +# else + str r4, [sp, #-8]! + + mov r4, r0 + adr ip, LOCAL_LABEL(div0block) + + lsr r3, r4, #16 + cmp r3, r1 + movhs r4, r3 + subhs ip, ip, #(16 * 12) + + lsr r3, r4, #8 + cmp r3, r1 + movhs r4, r3 + subhs ip, ip, #(8 * 12) + + lsr r3, r4, #4 + cmp r3, r1 + movhs r4, r3 + subhs ip, #(4 * 12) + + lsr r3, r4, #2 + cmp r3, r1 + movhs r4, r3 + subhs ip, ip, #(2 * 12) + + /* Last block, no need to update r3 or r4. */ + cmp r1, r4, lsr #1 + subls ip, ip, #(1 * 12) + + ldr r4, [sp], #8 /* restore r4, we are done with it. */ + mov r3, #0 + + JMP(ip) +# endif + +#define IMM # + +#define block(shift) \ + cmp r0, r1, lsl IMM shift; \ + addhs r3, r3, IMM (1 << shift); \ + subhs r0, r0, r1, lsl IMM shift + + block(31) + block(30) + block(29) + block(28) + block(27) + block(26) + block(25) + block(24) + block(23) + block(22) + block(21) + block(20) + block(19) + block(18) + block(17) + block(16) + block(15) + block(14) + block(13) + block(12) + block(11) + block(10) + block(9) + block(8) + block(7) + block(6) + block(5) + block(4) + block(3) + block(2) + block(1) +LOCAL_LABEL(div0block): + block(0) + + str r0, [r2] + mov r0, r3 + JMP(lr) + +LOCAL_LABEL(quotient0): + str r0, [r2] + mov r0, #0 + JMP(lr) + +LOCAL_LABEL(divby1): + mov r3, #0 + str r3, [r2] + JMP(lr) +#endif /* __ARM_ARCH_EXT_IDIV__ */ + +LOCAL_LABEL(divby0): + mov r0, #0 +#ifdef __ARM_EABI__ + b __aeabi_idiv0 +#else + JMP(lr) +#endif + +END_COMPILERRT_FUNCTION(__udivmodsi4) diff --git a/lib/builtins/arm/udivsi3.S b/lib/builtins/arm/udivsi3.S new file mode 100644 index 000000000..11c1c096e --- /dev/null +++ b/lib/builtins/arm/udivsi3.S @@ -0,0 +1,148 @@ +/*===-- udivsi3.S - 32-bit unsigned integer divide ------------------------===// + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + *===----------------------------------------------------------------------===// + * + * This file implements the __udivsi3 (32-bit unsigned integer divide) + * function for the ARM 32-bit architecture. + * + *===----------------------------------------------------------------------===*/ + +#include "../assembly.h" + + .syntax unified + + .text + .p2align 2 +DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_uidiv, __udivsi3) +DEFINE_COMPILERRT_FUNCTION(__udivsi3) +#if __ARM_ARCH_EXT_IDIV__ + tst r1, r1 + beq LOCAL_LABEL(divby0) + mov r3, r0 + udiv r0, r3, r1 + mls r1, r0, r1, r3 + bx lr +#else + cmp r1, #1 + bcc LOCAL_LABEL(divby0) + JMPc(lr, eq) + cmp r0, r1 + movcc r0, #0 + JMPc(lr, cc) + /* + * Implement division using binary long division algorithm. + * + * r0 is the numerator, r1 the denominator. + * + * The code before JMP computes the correct shift I, so that + * r0 and (r1 << I) have the highest bit set in the same position. + * At the time of JMP, ip := .Ldiv0block - 12 * I. + * This depends on the fixed instruction size of block. + * + * block(shift) implements the test-and-update-quotient core. + * It assumes (r0 << shift) can be computed without overflow and + * that (r0 << shift) < 2 * r1. The quotient is stored in r3. + */ + +# ifdef __ARM_FEATURE_CLZ + clz ip, r0 + clz r3, r1 + /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */ + sub r3, r3, ip + adr ip, LOCAL_LABEL(div0block) + sub ip, ip, r3, lsl #2 + sub ip, ip, r3, lsl #3 + mov r3, #0 + bx ip +# else + mov r2, r0 + adr ip, LOCAL_LABEL(div0block) + + lsr r3, r2, #16 + cmp r3, r1 + movhs r2, r3 + subhs ip, ip, #(16 * 12) + + lsr r3, r2, #8 + cmp r3, r1 + movhs r2, r3 + subhs ip, ip, #(8 * 12) + + lsr r3, r2, #4 + cmp r3, r1 + movhs r2, r3 + subhs ip, #(4 * 12) + + lsr r3, r2, #2 + cmp r3, r1 + movhs r2, r3 + subhs ip, ip, #(2 * 12) + + /* Last block, no need to update r2 or r3. */ + cmp r1, r2, lsr #1 + subls ip, ip, #(1 * 12) + + mov r3, #0 + + JMP(ip) +# endif + +#define IMM # + +#define block(shift) \ + cmp r0, r1, lsl IMM shift; \ + addhs r3, r3, IMM (1 << shift); \ + subhs r0, r0, r1, lsl IMM shift + + block(31) + block(30) + block(29) + block(28) + block(27) + block(26) + block(25) + block(24) + block(23) + block(22) + block(21) + block(20) + block(19) + block(18) + block(17) + block(16) + block(15) + block(14) + block(13) + block(12) + block(11) + block(10) + block(9) + block(8) + block(7) + block(6) + block(5) + block(4) + block(3) + block(2) + block(1) +LOCAL_LABEL(div0block): + block(0) + + mov r0, r3 + JMP(lr) +#endif /* __ARM_ARCH_EXT_IDIV__ */ + +LOCAL_LABEL(divby0): + mov r0, #0 +#ifdef __ARM_EABI__ + b __aeabi_idiv0 +#else + JMP(lr) +#endif + +END_COMPILERRT_FUNCTION(__udivsi3) diff --git a/lib/builtins/arm/umodsi3.S b/lib/builtins/arm/umodsi3.S new file mode 100644 index 000000000..a03afefda --- /dev/null +++ b/lib/builtins/arm/umodsi3.S @@ -0,0 +1,141 @@ +/*===-- umodsi3.S - 32-bit unsigned integer modulus -----------------------===// + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + *===----------------------------------------------------------------------===// + * + * This file implements the __umodsi3 (32-bit unsigned integer modulus) + * function for the ARM 32-bit architecture. + * + *===----------------------------------------------------------------------===*/ + +#include "../assembly.h" + + .syntax unified + + .text + .p2align 2 +DEFINE_COMPILERRT_FUNCTION(__umodsi3) +#if __ARM_ARCH_EXT_IDIV__ + tst r1, r1 + beq LOCAL_LABEL(divby0) + mov r3, r0 + udiv r0, r3, r1 + mls r1, r0, r1, r3 + str r1, [r2] + bx lr +#else + cmp r1, #1 + bcc LOCAL_LABEL(divby0) + moveq r0, #0 + JMPc(lr, eq) + cmp r0, r1 + JMPc(lr, cc) + /* + * Implement division using binary long division algorithm. + * + * r0 is the numerator, r1 the denominator. + * + * The code before JMP computes the correct shift I, so that + * r0 and (r1 << I) have the highest bit set in the same position. + * At the time of JMP, ip := .Ldiv0block - 8 * I. + * This depends on the fixed instruction size of block. + * + * block(shift) implements the test-and-update-quotient core. + * It assumes (r0 << shift) can be computed without overflow and + * that (r0 << shift) < 2 * r1. The quotient is stored in r3. + */ + +# ifdef __ARM_FEATURE_CLZ + clz ip, r0 + clz r3, r1 + /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */ + sub r3, r3, ip + adr ip, LOCAL_LABEL(div0block) + sub ip, ip, r3, lsl #3 + bx ip +# else + mov r2, r0 + adr ip, LOCAL_LABEL(div0block) + + lsr r3, r2, #16 + cmp r3, r1 + movhs r2, r3 + subhs ip, ip, #(16 * 8) + + lsr r3, r2, #8 + cmp r3, r1 + movhs r2, r3 + subhs ip, ip, #(8 * 8) + + lsr r3, r2, #4 + cmp r3, r1 + movhs r2, r3 + subhs ip, #(4 * 8) + + lsr r3, r2, #2 + cmp r3, r1 + movhs r2, r3 + subhs ip, ip, #(2 * 8) + + /* Last block, no need to update r2 or r3. */ + cmp r1, r2, lsr #1 + subls ip, ip, #(1 * 8) + + JMP(ip) +# endif + +#define IMM # + +#define block(shift) \ + cmp r0, r1, lsl IMM shift; \ + subhs r0, r0, r1, lsl IMM shift + + block(31) + block(30) + block(29) + block(28) + block(27) + block(26) + block(25) + block(24) + block(23) + block(22) + block(21) + block(20) + block(19) + block(18) + block(17) + block(16) + block(15) + block(14) + block(13) + block(12) + block(11) + block(10) + block(9) + block(8) + block(7) + block(6) + block(5) + block(4) + block(3) + block(2) + block(1) +LOCAL_LABEL(div0block): + block(0) + JMP(lr) +#endif /* __ARM_ARCH_EXT_IDIV__ */ + +LOCAL_LABEL(divby0): + mov r0, #0 +#ifdef __ARM_EABI__ + b __aeabi_idiv0 +#else + JMP(lr) +#endif + +END_COMPILERRT_FUNCTION(__umodsi3) diff --git a/lib/builtins/arm/unorddf2vfp.S b/lib/builtins/arm/unorddf2vfp.S new file mode 100644 index 000000000..ee7de4025 --- /dev/null +++ b/lib/builtins/arm/unorddf2vfp.S @@ -0,0 +1,29 @@ +//===-- unorddf2vfp.S - Implement unorddf2vfp ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern int __unorddf2vfp(double a, double b); +// +// Returns one iff a or b is NaN +// Uses Darwin calling convention where double precision arguments are passsed +// like in GPR pairs. +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__unorddf2vfp) + vmov d6, r0, r1 // load r0/r1 pair in double register + vmov d7, r2, r3 // load r2/r3 pair in double register + vcmp.f64 d6, d7 + vmrs apsr_nzcv, fpscr + movvs r0, #1 // set result register to 1 if "overflow" (any NaNs) + movvc r0, #0 + bx lr +END_COMPILERRT_FUNCTION(__unorddf2vfp) diff --git a/lib/builtins/arm/unordsf2vfp.S b/lib/builtins/arm/unordsf2vfp.S new file mode 100644 index 000000000..eb419a541 --- /dev/null +++ b/lib/builtins/arm/unordsf2vfp.S @@ -0,0 +1,29 @@ +//===-- unordsf2vfp.S - Implement unordsf2vfp -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// extern int __unordsf2vfp(float a, float b); +// +// Returns one iff a or b is NaN +// Uses Darwin calling convention where single precision arguments are passsed +// like 32-bit ints +// + .syntax unified + .align 2 +DEFINE_COMPILERRT_FUNCTION(__unordsf2vfp) + vmov s14, r0 // move from GPR 0 to float register + vmov s15, r1 // move from GPR 1 to float register + vcmp.f32 s14, s15 + vmrs apsr_nzcv, fpscr + movvs r0, #1 // set result register to 1 if "overflow" (any NaNs) + movvc r0, #0 + bx lr +END_COMPILERRT_FUNCTION(__unordsf2vfp) diff --git a/lib/builtins/ashldi3.c b/lib/builtins/ashldi3.c new file mode 100644 index 000000000..eb4698ac5 --- /dev/null +++ b/lib/builtins/ashldi3.c @@ -0,0 +1,43 @@ +/* ====-- ashldi3.c - Implement __ashldi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __ashldi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: a << b */ + +/* Precondition: 0 <= b < bits_in_dword */ + +ARM_EABI_FNALIAS(llsl, ashldi3) + +COMPILER_RT_ABI di_int +__ashldi3(di_int a, si_int b) +{ + const int bits_in_word = (int)(sizeof(si_int) * CHAR_BIT); + dwords input; + dwords result; + input.all = a; + if (b & bits_in_word) /* bits_in_word <= b < bits_in_dword */ + { + result.s.low = 0; + result.s.high = input.s.low << (b - bits_in_word); + } + else /* 0 <= b < bits_in_word */ + { + if (b == 0) + return a; + result.s.low = input.s.low << b; + result.s.high = (input.s.high << b) | (input.s.low >> (bits_in_word - b)); + } + return result.all; +} diff --git a/lib/builtins/ashlti3.c b/lib/builtins/ashlti3.c new file mode 100644 index 000000000..4bd8219b5 --- /dev/null +++ b/lib/builtins/ashlti3.c @@ -0,0 +1,45 @@ +/* ===-- ashlti3.c - Implement __ashlti3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __ashlti3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: a << b */ + +/* Precondition: 0 <= b < bits_in_tword */ + +ti_int +__ashlti3(ti_int a, si_int b) +{ + const int bits_in_dword = (int)(sizeof(di_int) * CHAR_BIT); + twords input; + twords result; + input.all = a; + if (b & bits_in_dword) /* bits_in_dword <= b < bits_in_tword */ + { + result.s.low = 0; + result.s.high = input.s.low << (b - bits_in_dword); + } + else /* 0 <= b < bits_in_dword */ + { + if (b == 0) + return a; + result.s.low = input.s.low << b; + result.s.high = (input.s.high << b) | (input.s.low >> (bits_in_dword - b)); + } + return result.all; +} + +#endif /* __x86_64 */ diff --git a/lib/builtins/ashrdi3.c b/lib/builtins/ashrdi3.c new file mode 100644 index 000000000..14c878bb7 --- /dev/null +++ b/lib/builtins/ashrdi3.c @@ -0,0 +1,44 @@ +/*===-- ashrdi3.c - Implement __ashrdi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __ashrdi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: arithmetic a >> b */ + +/* Precondition: 0 <= b < bits_in_dword */ + +ARM_EABI_FNALIAS(lasr, ashrdi3) + +COMPILER_RT_ABI di_int +__ashrdi3(di_int a, si_int b) +{ + const int bits_in_word = (int)(sizeof(si_int) * CHAR_BIT); + dwords input; + dwords result; + input.all = a; + if (b & bits_in_word) /* bits_in_word <= b < bits_in_dword */ + { + /* result.s.high = input.s.high < 0 ? -1 : 0 */ + result.s.high = input.s.high >> (bits_in_word - 1); + result.s.low = input.s.high >> (b - bits_in_word); + } + else /* 0 <= b < bits_in_word */ + { + if (b == 0) + return a; + result.s.high = input.s.high >> b; + result.s.low = (input.s.high << (bits_in_word - b)) | (input.s.low >> b); + } + return result.all; +} diff --git a/lib/builtins/ashrti3.c b/lib/builtins/ashrti3.c new file mode 100644 index 000000000..ed43641c7 --- /dev/null +++ b/lib/builtins/ashrti3.c @@ -0,0 +1,46 @@ +/* ===-- ashrti3.c - Implement __ashrti3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __ashrti3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: arithmetic a >> b */ + +/* Precondition: 0 <= b < bits_in_tword */ + +ti_int +__ashrti3(ti_int a, si_int b) +{ + const int bits_in_dword = (int)(sizeof(di_int) * CHAR_BIT); + twords input; + twords result; + input.all = a; + if (b & bits_in_dword) /* bits_in_dword <= b < bits_in_tword */ + { + /* result.s.high = input.s.high < 0 ? -1 : 0 */ + result.s.high = input.s.high >> (bits_in_dword - 1); + result.s.low = input.s.high >> (b - bits_in_dword); + } + else /* 0 <= b < bits_in_dword */ + { + if (b == 0) + return a; + result.s.high = input.s.high >> b; + result.s.low = (input.s.high << (bits_in_dword - b)) | (input.s.low >> b); + } + return result.all; +} + +#endif /* __x86_64 */ diff --git a/lib/builtins/assembly.h b/lib/builtins/assembly.h new file mode 100644 index 000000000..1a9f79cb6 --- /dev/null +++ b/lib/builtins/assembly.h @@ -0,0 +1,136 @@ +/* ===-- assembly.h - compiler-rt assembler support macros -----------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file defines macros for use in compiler-rt assembler source. + * This file is not part of the interface of this library. + * + * ===----------------------------------------------------------------------=== + */ + +#ifndef COMPILERRT_ASSEMBLY_H +#define COMPILERRT_ASSEMBLY_H + +#if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__) +#define SEPARATOR @ +#else +#define SEPARATOR ; +#endif + +#if defined(__APPLE__) +#define HIDDEN_DIRECTIVE .private_extern +#define LOCAL_LABEL(name) L_##name +#define FILE_LEVEL_DIRECTIVE .subsections_via_symbols +#define SYMBOL_IS_FUNC(name) +#else +#define HIDDEN_DIRECTIVE .hidden +#define LOCAL_LABEL(name) .L_##name +#define FILE_LEVEL_DIRECTIVE +# if defined(__arm__) +# define SYMBOL_IS_FUNC(name) .type name, %function +# else +# define SYMBOL_IS_FUNC(name) .type name, @function +# endif +#endif + +#if defined(__arm__) +# ifndef __ARM_ARCH +# if defined (__ARM_ARCH_7__) || defined (__ARM_ARCH_7A__) || \ + defined (__ARM_ARCH_7R__) || defined (__ARM_ARCH_7M__) || \ + defined (__ARM_ARCH_7EM__) +# define __ARM_ARCH 7 +# endif +# endif + +# ifndef __ARM_ARCH +# if defined (__ARM_ARCH_6__) || \ + defined (__ARM_ARCH_6J__) || defined (__ARM_ARCH_6K__) || \ + defined (__ARM_ARCH_6Z__) || defined (__ARM_ARCH_6ZK__) || \ + defined (__ARM_ARCH_6ZM__) +# define __ARM_ARCH 6 +# endif +# endif + +# ifndef __ARM_ARCH +# if defined (__ARM_ARCH_5__) || defined (__ARM_ARCH_5T__) || \ + defined (__ARM_ARCH_5TE__) || defined (__ARM_ARCH_5TEJ__) +# define __ARM_ARCH 5 +# endif +# endif + +# ifndef __ARM_ARCH +# define __ARM_ARCH 4 +# endif + +# if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5 +# define ARM_HAS_BX +# endif +# if !defined(__ARM_FEATURE_CLZ) && \ + (__ARM_ARCH >= 6 || (__ARM_ARCH == 5 && !defined(__ARM_ARCH_5__))) +# define __ARM_FEATURE_CLZ +# endif + +# ifdef ARM_HAS_BX +# define JMP(r) bx r +# define JMPc(r,c) bx##c r +# else +# define JMP(r) mov pc, r +# define JMPc(r,c) mov##c pc, r +# endif +#endif + +#define GLUE2(a, b) a ## b +#define GLUE(a, b) GLUE2(a, b) +#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name) + +#ifdef VISIBILITY_HIDDEN +#define DECLARE_SYMBOL_VISIBILITY(name) \ + HIDDEN_DIRECTIVE SYMBOL_NAME(name) SEPARATOR +#else +#define DECLARE_SYMBOL_VISIBILITY(name) +#endif + +#define DEFINE_COMPILERRT_FUNCTION(name) \ + FILE_LEVEL_DIRECTIVE SEPARATOR \ + .globl SYMBOL_NAME(name) SEPARATOR \ + SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ + DECLARE_SYMBOL_VISIBILITY(name) \ + SYMBOL_NAME(name): + +#define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name) \ + .globl SYMBOL_NAME(name) SEPARATOR \ + SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ + HIDDEN_DIRECTIVE SYMBOL_NAME(name) SEPARATOR \ + SYMBOL_NAME(name): + +#define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \ + .globl name SEPARATOR \ + SYMBOL_IS_FUNC(name) SEPARATOR \ + HIDDEN_DIRECTIVE name SEPARATOR \ + name: + +#define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target) \ + .globl SYMBOL_NAME(name) SEPARATOR \ + SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ + .set SYMBOL_NAME(name), SYMBOL_NAME(target) SEPARATOR + +#if defined (__ARM_EABI__) +# define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name) \ + DEFINE_COMPILERRT_FUNCTION_ALIAS(aeabi_name, name) +#else +# define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name) +#endif + +#ifdef __ELF__ +#define END_COMPILERRT_FUNCTION(name) \ + .size SYMBOL_NAME(name), . - SYMBOL_NAME(name) +#else +#define END_COMPILERRT_FUNCTION(name) +#endif + +#endif /* COMPILERRT_ASSEMBLY_H */ diff --git a/lib/builtins/atomic.c b/lib/builtins/atomic.c new file mode 100644 index 000000000..02429a653 --- /dev/null +++ b/lib/builtins/atomic.c @@ -0,0 +1,337 @@ +/*===-- atomic.c - Implement support functions for atomic operations.------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + *===----------------------------------------------------------------------=== + * + * atomic.c defines a set of functions for performing atomic accesses on + * arbitrary-sized memory locations. This design uses locks that should + * be fast in the uncontended case, for two reasons: + * + * 1) This code must work with C programs that do not link to anything + * (including pthreads) and so it should not depend on any pthread + * functions. + * 2) Atomic operations, rather than explicit mutexes, are most commonly used + * on code where contended operations are rate. + * + * To avoid needing a per-object lock, this code allocates an array of + * locks and hashes the object pointers to find the one that it should use. + * For operations that must be atomic on two locations, the lower lock is + * always acquired first, to avoid deadlock. + * + *===----------------------------------------------------------------------=== + */ + +#include <stdint.h> +#include <string.h> + +// Clang objects if you redefine a builtin. This little hack allows us to +// define a function with the same name as an intrinsic. +#if __APPLE__ +// mach-o has extra leading underscore +#pragma redefine_extname __atomic_load_c ___atomic_load +#pragma redefine_extname __atomic_store_c ___atomic_store +#pragma redefine_extname __atomic_exchange_c ___atomic_exchange +#pragma redefine_extname __atomic_compare_exchange_c ___atomic_compare_exchange +#else +#pragma redefine_extname __atomic_load_c __atomic_load +#pragma redefine_extname __atomic_store_c __atomic_store +#pragma redefine_extname __atomic_exchange_c __atomic_exchange +#pragma redefine_extname __atomic_compare_exchange_c __atomic_compare_exchange +#endif + +/// Number of locks. This allocates one page on 32-bit platforms, two on +/// 64-bit. This can be specified externally if a different trade between +/// memory usage and contention probability is required for a given platform. +#ifndef SPINLOCK_COUNT +#define SPINLOCK_COUNT (1<<10) +#endif +static const long SPINLOCK_MASK = SPINLOCK_COUNT - 1; + +//////////////////////////////////////////////////////////////////////////////// +// Platform-specific lock implementation. Falls back to spinlocks if none is +// defined. Each platform should define the Lock type, and corresponding +// lock() and unlock() functions. +//////////////////////////////////////////////////////////////////////////////// +#ifdef __FreeBSD__ +#include <errno.h> +#include <sys/types.h> +#include <machine/atomic.h> +#include <sys/umtx.h> +typedef struct _usem Lock; +inline static void unlock(Lock *l) { + __c11_atomic_store((_Atomic(uint32_t)*)&l->_count, 1, __ATOMIC_RELEASE); + __c11_atomic_thread_fence(__ATOMIC_SEQ_CST); + if (l->_has_waiters) + _umtx_op(l, UMTX_OP_SEM_WAKE, 1, 0, 0); +} +inline static void lock(Lock *l) { + uint32_t old = 1; + while (!__c11_atomic_compare_exchange_weak((_Atomic(uint32_t)*)&l->_count, &old, + 0, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) { + _umtx_op(l, UMTX_OP_SEM_WAIT, 0, 0, 0); + old = 1; + } +} +/// locks for atomic operations +static Lock locks[SPINLOCK_COUNT] = { [0 ... SPINLOCK_COUNT-1] = {0,1,0} }; + +#elif defined(__APPLE__) +#include <libkern/OSAtomic.h> +typedef OSSpinLock Lock; +inline static void unlock(Lock *l) { + OSSpinLockUnlock(l); +} +/// Locks a lock. In the current implementation, this is potentially +/// unbounded in the contended case. +inline static void lock(Lock *l) { + OSSpinLockLock(l); +} +static Lock locks[SPINLOCK_COUNT]; // initialized to OS_SPINLOCK_INIT which is 0 + +#else +typedef _Atomic(uintptr_t) Lock; +/// Unlock a lock. This is a release operation. +inline static void unlock(Lock *l) { + __c11_atomic_store(l, 0, __ATOMIC_RELEASE); +} +/// Locks a lock. In the current implementation, this is potentially +/// unbounded in the contended case. +inline static void lock(Lock *l) { + uintptr_t old = 0; + while (!__c11_atomic_compare_exchange_weak(l, &old, 1, __ATOMIC_ACQUIRE, + __ATOMIC_RELAXED)) + old = 0; +} +/// locks for atomic operations +static Lock locks[SPINLOCK_COUNT]; +#endif + + +/// Returns a lock to use for a given pointer. +static inline Lock *lock_for_pointer(void *ptr) { + intptr_t hash = (intptr_t)ptr; + // Disregard the lowest 4 bits. We want all values that may be part of the + // same memory operation to hash to the same value and therefore use the same + // lock. + hash >>= 4; + // Use the next bits as the basis for the hash + intptr_t low = hash & SPINLOCK_MASK; + // Now use the high(er) set of bits to perturb the hash, so that we don't + // get collisions from atomic fields in a single object + hash >>= 16; + hash ^= low; + // Return a pointer to the word to use + return locks + (hash & SPINLOCK_MASK); +} + +/// Macros for determining whether a size is lock free. Clang can not yet +/// codegen __atomic_is_lock_free(16), so for now we assume 16-byte values are +/// not lock free. +#define IS_LOCK_FREE_1 __c11_atomic_is_lock_free(1) +#define IS_LOCK_FREE_2 __c11_atomic_is_lock_free(2) +#define IS_LOCK_FREE_4 __c11_atomic_is_lock_free(4) +#define IS_LOCK_FREE_8 __c11_atomic_is_lock_free(8) +#define IS_LOCK_FREE_16 0 + +/// Macro that calls the compiler-generated lock-free versions of functions +/// when they exist. +#define LOCK_FREE_CASES() \ + do {\ + switch (size) {\ + case 2:\ + if (IS_LOCK_FREE_2) {\ + LOCK_FREE_ACTION(uint16_t);\ + }\ + case 4:\ + if (IS_LOCK_FREE_4) {\ + LOCK_FREE_ACTION(uint32_t);\ + }\ + case 8:\ + if (IS_LOCK_FREE_8) {\ + LOCK_FREE_ACTION(uint64_t);\ + }\ + case 16:\ + if (IS_LOCK_FREE_16) {\ + /* FIXME: __uint128_t isn't available on 32 bit platforms. + LOCK_FREE_ACTION(__uint128_t);*/\ + }\ + }\ + } while (0) + + +/// An atomic load operation. This is atomic with respect to the source +/// pointer only. +void __atomic_load_c(int size, void *src, void *dest, int model) { +#define LOCK_FREE_ACTION(type) \ + *((type*)dest) = __c11_atomic_load((_Atomic(type)*)src, model);\ + return; + LOCK_FREE_CASES(); +#undef LOCK_FREE_ACTION + Lock *l = lock_for_pointer(src); + lock(l); + memcpy(dest, src, size); + unlock(l); +} + +/// An atomic store operation. This is atomic with respect to the destination +/// pointer only. +void __atomic_store_c(int size, void *dest, void *src, int model) { +#define LOCK_FREE_ACTION(type) \ + __c11_atomic_store((_Atomic(type)*)dest, *(type*)dest, model);\ + return; + LOCK_FREE_CASES(); +#undef LOCK_FREE_ACTION + Lock *l = lock_for_pointer(dest); + lock(l); + memcpy(dest, src, size); + unlock(l); +} + +/// Atomic compare and exchange operation. If the value at *ptr is identical +/// to the value at *expected, then this copies value at *desired to *ptr. If +/// they are not, then this stores the current value from *ptr in *expected. +/// +/// This function returns 1 if the exchange takes place or 0 if it fails. +int __atomic_compare_exchange_c(int size, void *ptr, void *expected, + void *desired, int success, int failure) { +#define LOCK_FREE_ACTION(type) \ + return __c11_atomic_compare_exchange_strong((_Atomic(type)*)ptr, (type*)expected,\ + *(type*)desired, success, failure) + LOCK_FREE_CASES(); +#undef LOCK_FREE_ACTION + Lock *l = lock_for_pointer(ptr); + lock(l); + if (memcmp(ptr, expected, size) == 0) { + memcpy(ptr, desired, size); + unlock(l); + return 1; + } + memcpy(expected, ptr, size); + unlock(l); + return 0; +} + +/// Performs an atomic exchange operation between two pointers. This is atomic +/// with respect to the target address. +void __atomic_exchange_c(int size, void *ptr, void *val, void *old, int model) { +#define LOCK_FREE_ACTION(type) \ + *(type*)old = __c11_atomic_exchange((_Atomic(type)*)ptr, *(type*)val,\ + model);\ + return; + LOCK_FREE_CASES(); +#undef LOCK_FREE_ACTION + Lock *l = lock_for_pointer(ptr); + lock(l); + memcpy(old, ptr, size); + memcpy(ptr, val, size); + unlock(l); +} + +//////////////////////////////////////////////////////////////////////////////// +// Where the size is known at compile time, the compiler may emit calls to +// specialised versions of the above functions. +//////////////////////////////////////////////////////////////////////////////// +#define OPTIMISED_CASES\ + OPTIMISED_CASE(1, IS_LOCK_FREE_1, uint8_t)\ + OPTIMISED_CASE(2, IS_LOCK_FREE_2, uint16_t)\ + OPTIMISED_CASE(4, IS_LOCK_FREE_4, uint32_t)\ + OPTIMISED_CASE(8, IS_LOCK_FREE_8, uint64_t)\ + /* FIXME: __uint128_t isn't available on 32 bit platforms. + OPTIMISED_CASE(16, IS_LOCK_FREE_16, __uint128_t)*/\ + +#define OPTIMISED_CASE(n, lockfree, type)\ +type __atomic_load_##n(type *src, int model) {\ + if (lockfree)\ + return __c11_atomic_load((_Atomic(type)*)src, model);\ + Lock *l = lock_for_pointer(src);\ + lock(l);\ + type val = *src;\ + unlock(l);\ + return val;\ +} +OPTIMISED_CASES +#undef OPTIMISED_CASE + +#define OPTIMISED_CASE(n, lockfree, type)\ +void __atomic_store_##n(type *dest, type val, int model) {\ + if (lockfree) {\ + __c11_atomic_store((_Atomic(type)*)dest, val, model);\ + return;\ + }\ + Lock *l = lock_for_pointer(dest);\ + lock(l);\ + *dest = val;\ + unlock(l);\ + return;\ +} +OPTIMISED_CASES +#undef OPTIMISED_CASE + +#define OPTIMISED_CASE(n, lockfree, type)\ +type __atomic_exchange_##n(type *dest, type val, int model) {\ + if (lockfree)\ + return __c11_atomic_exchange((_Atomic(type)*)dest, val, model);\ + Lock *l = lock_for_pointer(dest);\ + lock(l);\ + type tmp = *dest;\ + *dest = val;\ + unlock(l);\ + return tmp;\ +} +OPTIMISED_CASES +#undef OPTIMISED_CASE + +#define OPTIMISED_CASE(n, lockfree, type)\ +int __atomic_compare_exchange_##n(type *ptr, type *expected, type desired,\ + int success, int failure) {\ + if (lockfree)\ + return __c11_atomic_compare_exchange_strong((_Atomic(type)*)ptr, expected, desired,\ + success, failure);\ + Lock *l = lock_for_pointer(ptr);\ + lock(l);\ + if (*ptr == *expected) {\ + *ptr = desired;\ + unlock(l);\ + return 1;\ + }\ + *expected = *ptr;\ + unlock(l);\ + return 0;\ +} +OPTIMISED_CASES +#undef OPTIMISED_CASE + +//////////////////////////////////////////////////////////////////////////////// +// Atomic read-modify-write operations for integers of various sizes. +//////////////////////////////////////////////////////////////////////////////// +#define ATOMIC_RMW(n, lockfree, type, opname, op) \ +type __atomic_fetch_##opname##_##n(type *ptr, type val, int model) {\ + if (lockfree) \ + return __c11_atomic_fetch_##opname((_Atomic(type)*)ptr, val, model);\ + Lock *l = lock_for_pointer(ptr);\ + lock(l);\ + type tmp = *ptr;\ + *ptr = tmp op val;\ + unlock(l);\ + return tmp;\ +} + +#define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, add, +) +OPTIMISED_CASES +#undef OPTIMISED_CASE +#define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, sub, -) +OPTIMISED_CASES +#undef OPTIMISED_CASE +#define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, and, &) +OPTIMISED_CASES +#undef OPTIMISED_CASE +#define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, or, |) +OPTIMISED_CASES +#undef OPTIMISED_CASE +#define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, xor, ^) +OPTIMISED_CASES +#undef OPTIMISED_CASE diff --git a/lib/builtins/clear_cache.c b/lib/builtins/clear_cache.c new file mode 100644 index 000000000..7aee28590 --- /dev/null +++ b/lib/builtins/clear_cache.c @@ -0,0 +1,71 @@ +/* ===-- clear_cache.c - Implement __clear_cache ---------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __APPLE__ + #include <libkern/OSCacheControl.h> +#endif +#if defined(__NetBSD__) && defined(__arm__) + #include <machine/sysarch.h> +#endif + +/* + * The compiler generates calls to __clear_cache() when creating + * trampoline functions on the stack for use with nested functions. + * It is expected to invalidate the instruction cache for the + * specified range. + */ + +void __clear_cache(void* start, void* end) +{ +#if __i386__ || __x86_64__ +/* + * Intel processors have a unified instruction and data cache + * so there is nothing to do + */ +#elif defined(__NetBSD__) && defined(__arm__) + struct arm_sync_icache_args arg; + + arg.addr = (uintptr_t)start; + arg.len = (uintptr_t)end - (uintptr_t)start; + + sysarch(ARM_SYNC_ICACHE, &arg); +#elif defined(__aarch64__) && !defined(__APPLE__) + uint64_t xstart = (uint64_t)(uintptr_t) start; + uint64_t xend = (uint64_t)(uintptr_t) end; + + // Get Cache Type Info + uint64_t ctr_el0; + __asm __volatile("mrs %0, ctr_el0" : "=r"(ctr_el0)); + + /* + * dc & ic instructions must use 64bit registers so we don't use + * uintptr_t in case this runs in an IPL32 environment. + */ + const size_t dcache_line_size = 4 << ((ctr_el0 >> 16) & 15); + for (uint64_t addr = xstart; addr < xend; addr += dcache_line_size) + __asm __volatile("dc cvau, %0" :: "r"(addr)); + __asm __volatile("dsb ish"); + + const size_t icache_line_size = 4 << ((ctr_el0 >> 0) & 15); + for (uint64_t addr = xstart; addr < xend; addr += icache_line_size) + __asm __volatile("ic ivau, %0" :: "r"(addr)); + __asm __volatile("isb sy"); +#else + #if __APPLE__ + /* On Darwin, sys_icache_invalidate() provides this functionality */ + sys_icache_invalidate(start, end-start); + #else + compilerrt_abort(); + #endif +#endif +} + diff --git a/lib/builtins/clzdi2.c b/lib/builtins/clzdi2.c new file mode 100644 index 000000000..b9e64da49 --- /dev/null +++ b/lib/builtins/clzdi2.c @@ -0,0 +1,29 @@ +/* ===-- clzdi2.c - Implement __clzdi2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __clzdi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: the number of leading 0-bits */ + +/* Precondition: a != 0 */ + +COMPILER_RT_ABI si_int +__clzdi2(di_int a) +{ + dwords x; + x.all = a; + const si_int f = -(x.s.high == 0); + return __builtin_clz((x.s.high & ~f) | (x.s.low & f)) + + (f & ((si_int)(sizeof(si_int) * CHAR_BIT))); +} diff --git a/lib/builtins/clzsi2.c b/lib/builtins/clzsi2.c new file mode 100644 index 000000000..25b8ed2c4 --- /dev/null +++ b/lib/builtins/clzsi2.c @@ -0,0 +1,53 @@ +/* ===-- clzsi2.c - Implement __clzsi2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __clzsi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: the number of leading 0-bits */ + +/* Precondition: a != 0 */ + +COMPILER_RT_ABI si_int +__clzsi2(si_int a) +{ + su_int x = (su_int)a; + si_int t = ((x & 0xFFFF0000) == 0) << 4; /* if (x is small) t = 16 else 0 */ + x >>= 16 - t; /* x = [0 - 0xFFFF] */ + su_int r = t; /* r = [0, 16] */ + /* return r + clz(x) */ + t = ((x & 0xFF00) == 0) << 3; + x >>= 8 - t; /* x = [0 - 0xFF] */ + r += t; /* r = [0, 8, 16, 24] */ + /* return r + clz(x) */ + t = ((x & 0xF0) == 0) << 2; + x >>= 4 - t; /* x = [0 - 0xF] */ + r += t; /* r = [0, 4, 8, 12, 16, 20, 24, 28] */ + /* return r + clz(x) */ + t = ((x & 0xC) == 0) << 1; + x >>= 2 - t; /* x = [0 - 3] */ + r += t; /* r = [0 - 30] and is even */ + /* return r + clz(x) */ +/* switch (x) + * { + * case 0: + * return r + 2; + * case 1: + * return r + 1; + * case 2: + * case 3: + * return r; + * } + */ + return r + ((2 - x) & -((x & 2) == 0)); +} diff --git a/lib/builtins/clzti2.c b/lib/builtins/clzti2.c new file mode 100644 index 000000000..355c20e42 --- /dev/null +++ b/lib/builtins/clzti2.c @@ -0,0 +1,33 @@ +/* ===-- clzti2.c - Implement __clzti2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __clzti2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: the number of leading 0-bits */ + +/* Precondition: a != 0 */ + +si_int +__clzti2(ti_int a) +{ + twords x; + x.all = a; + const di_int f = -(x.s.high == 0); + return __builtin_clzll((x.s.high & ~f) | (x.s.low & f)) + + ((si_int)f & ((si_int)(sizeof(di_int) * CHAR_BIT))); +} + +#endif /* __x86_64 */ diff --git a/lib/builtins/cmpdi2.c b/lib/builtins/cmpdi2.c new file mode 100644 index 000000000..52634d9c3 --- /dev/null +++ b/lib/builtins/cmpdi2.c @@ -0,0 +1,51 @@ +/* ===-- cmpdi2.c - Implement __cmpdi2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __cmpdi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: if (a < b) returns 0 +* if (a == b) returns 1 +* if (a > b) returns 2 +*/ + +COMPILER_RT_ABI si_int +__cmpdi2(di_int a, di_int b) +{ + dwords x; + x.all = a; + dwords y; + y.all = b; + if (x.s.high < y.s.high) + return 0; + if (x.s.high > y.s.high) + return 2; + if (x.s.low < y.s.low) + return 0; + if (x.s.low > y.s.low) + return 2; + return 1; +} + +#ifdef __ARM_EABI__ +/* Returns: if (a < b) returns -1 +* if (a == b) returns 0 +* if (a > b) returns 1 +*/ +COMPILER_RT_ABI si_int +__aeabi_lcmp(di_int a, di_int b) +{ + return __cmpdi2(a, b) - 1; +} +#endif + diff --git a/lib/builtins/cmpti2.c b/lib/builtins/cmpti2.c new file mode 100644 index 000000000..d0aec452a --- /dev/null +++ b/lib/builtins/cmpti2.c @@ -0,0 +1,42 @@ +/* ===-- cmpti2.c - Implement __cmpti2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __cmpti2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: if (a < b) returns 0 + * if (a == b) returns 1 + * if (a > b) returns 2 + */ + +si_int +__cmpti2(ti_int a, ti_int b) +{ + twords x; + x.all = a; + twords y; + y.all = b; + if (x.s.high < y.s.high) + return 0; + if (x.s.high > y.s.high) + return 2; + if (x.s.low < y.s.low) + return 0; + if (x.s.low > y.s.low) + return 2; + return 1; +} + +#endif diff --git a/lib/builtins/comparedf2.c b/lib/builtins/comparedf2.c new file mode 100644 index 000000000..de67784dc --- /dev/null +++ b/lib/builtins/comparedf2.c @@ -0,0 +1,134 @@ +//===-- lib/comparedf2.c - Double-precision comparisons -----------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// // This file implements the following soft-float comparison routines: +// +// __eqdf2 __gedf2 __unorddf2 +// __ledf2 __gtdf2 +// __ltdf2 +// __nedf2 +// +// The semantics of the routines grouped in each column are identical, so there +// is a single implementation for each, and wrappers to provide the other names. +// +// The main routines behave as follows: +// +// __ledf2(a,b) returns -1 if a < b +// 0 if a == b +// 1 if a > b +// 1 if either a or b is NaN +// +// __gedf2(a,b) returns -1 if a < b +// 0 if a == b +// 1 if a > b +// -1 if either a or b is NaN +// +// __unorddf2(a,b) returns 0 if both a and b are numbers +// 1 if either a or b is NaN +// +// Note that __ledf2( ) and __gedf2( ) are identical except in their handling of +// NaN values. +// +//===----------------------------------------------------------------------===// + +#define DOUBLE_PRECISION +#include "fp_lib.h" + +enum LE_RESULT { + LE_LESS = -1, + LE_EQUAL = 0, + LE_GREATER = 1, + LE_UNORDERED = 1 +}; + +enum LE_RESULT __ledf2(fp_t a, fp_t b) { + + const srep_t aInt = toRep(a); + const srep_t bInt = toRep(b); + const rep_t aAbs = aInt & absMask; + const rep_t bAbs = bInt & absMask; + + // If either a or b is NaN, they are unordered. + if (aAbs > infRep || bAbs > infRep) return LE_UNORDERED; + + // If a and b are both zeros, they are equal. + if ((aAbs | bAbs) == 0) return LE_EQUAL; + + // If at least one of a and b is positive, we get the same result comparing + // a and b as signed integers as we would with a floating-point compare. + if ((aInt & bInt) >= 0) { + if (aInt < bInt) return LE_LESS; + else if (aInt == bInt) return LE_EQUAL; + else return LE_GREATER; + } + + // Otherwise, both are negative, so we need to flip the sense of the + // comparison to get the correct result. (This assumes a twos- or ones- + // complement integer representation; if integers are represented in a + // sign-magnitude representation, then this flip is incorrect). + else { + if (aInt > bInt) return LE_LESS; + else if (aInt == bInt) return LE_EQUAL; + else return LE_GREATER; + } +} + +enum GE_RESULT { + GE_LESS = -1, + GE_EQUAL = 0, + GE_GREATER = 1, + GE_UNORDERED = -1 // Note: different from LE_UNORDERED +}; + +enum GE_RESULT __gedf2(fp_t a, fp_t b) { + + const srep_t aInt = toRep(a); + const srep_t bInt = toRep(b); + const rep_t aAbs = aInt & absMask; + const rep_t bAbs = bInt & absMask; + + if (aAbs > infRep || bAbs > infRep) return GE_UNORDERED; + if ((aAbs | bAbs) == 0) return GE_EQUAL; + if ((aInt & bInt) >= 0) { + if (aInt < bInt) return GE_LESS; + else if (aInt == bInt) return GE_EQUAL; + else return GE_GREATER; + } else { + if (aInt > bInt) return GE_LESS; + else if (aInt == bInt) return GE_EQUAL; + else return GE_GREATER; + } +} + +ARM_EABI_FNALIAS(dcmpun, unorddf2) + +int __unorddf2(fp_t a, fp_t b) { + const rep_t aAbs = toRep(a) & absMask; + const rep_t bAbs = toRep(b) & absMask; + return aAbs > infRep || bAbs > infRep; +} + +// The following are alternative names for the preceeding routines. + +enum LE_RESULT __eqdf2(fp_t a, fp_t b) { + return __ledf2(a, b); +} + +enum LE_RESULT __ltdf2(fp_t a, fp_t b) { + return __ledf2(a, b); +} + +enum LE_RESULT __nedf2(fp_t a, fp_t b) { + return __ledf2(a, b); +} + +enum GE_RESULT __gtdf2(fp_t a, fp_t b) { + return __gedf2(a, b); +} + diff --git a/lib/builtins/comparesf2.c b/lib/builtins/comparesf2.c new file mode 100644 index 000000000..c1c3a479c --- /dev/null +++ b/lib/builtins/comparesf2.c @@ -0,0 +1,133 @@ +//===-- lib/comparesf2.c - Single-precision comparisons -----------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the following soft-fp_t comparison routines: +// +// __eqsf2 __gesf2 __unordsf2 +// __lesf2 __gtsf2 +// __ltsf2 +// __nesf2 +// +// The semantics of the routines grouped in each column are identical, so there +// is a single implementation for each, and wrappers to provide the other names. +// +// The main routines behave as follows: +// +// __lesf2(a,b) returns -1 if a < b +// 0 if a == b +// 1 if a > b +// 1 if either a or b is NaN +// +// __gesf2(a,b) returns -1 if a < b +// 0 if a == b +// 1 if a > b +// -1 if either a or b is NaN +// +// __unordsf2(a,b) returns 0 if both a and b are numbers +// 1 if either a or b is NaN +// +// Note that __lesf2( ) and __gesf2( ) are identical except in their handling of +// NaN values. +// +//===----------------------------------------------------------------------===// + +#define SINGLE_PRECISION +#include "fp_lib.h" + +enum LE_RESULT { + LE_LESS = -1, + LE_EQUAL = 0, + LE_GREATER = 1, + LE_UNORDERED = 1 +}; + +enum LE_RESULT __lesf2(fp_t a, fp_t b) { + + const srep_t aInt = toRep(a); + const srep_t bInt = toRep(b); + const rep_t aAbs = aInt & absMask; + const rep_t bAbs = bInt & absMask; + + // If either a or b is NaN, they are unordered. + if (aAbs > infRep || bAbs > infRep) return LE_UNORDERED; + + // If a and b are both zeros, they are equal. + if ((aAbs | bAbs) == 0) return LE_EQUAL; + + // If at least one of a and b is positive, we get the same result comparing + // a and b as signed integers as we would with a fp_ting-point compare. + if ((aInt & bInt) >= 0) { + if (aInt < bInt) return LE_LESS; + else if (aInt == bInt) return LE_EQUAL; + else return LE_GREATER; + } + + // Otherwise, both are negative, so we need to flip the sense of the + // comparison to get the correct result. (This assumes a twos- or ones- + // complement integer representation; if integers are represented in a + // sign-magnitude representation, then this flip is incorrect). + else { + if (aInt > bInt) return LE_LESS; + else if (aInt == bInt) return LE_EQUAL; + else return LE_GREATER; + } +} + +enum GE_RESULT { + GE_LESS = -1, + GE_EQUAL = 0, + GE_GREATER = 1, + GE_UNORDERED = -1 // Note: different from LE_UNORDERED +}; + +enum GE_RESULT __gesf2(fp_t a, fp_t b) { + + const srep_t aInt = toRep(a); + const srep_t bInt = toRep(b); + const rep_t aAbs = aInt & absMask; + const rep_t bAbs = bInt & absMask; + + if (aAbs > infRep || bAbs > infRep) return GE_UNORDERED; + if ((aAbs | bAbs) == 0) return GE_EQUAL; + if ((aInt & bInt) >= 0) { + if (aInt < bInt) return GE_LESS; + else if (aInt == bInt) return GE_EQUAL; + else return GE_GREATER; + } else { + if (aInt > bInt) return GE_LESS; + else if (aInt == bInt) return GE_EQUAL; + else return GE_GREATER; + } +} + +ARM_EABI_FNALIAS(fcmpun, unordsf2) + +int __unordsf2(fp_t a, fp_t b) { + const rep_t aAbs = toRep(a) & absMask; + const rep_t bAbs = toRep(b) & absMask; + return aAbs > infRep || bAbs > infRep; +} + +// The following are alternative names for the preceeding routines. + +enum LE_RESULT __eqsf2(fp_t a, fp_t b) { + return __lesf2(a, b); +} + +enum LE_RESULT __ltsf2(fp_t a, fp_t b) { + return __lesf2(a, b); +} + +enum LE_RESULT __nesf2(fp_t a, fp_t b) { + return __lesf2(a, b); +} + +enum GE_RESULT __gtsf2(fp_t a, fp_t b) { + return __gesf2(a, b); +} diff --git a/lib/builtins/ctzdi2.c b/lib/builtins/ctzdi2.c new file mode 100644 index 000000000..db3c6fdc0 --- /dev/null +++ b/lib/builtins/ctzdi2.c @@ -0,0 +1,29 @@ +/* ===-- ctzdi2.c - Implement __ctzdi2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __ctzdi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: the number of trailing 0-bits */ + +/* Precondition: a != 0 */ + +COMPILER_RT_ABI si_int +__ctzdi2(di_int a) +{ + dwords x; + x.all = a; + const si_int f = -(x.s.low == 0); + return __builtin_ctz((x.s.high & f) | (x.s.low & ~f)) + + (f & ((si_int)(sizeof(si_int) * CHAR_BIT))); +} diff --git a/lib/builtins/ctzsi2.c b/lib/builtins/ctzsi2.c new file mode 100644 index 000000000..c69486ea4 --- /dev/null +++ b/lib/builtins/ctzsi2.c @@ -0,0 +1,57 @@ +/* ===-- ctzsi2.c - Implement __ctzsi2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __ctzsi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: the number of trailing 0-bits */ + +/* Precondition: a != 0 */ + +COMPILER_RT_ABI si_int +__ctzsi2(si_int a) +{ + su_int x = (su_int)a; + si_int t = ((x & 0x0000FFFF) == 0) << 4; /* if (x has no small bits) t = 16 else 0 */ + x >>= t; /* x = [0 - 0xFFFF] + higher garbage bits */ + su_int r = t; /* r = [0, 16] */ + /* return r + ctz(x) */ + t = ((x & 0x00FF) == 0) << 3; + x >>= t; /* x = [0 - 0xFF] + higher garbage bits */ + r += t; /* r = [0, 8, 16, 24] */ + /* return r + ctz(x) */ + t = ((x & 0x0F) == 0) << 2; + x >>= t; /* x = [0 - 0xF] + higher garbage bits */ + r += t; /* r = [0, 4, 8, 12, 16, 20, 24, 28] */ + /* return r + ctz(x) */ + t = ((x & 0x3) == 0) << 1; + x >>= t; + x &= 3; /* x = [0 - 3] */ + r += t; /* r = [0 - 30] and is even */ + /* return r + ctz(x) */ + +/* The branch-less return statement below is equivalent + * to the following switch statement: + * switch (x) + * { + * case 0: + * return r + 2; + * case 2: + * return r + 1; + * case 1: + * case 3: + * return r; + * } + */ + return r + ((2 - (x >> 1)) & -((x & 1) == 0)); +} diff --git a/lib/builtins/ctzti2.c b/lib/builtins/ctzti2.c new file mode 100644 index 000000000..66dc01b7a --- /dev/null +++ b/lib/builtins/ctzti2.c @@ -0,0 +1,33 @@ +/* ===-- ctzti2.c - Implement __ctzti2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __ctzti2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: the number of trailing 0-bits */ + +/* Precondition: a != 0 */ + +si_int +__ctzti2(ti_int a) +{ + twords x; + x.all = a; + const di_int f = -(x.s.low == 0); + return __builtin_ctzll((x.s.high & f) | (x.s.low & ~f)) + + ((si_int)f & ((si_int)(sizeof(di_int) * CHAR_BIT))); +} + +#endif diff --git a/lib/builtins/divdc3.c b/lib/builtins/divdc3.c new file mode 100644 index 000000000..cfbc498e7 --- /dev/null +++ b/lib/builtins/divdc3.c @@ -0,0 +1,60 @@ +/* ===-- divdc3.c - Implement __divdc3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __divdc3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" +#include "int_math.h" + +/* Returns: the quotient of (a + ib) / (c + id) */ + +double _Complex +__divdc3(double __a, double __b, double __c, double __d) +{ + int __ilogbw = 0; + double __logbw = crt_logb(crt_fmax(crt_fabs(__c), crt_fabs(__d))); + if (crt_isfinite(__logbw)) + { + __ilogbw = (int)__logbw; + __c = crt_scalbn(__c, -__ilogbw); + __d = crt_scalbn(__d, -__ilogbw); + } + double __denom = __c * __c + __d * __d; + double _Complex z; + __real__ z = crt_scalbn((__a * __c + __b * __d) / __denom, -__ilogbw); + __imag__ z = crt_scalbn((__b * __c - __a * __d) / __denom, -__ilogbw); + if (crt_isnan(__real__ z) && crt_isnan(__imag__ z)) + { + if ((__denom == 0.0) && (!crt_isnan(__a) || !crt_isnan(__b))) + { + __real__ z = crt_copysign(CRT_INFINITY, __c) * __a; + __imag__ z = crt_copysign(CRT_INFINITY, __c) * __b; + } + else if ((crt_isinf(__a) || crt_isinf(__b)) && + crt_isfinite(__c) && crt_isfinite(__d)) + { + __a = crt_copysign(crt_isinf(__a) ? 1.0 : 0.0, __a); + __b = crt_copysign(crt_isinf(__b) ? 1.0 : 0.0, __b); + __real__ z = CRT_INFINITY * (__a * __c + __b * __d); + __imag__ z = CRT_INFINITY * (__b * __c - __a * __d); + } + else if (crt_isinf(__logbw) && __logbw > 0.0 && + crt_isfinite(__a) && crt_isfinite(__b)) + { + __c = crt_copysign(crt_isinf(__c) ? 1.0 : 0.0, __c); + __d = crt_copysign(crt_isinf(__d) ? 1.0 : 0.0, __d); + __real__ z = 0.0 * (__a * __c + __b * __d); + __imag__ z = 0.0 * (__b * __c - __a * __d); + } + } + return z; +} diff --git a/lib/builtins/divdf3.c b/lib/builtins/divdf3.c new file mode 100644 index 000000000..efce6bb4b --- /dev/null +++ b/lib/builtins/divdf3.c @@ -0,0 +1,184 @@ +//===-- lib/divdf3.c - Double-precision division ------------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements double-precision soft-float division +// with the IEEE-754 default rounding (to nearest, ties to even). +// +// For simplicity, this implementation currently flushes denormals to zero. +// It should be a fairly straightforward exercise to implement gradual +// underflow with correct rounding. +// +//===----------------------------------------------------------------------===// + +#define DOUBLE_PRECISION +#include "fp_lib.h" + +ARM_EABI_FNALIAS(ddiv, divdf3) + +fp_t __divdf3(fp_t a, fp_t b) { + + const unsigned int aExponent = toRep(a) >> significandBits & maxExponent; + const unsigned int bExponent = toRep(b) >> significandBits & maxExponent; + const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit; + + rep_t aSignificand = toRep(a) & significandMask; + rep_t bSignificand = toRep(b) & significandMask; + int scale = 0; + + // Detect if a or b is zero, denormal, infinity, or NaN. + if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) { + + const rep_t aAbs = toRep(a) & absMask; + const rep_t bAbs = toRep(b) & absMask; + + // NaN / anything = qNaN + if (aAbs > infRep) return fromRep(toRep(a) | quietBit); + // anything / NaN = qNaN + if (bAbs > infRep) return fromRep(toRep(b) | quietBit); + + if (aAbs == infRep) { + // infinity / infinity = NaN + if (bAbs == infRep) return fromRep(qnanRep); + // infinity / anything else = +/- infinity + else return fromRep(aAbs | quotientSign); + } + + // anything else / infinity = +/- 0 + if (bAbs == infRep) return fromRep(quotientSign); + + if (!aAbs) { + // zero / zero = NaN + if (!bAbs) return fromRep(qnanRep); + // zero / anything else = +/- zero + else return fromRep(quotientSign); + } + // anything else / zero = +/- infinity + if (!bAbs) return fromRep(infRep | quotientSign); + + // one or both of a or b is denormal, the other (if applicable) is a + // normal number. Renormalize one or both of a and b, and set scale to + // include the necessary exponent adjustment. + if (aAbs < implicitBit) scale += normalize(&aSignificand); + if (bAbs < implicitBit) scale -= normalize(&bSignificand); + } + + // Or in the implicit significand bit. (If we fell through from the + // denormal path it was already set by normalize( ), but setting it twice + // won't hurt anything.) + aSignificand |= implicitBit; + bSignificand |= implicitBit; + int quotientExponent = aExponent - bExponent + scale; + + // Align the significand of b as a Q31 fixed-point number in the range + // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax + // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This + // is accurate to about 3.5 binary digits. + const uint32_t q31b = bSignificand >> 21; + uint32_t recip32 = UINT32_C(0x7504f333) - q31b; + + // Now refine the reciprocal estimate using a Newton-Raphson iteration: + // + // x1 = x0 * (2 - x0 * b) + // + // This doubles the number of correct binary digits in the approximation + // with each iteration, so after three iterations, we have about 28 binary + // digits of accuracy. + uint32_t correction32; + correction32 = -((uint64_t)recip32 * q31b >> 32); + recip32 = (uint64_t)recip32 * correction32 >> 31; + correction32 = -((uint64_t)recip32 * q31b >> 32); + recip32 = (uint64_t)recip32 * correction32 >> 31; + correction32 = -((uint64_t)recip32 * q31b >> 32); + recip32 = (uint64_t)recip32 * correction32 >> 31; + + // recip32 might have overflowed to exactly zero in the preceeding + // computation if the high word of b is exactly 1.0. This would sabotage + // the full-width final stage of the computation that follows, so we adjust + // recip32 downward by one bit. + recip32--; + + // We need to perform one more iteration to get us to 56 binary digits; + // The last iteration needs to happen with extra precision. + const uint32_t q63blo = bSignificand << 11; + uint64_t correction, reciprocal; + correction = -((uint64_t)recip32*q31b + ((uint64_t)recip32*q63blo >> 32)); + uint32_t cHi = correction >> 32; + uint32_t cLo = correction; + reciprocal = (uint64_t)recip32*cHi + ((uint64_t)recip32*cLo >> 32); + + // We already adjusted the 32-bit estimate, now we need to adjust the final + // 64-bit reciprocal estimate downward to ensure that it is strictly smaller + // than the infinitely precise exact reciprocal. Because the computation + // of the Newton-Raphson step is truncating at every step, this adjustment + // is small; most of the work is already done. + reciprocal -= 2; + + // The numerical reciprocal is accurate to within 2^-56, lies in the + // interval [0.5, 1.0), and is strictly smaller than the true reciprocal + // of b. Multiplying a by this reciprocal thus gives a numerical q = a/b + // in Q53 with the following properties: + // + // 1. q < a/b + // 2. q is in the interval [0.5, 2.0) + // 3. the error in q is bounded away from 2^-53 (actually, we have a + // couple of bits to spare, but this is all we need). + + // We need a 64 x 64 multiply high to compute q, which isn't a basic + // operation in C, so we need to be a little bit fussy. + rep_t quotient, quotientLo; + wideMultiply(aSignificand << 2, reciprocal, "ient, "ientLo); + + // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0). + // In either case, we are going to compute a residual of the form + // + // r = a - q*b + // + // We know from the construction of q that r satisfies: + // + // 0 <= r < ulp(q)*b + // + // if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we + // already have the correct result. The exact halfway case cannot occur. + // We also take this time to right shift quotient if it falls in the [1,2) + // range and adjust the exponent accordingly. + rep_t residual; + if (quotient < (implicitBit << 1)) { + residual = (aSignificand << 53) - quotient * bSignificand; + quotientExponent--; + } else { + quotient >>= 1; + residual = (aSignificand << 52) - quotient * bSignificand; + } + + const int writtenExponent = quotientExponent + exponentBias; + + if (writtenExponent >= maxExponent) { + // If we have overflowed the exponent, return infinity. + return fromRep(infRep | quotientSign); + } + + else if (writtenExponent < 1) { + // Flush denormals to zero. In the future, it would be nice to add + // code to round them correctly. + return fromRep(quotientSign); + } + + else { + const bool round = (residual << 1) > bSignificand; + // Clear the implicit bit + rep_t absResult = quotient & significandMask; + // Insert the exponent + absResult |= (rep_t)writtenExponent << significandBits; + // Round + absResult += round; + // Insert the sign and return + const double result = fromRep(absResult | quotientSign); + return result; + } +} diff --git a/lib/builtins/divdi3.c b/lib/builtins/divdi3.c new file mode 100644 index 000000000..2c2bcc26d --- /dev/null +++ b/lib/builtins/divdi3.c @@ -0,0 +1,31 @@ +/* ===-- divdi3.c - Implement __divdi3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __divdi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +du_int COMPILER_RT_ABI __udivmoddi4(du_int a, du_int b, du_int* rem); + +/* Returns: a / b */ + +COMPILER_RT_ABI di_int +__divdi3(di_int a, di_int b) +{ + const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1; + di_int s_a = a >> bits_in_dword_m1; /* s_a = a < 0 ? -1 : 0 */ + di_int s_b = b >> bits_in_dword_m1; /* s_b = b < 0 ? -1 : 0 */ + a = (a ^ s_a) - s_a; /* negate if s_a == -1 */ + b = (b ^ s_b) - s_b; /* negate if s_b == -1 */ + s_a ^= s_b; /*sign of quotient */ + return (__udivmoddi4(a, b, (du_int*)0) ^ s_a) - s_a; /* negate if s_a == -1 */ +} diff --git a/lib/builtins/divmoddi4.c b/lib/builtins/divmoddi4.c new file mode 100644 index 000000000..2fe2b4818 --- /dev/null +++ b/lib/builtins/divmoddi4.c @@ -0,0 +1,27 @@ +/*===-- divmoddi4.c - Implement __divmoddi4 --------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __divmoddi4 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +extern COMPILER_RT_ABI di_int __divdi3(di_int a, di_int b); + +/* Returns: a / b, *rem = a % b */ + +COMPILER_RT_ABI di_int +__divmoddi4(di_int a, di_int b, di_int* rem) +{ + di_int d = __divdi3(a,b); + *rem = a - (d*b); + return d; +} diff --git a/lib/builtins/divmodsi4.c b/lib/builtins/divmodsi4.c new file mode 100644 index 000000000..c7f7b1a7c --- /dev/null +++ b/lib/builtins/divmodsi4.c @@ -0,0 +1,30 @@ +/*===-- divmodsi4.c - Implement __divmodsi4 --------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __divmodsi4 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +extern COMPILER_RT_ABI si_int __divsi3(si_int a, si_int b); + + +/* Returns: a / b, *rem = a % b */ + +COMPILER_RT_ABI si_int +__divmodsi4(si_int a, si_int b, si_int* rem) +{ + si_int d = __divsi3(a,b); + *rem = a - (d*b); + return d; +} + + diff --git a/lib/builtins/divsc3.c b/lib/builtins/divsc3.c new file mode 100644 index 000000000..caa0c4075 --- /dev/null +++ b/lib/builtins/divsc3.c @@ -0,0 +1,60 @@ +/*===-- divsc3.c - Implement __divsc3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __divsc3 for the compiler_rt library. + * + *===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" +#include "int_math.h" + +/* Returns: the quotient of (a + ib) / (c + id) */ + +float _Complex +__divsc3(float __a, float __b, float __c, float __d) +{ + int __ilogbw = 0; + float __logbw = crt_logbf(crt_fmaxf(crt_fabsf(__c), crt_fabsf(__d))); + if (crt_isfinite(__logbw)) + { + __ilogbw = (int)__logbw; + __c = crt_scalbnf(__c, -__ilogbw); + __d = crt_scalbnf(__d, -__ilogbw); + } + float __denom = __c * __c + __d * __d; + float _Complex z; + __real__ z = crt_scalbnf((__a * __c + __b * __d) / __denom, -__ilogbw); + __imag__ z = crt_scalbnf((__b * __c - __a * __d) / __denom, -__ilogbw); + if (crt_isnan(__real__ z) && crt_isnan(__imag__ z)) + { + if ((__denom == 0) && (!crt_isnan(__a) || !crt_isnan(__b))) + { + __real__ z = crt_copysignf(CRT_INFINITY, __c) * __a; + __imag__ z = crt_copysignf(CRT_INFINITY, __c) * __b; + } + else if ((crt_isinf(__a) || crt_isinf(__b)) && + crt_isfinite(__c) && crt_isfinite(__d)) + { + __a = crt_copysignf(crt_isinf(__a) ? 1 : 0, __a); + __b = crt_copysignf(crt_isinf(__b) ? 1 : 0, __b); + __real__ z = CRT_INFINITY * (__a * __c + __b * __d); + __imag__ z = CRT_INFINITY * (__b * __c - __a * __d); + } + else if (crt_isinf(__logbw) && __logbw > 0 && + crt_isfinite(__a) && crt_isfinite(__b)) + { + __c = crt_copysignf(crt_isinf(__c) ? 1 : 0, __c); + __d = crt_copysignf(crt_isinf(__d) ? 1 : 0, __d); + __real__ z = 0 * (__a * __c + __b * __d); + __imag__ z = 0 * (__b * __c - __a * __d); + } + } + return z; +} diff --git a/lib/builtins/divsf3.c b/lib/builtins/divsf3.c new file mode 100644 index 000000000..c91c648fa --- /dev/null +++ b/lib/builtins/divsf3.c @@ -0,0 +1,168 @@ +//===-- lib/divsf3.c - Single-precision division ------------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements single-precision soft-float division +// with the IEEE-754 default rounding (to nearest, ties to even). +// +// For simplicity, this implementation currently flushes denormals to zero. +// It should be a fairly straightforward exercise to implement gradual +// underflow with correct rounding. +// +//===----------------------------------------------------------------------===// + +#define SINGLE_PRECISION +#include "fp_lib.h" + +ARM_EABI_FNALIAS(fdiv, divsf3) + +fp_t __divsf3(fp_t a, fp_t b) { + + const unsigned int aExponent = toRep(a) >> significandBits & maxExponent; + const unsigned int bExponent = toRep(b) >> significandBits & maxExponent; + const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit; + + rep_t aSignificand = toRep(a) & significandMask; + rep_t bSignificand = toRep(b) & significandMask; + int scale = 0; + + // Detect if a or b is zero, denormal, infinity, or NaN. + if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) { + + const rep_t aAbs = toRep(a) & absMask; + const rep_t bAbs = toRep(b) & absMask; + + // NaN / anything = qNaN + if (aAbs > infRep) return fromRep(toRep(a) | quietBit); + // anything / NaN = qNaN + if (bAbs > infRep) return fromRep(toRep(b) | quietBit); + + if (aAbs == infRep) { + // infinity / infinity = NaN + if (bAbs == infRep) return fromRep(qnanRep); + // infinity / anything else = +/- infinity + else return fromRep(aAbs | quotientSign); + } + + // anything else / infinity = +/- 0 + if (bAbs == infRep) return fromRep(quotientSign); + + if (!aAbs) { + // zero / zero = NaN + if (!bAbs) return fromRep(qnanRep); + // zero / anything else = +/- zero + else return fromRep(quotientSign); + } + // anything else / zero = +/- infinity + if (!bAbs) return fromRep(infRep | quotientSign); + + // one or both of a or b is denormal, the other (if applicable) is a + // normal number. Renormalize one or both of a and b, and set scale to + // include the necessary exponent adjustment. + if (aAbs < implicitBit) scale += normalize(&aSignificand); + if (bAbs < implicitBit) scale -= normalize(&bSignificand); + } + + // Or in the implicit significand bit. (If we fell through from the + // denormal path it was already set by normalize( ), but setting it twice + // won't hurt anything.) + aSignificand |= implicitBit; + bSignificand |= implicitBit; + int quotientExponent = aExponent - bExponent + scale; + + // Align the significand of b as a Q31 fixed-point number in the range + // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax + // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This + // is accurate to about 3.5 binary digits. + uint32_t q31b = bSignificand << 8; + uint32_t reciprocal = UINT32_C(0x7504f333) - q31b; + + // Now refine the reciprocal estimate using a Newton-Raphson iteration: + // + // x1 = x0 * (2 - x0 * b) + // + // This doubles the number of correct binary digits in the approximation + // with each iteration, so after three iterations, we have about 28 binary + // digits of accuracy. + uint32_t correction; + correction = -((uint64_t)reciprocal * q31b >> 32); + reciprocal = (uint64_t)reciprocal * correction >> 31; + correction = -((uint64_t)reciprocal * q31b >> 32); + reciprocal = (uint64_t)reciprocal * correction >> 31; + correction = -((uint64_t)reciprocal * q31b >> 32); + reciprocal = (uint64_t)reciprocal * correction >> 31; + + // Exhaustive testing shows that the error in reciprocal after three steps + // is in the interval [-0x1.f58108p-31, 0x1.d0e48cp-29], in line with our + // expectations. We bump the reciprocal by a tiny value to force the error + // to be strictly positive (in the range [0x1.4fdfp-37,0x1.287246p-29], to + // be specific). This also causes 1/1 to give a sensible approximation + // instead of zero (due to overflow). + reciprocal -= 2; + + // The numerical reciprocal is accurate to within 2^-28, lies in the + // interval [0x1.000000eep-1, 0x1.fffffffcp-1], and is strictly smaller + // than the true reciprocal of b. Multiplying a by this reciprocal thus + // gives a numerical q = a/b in Q24 with the following properties: + // + // 1. q < a/b + // 2. q is in the interval [0x1.000000eep-1, 0x1.fffffffcp0) + // 3. the error in q is at most 2^-24 + 2^-27 -- the 2^24 term comes + // from the fact that we truncate the product, and the 2^27 term + // is the error in the reciprocal of b scaled by the maximum + // possible value of a. As a consequence of this error bound, + // either q or nextafter(q) is the correctly rounded + rep_t quotient = (uint64_t)reciprocal*(aSignificand << 1) >> 32; + + // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0). + // In either case, we are going to compute a residual of the form + // + // r = a - q*b + // + // We know from the construction of q that r satisfies: + // + // 0 <= r < ulp(q)*b + // + // if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we + // already have the correct result. The exact halfway case cannot occur. + // We also take this time to right shift quotient if it falls in the [1,2) + // range and adjust the exponent accordingly. + rep_t residual; + if (quotient < (implicitBit << 1)) { + residual = (aSignificand << 24) - quotient * bSignificand; + quotientExponent--; + } else { + quotient >>= 1; + residual = (aSignificand << 23) - quotient * bSignificand; + } + + const int writtenExponent = quotientExponent + exponentBias; + + if (writtenExponent >= maxExponent) { + // If we have overflowed the exponent, return infinity. + return fromRep(infRep | quotientSign); + } + + else if (writtenExponent < 1) { + // Flush denormals to zero. In the future, it would be nice to add + // code to round them correctly. + return fromRep(quotientSign); + } + + else { + const bool round = (residual << 1) > bSignificand; + // Clear the implicit bit + rep_t absResult = quotient & significandMask; + // Insert the exponent + absResult |= (rep_t)writtenExponent << significandBits; + // Round + absResult += round; + // Insert the sign and return + return fromRep(absResult | quotientSign); + } +} diff --git a/lib/builtins/divsi3.c b/lib/builtins/divsi3.c new file mode 100644 index 000000000..cd19de952 --- /dev/null +++ b/lib/builtins/divsi3.c @@ -0,0 +1,39 @@ +/* ===-- divsi3.c - Implement __divsi3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __divsi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +su_int COMPILER_RT_ABI __udivsi3(su_int n, su_int d); + +/* Returns: a / b */ + +ARM_EABI_FNALIAS(idiv, divsi3) + +COMPILER_RT_ABI si_int +__divsi3(si_int a, si_int b) +{ + const int bits_in_word_m1 = (int)(sizeof(si_int) * CHAR_BIT) - 1; + si_int s_a = a >> bits_in_word_m1; /* s_a = a < 0 ? -1 : 0 */ + si_int s_b = b >> bits_in_word_m1; /* s_b = b < 0 ? -1 : 0 */ + a = (a ^ s_a) - s_a; /* negate if s_a == -1 */ + b = (b ^ s_b) - s_b; /* negate if s_b == -1 */ + s_a ^= s_b; /* sign of quotient */ + /* + * On CPUs without unsigned hardware division support, + * this calls __udivsi3 (notice the cast to su_int). + * On CPUs with unsigned hardware division support, + * this uses the unsigned division instruction. + */ + return ((su_int)a/(su_int)b ^ s_a) - s_a; /* negate if s_a == -1 */ +} diff --git a/lib/builtins/divti3.c b/lib/builtins/divti3.c new file mode 100644 index 000000000..0242c1368 --- /dev/null +++ b/lib/builtins/divti3.c @@ -0,0 +1,35 @@ +/* ===-- divti3.c - Implement __divti3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __divti3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem); + +/* Returns: a / b */ + +ti_int +__divti3(ti_int a, ti_int b) +{ + const int bits_in_tword_m1 = (int)(sizeof(ti_int) * CHAR_BIT) - 1; + ti_int s_a = a >> bits_in_tword_m1; /* s_a = a < 0 ? -1 : 0 */ + ti_int s_b = b >> bits_in_tword_m1; /* s_b = b < 0 ? -1 : 0 */ + a = (a ^ s_a) - s_a; /* negate if s_a == -1 */ + b = (b ^ s_b) - s_b; /* negate if s_b == -1 */ + s_a ^= s_b; /* sign of quotient */ + return (__udivmodti4(a, b, (tu_int*)0) ^ s_a) - s_a; /* negate if s_a == -1 */ +} + +#endif diff --git a/lib/builtins/divxc3.c b/lib/builtins/divxc3.c new file mode 100644 index 000000000..5f240e956 --- /dev/null +++ b/lib/builtins/divxc3.c @@ -0,0 +1,63 @@ +/* ===-- divxc3.c - Implement __divxc3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __divxc3 for the compiler_rt library. + * + */ + +#if !_ARCH_PPC + +#include "int_lib.h" +#include "int_math.h" + +/* Returns: the quotient of (a + ib) / (c + id) */ + +long double _Complex +__divxc3(long double __a, long double __b, long double __c, long double __d) +{ + int __ilogbw = 0; + long double __logbw = crt_logbl(crt_fmaxl(crt_fabsl(__c), crt_fabsl(__d))); + if (crt_isfinite(__logbw)) + { + __ilogbw = (int)__logbw; + __c = crt_scalbnl(__c, -__ilogbw); + __d = crt_scalbnl(__d, -__ilogbw); + } + long double __denom = __c * __c + __d * __d; + long double _Complex z; + __real__ z = crt_scalbnl((__a * __c + __b * __d) / __denom, -__ilogbw); + __imag__ z = crt_scalbnl((__b * __c - __a * __d) / __denom, -__ilogbw); + if (crt_isnan(__real__ z) && crt_isnan(__imag__ z)) + { + if ((__denom == 0) && (!crt_isnan(__a) || !crt_isnan(__b))) + { + __real__ z = crt_copysignl(CRT_INFINITY, __c) * __a; + __imag__ z = crt_copysignl(CRT_INFINITY, __c) * __b; + } + else if ((crt_isinf(__a) || crt_isinf(__b)) && + crt_isfinite(__c) && crt_isfinite(__d)) + { + __a = crt_copysignl(crt_isinf(__a) ? 1 : 0, __a); + __b = crt_copysignl(crt_isinf(__b) ? 1 : 0, __b); + __real__ z = CRT_INFINITY * (__a * __c + __b * __d); + __imag__ z = CRT_INFINITY * (__b * __c - __a * __d); + } + else if (crt_isinf(__logbw) && __logbw > 0 && + crt_isfinite(__a) && crt_isfinite(__b)) + { + __c = crt_copysignl(crt_isinf(__c) ? 1 : 0, __c); + __d = crt_copysignl(crt_isinf(__d) ? 1 : 0, __d); + __real__ z = 0 * (__a * __c + __b * __d); + __imag__ z = 0 * (__b * __c - __a * __d); + } + } + return z; +} + +#endif diff --git a/lib/builtins/enable_execute_stack.c b/lib/builtins/enable_execute_stack.c new file mode 100644 index 000000000..278ca246f --- /dev/null +++ b/lib/builtins/enable_execute_stack.c @@ -0,0 +1,59 @@ +/* ===-- enable_execute_stack.c - Implement __enable_execute_stack ---------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#include <sys/mman.h> + +/* #include "config.h" + * FIXME: CMake - include when cmake system is ready. + * Remove #define HAVE_SYSCONF 1 line. + */ +#define HAVE_SYSCONF 1 + +#ifndef __APPLE__ +#include <unistd.h> +#endif /* __APPLE__ */ + +#if __LP64__ + #define TRAMPOLINE_SIZE 48 +#else + #define TRAMPOLINE_SIZE 40 +#endif + +/* + * The compiler generates calls to __enable_execute_stack() when creating + * trampoline functions on the stack for use with nested functions. + * It is expected to mark the page(s) containing the address + * and the next 48 bytes as executable. Since the stack is normally rw- + * that means changing the protection on those page(s) to rwx. + */ + +void __enable_execute_stack(void* addr) +{ + +#if __APPLE__ + /* On Darwin, pagesize is always 4096 bytes */ + const uintptr_t pageSize = 4096; +#elif !defined(HAVE_SYSCONF) +#error "HAVE_SYSCONF not defined! See enable_execute_stack.c" +#else + const uintptr_t pageSize = sysconf(_SC_PAGESIZE); +#endif /* __APPLE__ */ + + const uintptr_t pageAlignMask = ~(pageSize-1); + uintptr_t p = (uintptr_t)addr; + unsigned char* startPage = (unsigned char*)(p & pageAlignMask); + unsigned char* endPage = (unsigned char*)((p+TRAMPOLINE_SIZE+pageSize) & pageAlignMask); + size_t length = endPage - startPage; + (void) mprotect((void *)startPage, length, PROT_READ | PROT_WRITE | PROT_EXEC); +} + + diff --git a/lib/builtins/eprintf.c b/lib/builtins/eprintf.c new file mode 100644 index 000000000..3626dbf8b --- /dev/null +++ b/lib/builtins/eprintf.c @@ -0,0 +1,34 @@ +/* ===---------- eprintf.c - Implements __eprintf --------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + */ + + + +#include "int_lib.h" +#include <stdio.h> + + +/* + * __eprintf() was used in an old version of <assert.h>. + * It can eventually go away, but it is needed when linking + * .o files built with the old <assert.h>. + * + * It should never be exported from a dylib, so it is marked + * visibility hidden. + */ +#ifndef _WIN32 +__attribute__((visibility("hidden"))) +#endif +void __eprintf(const char* format, const char* assertion_expression, + const char* line, const char* file) +{ + fprintf(stderr, format, assertion_expression, line, file); + fflush(stderr); + compilerrt_abort(); +} diff --git a/lib/builtins/extendsfdf2.c b/lib/builtins/extendsfdf2.c new file mode 100644 index 000000000..91fd2b436 --- /dev/null +++ b/lib/builtins/extendsfdf2.c @@ -0,0 +1,137 @@ +//===-- lib/extendsfdf2.c - single -> double conversion -----------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a fairly generic conversion from a narrower to a wider +// IEEE-754 floating-point type. The constants and types defined following the +// includes below parameterize the conversion. +// +// This routine can be trivially adapted to support conversions from +// half-precision or to quad-precision. It does not support types that don't +// use the usual IEEE-754 interchange formats; specifically, some work would be +// needed to adapt it to (for example) the Intel 80-bit format or PowerPC +// double-double format. +// +// Note please, however, that this implementation is only intended to support +// *widening* operations; if you need to convert to a *narrower* floating-point +// type (e.g. double -> float), then this routine will not do what you want it +// to. +// +// It also requires that integer types at least as large as both formats +// are available on the target platform; this may pose a problem when trying +// to add support for quad on some 32-bit systems, for example. You also may +// run into trouble finding an appropriate CLZ function for wide source types; +// you will likely need to roll your own on some platforms. +// +// Finally, the following assumptions are made: +// +// 1. floating-point types and integer types have the same endianness on the +// target platform +// +// 2. quiet NaNs, if supported, are indicated by the leading bit of the +// significand field being set +// +//===----------------------------------------------------------------------===// + +#include "int_lib.h" + +typedef float src_t; +typedef uint32_t src_rep_t; +#define SRC_REP_C UINT32_C +static const int srcSigBits = 23; +#define src_rep_t_clz __builtin_clz + +typedef double dst_t; +typedef uint64_t dst_rep_t; +#define DST_REP_C UINT64_C +static const int dstSigBits = 52; + +// End of specialization parameters. Two helper routines for conversion to and +// from the representation of floating-point data as integer values follow. + +static inline src_rep_t srcToRep(src_t x) { + const union { src_t f; src_rep_t i; } rep = {.f = x}; + return rep.i; +} + +static inline dst_t dstFromRep(dst_rep_t x) { + const union { dst_t f; dst_rep_t i; } rep = {.i = x}; + return rep.f; +} + +// End helper routines. Conversion implementation follows. + +ARM_EABI_FNALIAS(f2d, extendsfdf2) + +dst_t __extendsfdf2(src_t a) { + + // Various constants whose values follow from the type parameters. + // Any reasonable optimizer will fold and propagate all of these. + const int srcBits = sizeof(src_t)*CHAR_BIT; + const int srcExpBits = srcBits - srcSigBits - 1; + const int srcInfExp = (1 << srcExpBits) - 1; + const int srcExpBias = srcInfExp >> 1; + + const src_rep_t srcMinNormal = SRC_REP_C(1) << srcSigBits; + const src_rep_t srcInfinity = (src_rep_t)srcInfExp << srcSigBits; + const src_rep_t srcSignMask = SRC_REP_C(1) << (srcSigBits + srcExpBits); + const src_rep_t srcAbsMask = srcSignMask - 1; + const src_rep_t srcQNaN = SRC_REP_C(1) << (srcSigBits - 1); + const src_rep_t srcNaNCode = srcQNaN - 1; + + const int dstBits = sizeof(dst_t)*CHAR_BIT; + const int dstExpBits = dstBits - dstSigBits - 1; + const int dstInfExp = (1 << dstExpBits) - 1; + const int dstExpBias = dstInfExp >> 1; + + const dst_rep_t dstMinNormal = DST_REP_C(1) << dstSigBits; + + // Break a into a sign and representation of the absolute value + const src_rep_t aRep = srcToRep(a); + const src_rep_t aAbs = aRep & srcAbsMask; + const src_rep_t sign = aRep & srcSignMask; + dst_rep_t absResult; + + if (aAbs - srcMinNormal < srcInfinity - srcMinNormal) { + // a is a normal number. + // Extend to the destination type by shifting the significand and + // exponent into the proper position and rebiasing the exponent. + absResult = (dst_rep_t)aAbs << (dstSigBits - srcSigBits); + absResult += (dst_rep_t)(dstExpBias - srcExpBias) << dstSigBits; + } + + else if (aAbs >= srcInfinity) { + // a is NaN or infinity. + // Conjure the result by beginning with infinity, then setting the qNaN + // bit (if needed) and right-aligning the rest of the trailing NaN + // payload field. + absResult = (dst_rep_t)dstInfExp << dstSigBits; + absResult |= (dst_rep_t)(aAbs & srcQNaN) << (dstSigBits - srcSigBits); + absResult |= aAbs & srcNaNCode; + } + + else if (aAbs) { + // a is denormal. + // renormalize the significand and clear the leading bit, then insert + // the correct adjusted exponent in the destination type. + const int scale = src_rep_t_clz(aAbs) - src_rep_t_clz(srcMinNormal); + absResult = (dst_rep_t)aAbs << (dstSigBits - srcSigBits + scale); + absResult ^= dstMinNormal; + const int resultExponent = dstExpBias - srcExpBias - scale + 1; + absResult |= (dst_rep_t)resultExponent << dstSigBits; + } + + else { + // a is zero. + absResult = 0; + } + + // Apply the signbit to (dst_t)abs(a). + const dst_rep_t result = absResult | (dst_rep_t)sign << (dstBits - srcBits); + return dstFromRep(result); +} diff --git a/lib/builtins/ffsdi2.c b/lib/builtins/ffsdi2.c new file mode 100644 index 000000000..a5ac9900f --- /dev/null +++ b/lib/builtins/ffsdi2.c @@ -0,0 +1,33 @@ +/* ===-- ffsdi2.c - Implement __ffsdi2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __ffsdi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: the index of the least significant 1-bit in a, or + * the value zero if a is zero. The least significant bit is index one. + */ + +COMPILER_RT_ABI si_int +__ffsdi2(di_int a) +{ + dwords x; + x.all = a; + if (x.s.low == 0) + { + if (x.s.high == 0) + return 0; + return __builtin_ctz(x.s.high) + (1 + sizeof(si_int) * CHAR_BIT); + } + return __builtin_ctz(x.s.low) + 1; +} diff --git a/lib/builtins/ffsti2.c b/lib/builtins/ffsti2.c new file mode 100644 index 000000000..27e15d581 --- /dev/null +++ b/lib/builtins/ffsti2.c @@ -0,0 +1,37 @@ +/* ===-- ffsti2.c - Implement __ffsti2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __ffsti2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: the index of the least significant 1-bit in a, or + * the value zero if a is zero. The least significant bit is index one. + */ + +si_int +__ffsti2(ti_int a) +{ + twords x; + x.all = a; + if (x.s.low == 0) + { + if (x.s.high == 0) + return 0; + return __builtin_ctzll(x.s.high) + (1 + sizeof(di_int) * CHAR_BIT); + } + return __builtin_ctzll(x.s.low) + 1; +} + +#endif /* __x86_64 */ diff --git a/lib/builtins/fixdfdi.c b/lib/builtins/fixdfdi.c new file mode 100644 index 000000000..7665ea5a3 --- /dev/null +++ b/lib/builtins/fixdfdi.c @@ -0,0 +1,45 @@ +/* ===-- fixdfdi.c - Implement __fixdfdi -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixdfdi for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: convert a to a signed long long, rounding toward zero. */ + +/* Assumption: double is a IEEE 64 bit floating point type + * su_int is a 32 bit integral type + * value in double is representable in di_int (no range checking performed) + */ + +/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ + +ARM_EABI_FNALIAS(d2lz, fixdfdi) + +di_int +__fixdfdi(double a) +{ + double_bits fb; + fb.f = a; + int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023; + if (e < 0) + return 0; + di_int s = (si_int)(fb.u.s.high & 0x80000000) >> 31; + dwords r; + r.s.high = (fb.u.s.high & 0x000FFFFF) | 0x00100000; + r.s.low = fb.u.s.low; + if (e > 52) + r.all <<= (e - 52); + else + r.all >>= (52 - e); + return (r.all ^ s) - s; +} diff --git a/lib/builtins/fixdfsi.c b/lib/builtins/fixdfsi.c new file mode 100644 index 000000000..614d032a4 --- /dev/null +++ b/lib/builtins/fixdfsi.c @@ -0,0 +1,49 @@ +//===-- lib/fixdfsi.c - Double-precision -> integer conversion ----*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements double-precision to integer conversion for the +// compiler-rt library. No range checking is performed; the behavior of this +// conversion is undefined for out of range values in the C standard. +// +//===----------------------------------------------------------------------===// + +#define DOUBLE_PRECISION +#include "fp_lib.h" + +#include "int_lib.h" + +ARM_EABI_FNALIAS(d2iz, fixdfsi) + +int __fixdfsi(fp_t a) { + + // Break a into sign, exponent, significand + const rep_t aRep = toRep(a); + const rep_t aAbs = aRep & absMask; + const int sign = aRep & signBit ? -1 : 1; + const int exponent = (aAbs >> significandBits) - exponentBias; + const rep_t significand = (aAbs & significandMask) | implicitBit; + + // If 0 < exponent < significandBits, right shift to get the result. + if ((unsigned int)exponent < significandBits) { + return sign * (significand >> (significandBits - exponent)); + } + + // If exponent is negative, the result is zero. + else if (exponent < 0) { + return 0; + } + + // If significandBits < exponent, left shift to get the result. This shift + // may end up being larger than the type width, which incurs undefined + // behavior, but the conversion itself is undefined in that case, so + // whatever the compiler decides to do is fine. + else { + return sign * (significand << (exponent - significandBits)); + } +} diff --git a/lib/builtins/fixdfti.c b/lib/builtins/fixdfti.c new file mode 100644 index 000000000..b110a94b8 --- /dev/null +++ b/lib/builtins/fixdfti.c @@ -0,0 +1,45 @@ +/* ===-- fixdfti.c - Implement __fixdfti -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixdfti for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: convert a to a signed long long, rounding toward zero. */ + +/* Assumption: double is a IEEE 64 bit floating point type + * su_int is a 32 bit integral type + * value in double is representable in ti_int (no range checking performed) + */ + +/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ + +ti_int +__fixdfti(double a) +{ + double_bits fb; + fb.f = a; + int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023; + if (e < 0) + return 0; + ti_int s = (si_int)(fb.u.s.high & 0x80000000) >> 31; + ti_int r = 0x0010000000000000uLL | (0x000FFFFFFFFFFFFFuLL & fb.u.all); + if (e > 52) + r <<= (e - 52); + else + r >>= (52 - e); + return (r ^ s) - s; +} + +#endif diff --git a/lib/builtins/fixsfdi.c b/lib/builtins/fixsfdi.c new file mode 100644 index 000000000..4f6cfdd7a --- /dev/null +++ b/lib/builtins/fixsfdi.c @@ -0,0 +1,43 @@ +/* ===-- fixsfdi.c - Implement __fixsfdi -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixsfdi for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: convert a to a signed long long, rounding toward zero. */ + +/* Assumption: float is a IEEE 32 bit floating point type + * su_int is a 32 bit integral type + * value in float is representable in di_int (no range checking performed) + */ + +/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */ + +ARM_EABI_FNALIAS(f2lz, fixsfdi) + +COMPILER_RT_ABI di_int +__fixsfdi(float a) +{ + float_bits fb; + fb.f = a; + int e = ((fb.u & 0x7F800000) >> 23) - 127; + if (e < 0) + return 0; + di_int s = (si_int)(fb.u & 0x80000000) >> 31; + di_int r = (fb.u & 0x007FFFFF) | 0x00800000; + if (e > 23) + r <<= (e - 23); + else + r >>= (23 - e); + return (r ^ s) - s; +} diff --git a/lib/builtins/fixsfsi.c b/lib/builtins/fixsfsi.c new file mode 100644 index 000000000..e3cc42d52 --- /dev/null +++ b/lib/builtins/fixsfsi.c @@ -0,0 +1,47 @@ +//===-- lib/fixsfsi.c - Single-precision -> integer conversion ----*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements single-precision to integer conversion for the +// compiler-rt library. No range checking is performed; the behavior of this +// conversion is undefined for out of range values in the C standard. +// +//===----------------------------------------------------------------------===// + +#define SINGLE_PRECISION +#include "fp_lib.h" + +ARM_EABI_FNALIAS(f2iz, fixsfsi) + +COMPILER_RT_ABI int +__fixsfsi(fp_t a) { + // Break a into sign, exponent, significand + const rep_t aRep = toRep(a); + const rep_t aAbs = aRep & absMask; + const int sign = aRep & signBit ? -1 : 1; + const int exponent = (aAbs >> significandBits) - exponentBias; + const rep_t significand = (aAbs & significandMask) | implicitBit; + + // If 0 < exponent < significandBits, right shift to get the result. + if ((unsigned int)exponent < significandBits) { + return sign * (significand >> (significandBits - exponent)); + } + + // If exponent is negative, the result is zero. + else if (exponent < 0) { + return 0; + } + + // If significandBits < exponent, left shift to get the result. This shift + // may end up being larger than the type width, which incurs undefined + // behavior, but the conversion itself is undefined in that case, so + // whatever the compiler decides to do is fine. + else { + return sign * (significand << (exponent - significandBits)); + } +} diff --git a/lib/builtins/fixsfti.c b/lib/builtins/fixsfti.c new file mode 100644 index 000000000..c730ae046 --- /dev/null +++ b/lib/builtins/fixsfti.c @@ -0,0 +1,45 @@ +/* ===-- fixsfti.c - Implement __fixsfti -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixsfti for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: convert a to a signed long long, rounding toward zero. */ + +/* Assumption: float is a IEEE 32 bit floating point type + * su_int is a 32 bit integral type + * value in float is representable in ti_int (no range checking performed) + */ + +/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */ + +ti_int +__fixsfti(float a) +{ + float_bits fb; + fb.f = a; + int e = ((fb.u & 0x7F800000) >> 23) - 127; + if (e < 0) + return 0; + ti_int s = (si_int)(fb.u & 0x80000000) >> 31; + ti_int r = (fb.u & 0x007FFFFF) | 0x00800000; + if (e > 23) + r <<= (e - 23); + else + r >>= (23 - e); + return (r ^ s) - s; +} + +#endif diff --git a/lib/builtins/fixunsdfdi.c b/lib/builtins/fixunsdfdi.c new file mode 100644 index 000000000..9e6371390 --- /dev/null +++ b/lib/builtins/fixunsdfdi.c @@ -0,0 +1,47 @@ +/* ===-- fixunsdfdi.c - Implement __fixunsdfdi -----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixunsdfdi for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: convert a to a unsigned long long, rounding toward zero. + * Negative values all become zero. + */ + +/* Assumption: double is a IEEE 64 bit floating point type + * du_int is a 64 bit integral type + * value in double is representable in du_int or is negative + * (no range checking performed) + */ + +/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ + +ARM_EABI_FNALIAS(d2ulz, fixunsdfdi) + +COMPILER_RT_ABI du_int +__fixunsdfdi(double a) +{ + double_bits fb; + fb.f = a; + int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023; + if (e < 0 || (fb.u.s.high & 0x80000000)) + return 0; + udwords r; + r.s.high = (fb.u.s.high & 0x000FFFFF) | 0x00100000; + r.s.low = fb.u.s.low; + if (e > 52) + r.all <<= (e - 52); + else + r.all >>= (52 - e); + return r.all; +} diff --git a/lib/builtins/fixunsdfsi.c b/lib/builtins/fixunsdfsi.c new file mode 100644 index 000000000..c6a3c755e --- /dev/null +++ b/lib/builtins/fixunsdfsi.c @@ -0,0 +1,44 @@ +/* ===-- fixunsdfsi.c - Implement __fixunsdfsi -----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixunsdfsi for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: convert a to a unsigned int, rounding toward zero. + * Negative values all become zero. + */ + +/* Assumption: double is a IEEE 64 bit floating point type + * su_int is a 32 bit integral type + * value in double is representable in su_int or is negative + * (no range checking performed) + */ + +/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ + +ARM_EABI_FNALIAS(d2uiz, fixunsdfsi) + +COMPILER_RT_ABI su_int +__fixunsdfsi(double a) +{ + double_bits fb; + fb.f = a; + int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023; + if (e < 0 || (fb.u.s.high & 0x80000000)) + return 0; + return ( + 0x80000000u | + ((fb.u.s.high & 0x000FFFFF) << 11) | + (fb.u.s.low >> 21) + ) >> (31 - e); +} diff --git a/lib/builtins/fixunsdfti.c b/lib/builtins/fixunsdfti.c new file mode 100644 index 000000000..fb0336f69 --- /dev/null +++ b/lib/builtins/fixunsdfti.c @@ -0,0 +1,47 @@ +/* ===-- fixunsdfti.c - Implement __fixunsdfti -----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixunsdfti for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: convert a to a unsigned long long, rounding toward zero. + * Negative values all become zero. + */ + +/* Assumption: double is a IEEE 64 bit floating point type + * tu_int is a 64 bit integral type + * value in double is representable in tu_int or is negative + * (no range checking performed) + */ + +/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ + +tu_int +__fixunsdfti(double a) +{ + double_bits fb; + fb.f = a; + int e = ((fb.u.s.high & 0x7FF00000) >> 20) - 1023; + if (e < 0 || (fb.u.s.high & 0x80000000)) + return 0; + tu_int r = 0x0010000000000000uLL | (fb.u.all & 0x000FFFFFFFFFFFFFuLL); + if (e > 52) + r <<= (e - 52); + else + r >>= (52 - e); + return r; +} + +#endif diff --git a/lib/builtins/fixunssfdi.c b/lib/builtins/fixunssfdi.c new file mode 100644 index 000000000..69d5952e9 --- /dev/null +++ b/lib/builtins/fixunssfdi.c @@ -0,0 +1,44 @@ +/* ===-- fixunssfdi.c - Implement __fixunssfdi -----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixunssfdi for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" +/* Returns: convert a to a unsigned long long, rounding toward zero. + * Negative values all become zero. + */ + +/* Assumption: float is a IEEE 32 bit floating point type + * du_int is a 64 bit integral type + * value in float is representable in du_int or is negative + * (no range checking performed) + */ + +/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */ + +ARM_EABI_FNALIAS(f2ulz, fixunssfdi) + +COMPILER_RT_ABI du_int +__fixunssfdi(float a) +{ + float_bits fb; + fb.f = a; + int e = ((fb.u & 0x7F800000) >> 23) - 127; + if (e < 0 || (fb.u & 0x80000000)) + return 0; + du_int r = (fb.u & 0x007FFFFF) | 0x00800000; + if (e > 23) + r <<= (e - 23); + else + r >>= (23 - e); + return r; +} diff --git a/lib/builtins/fixunssfsi.c b/lib/builtins/fixunssfsi.c new file mode 100644 index 000000000..e034139ea --- /dev/null +++ b/lib/builtins/fixunssfsi.c @@ -0,0 +1,45 @@ +/* ===-- fixunssfsi.c - Implement __fixunssfsi -----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixunssfsi for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: convert a to a unsigned int, rounding toward zero. + * Negative values all become zero. + */ + +/* Assumption: float is a IEEE 32 bit floating point type + * su_int is a 32 bit integral type + * value in float is representable in su_int or is negative + * (no range checking performed) + */ + +/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */ + +ARM_EABI_FNALIAS(f2uiz, fixunssfsi) + +COMPILER_RT_ABI su_int +__fixunssfsi(float a) +{ + float_bits fb; + fb.f = a; + int e = ((fb.u & 0x7F800000) >> 23) - 127; + if (e < 0 || (fb.u & 0x80000000)) + return 0; + su_int r = (fb.u & 0x007FFFFF) | 0x00800000; + if (e > 23) + r <<= (e - 23); + else + r >>= (23 - e); + return r; +} diff --git a/lib/builtins/fixunssfti.c b/lib/builtins/fixunssfti.c new file mode 100644 index 000000000..8f4c62627 --- /dev/null +++ b/lib/builtins/fixunssfti.c @@ -0,0 +1,47 @@ +/* ===-- fixunssfti.c - Implement __fixunssfti -----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixunssfti for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: convert a to a unsigned long long, rounding toward zero. + * Negative values all become zero. + */ + +/* Assumption: float is a IEEE 32 bit floating point type + * tu_int is a 64 bit integral type + * value in float is representable in tu_int or is negative + * (no range checking performed) + */ + +/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */ + +tu_int +__fixunssfti(float a) +{ + float_bits fb; + fb.f = a; + int e = ((fb.u & 0x7F800000) >> 23) - 127; + if (e < 0 || (fb.u & 0x80000000)) + return 0; + tu_int r = (fb.u & 0x007FFFFF) | 0x00800000; + if (e > 23) + r <<= (e - 23); + else + r >>= (23 - e); + return r; +} + +#endif diff --git a/lib/builtins/fixunsxfdi.c b/lib/builtins/fixunsxfdi.c new file mode 100644 index 000000000..6c817d8e1 --- /dev/null +++ b/lib/builtins/fixunsxfdi.c @@ -0,0 +1,44 @@ +/* ===-- fixunsxfdi.c - Implement __fixunsxfdi -----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixunsxfdi for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if !_ARCH_PPC + +#include "int_lib.h" + +/* Returns: convert a to a unsigned long long, rounding toward zero. + * Negative values all become zero. + */ + +/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes + * du_int is a 64 bit integral type + * value in long double is representable in du_int or is negative + * (no range checking performed) + */ + +/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee | + * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm + */ + +du_int +__fixunsxfdi(long double a) +{ + long_double_bits fb; + fb.f = a; + int e = (fb.u.high.s.low & 0x00007FFF) - 16383; + if (e < 0 || (fb.u.high.s.low & 0x00008000)) + return 0; + return fb.u.low.all >> (63 - e); +} + +#endif diff --git a/lib/builtins/fixunsxfsi.c b/lib/builtins/fixunsxfsi.c new file mode 100644 index 000000000..b9da86c4f --- /dev/null +++ b/lib/builtins/fixunsxfsi.c @@ -0,0 +1,44 @@ +/* ===-- fixunsxfsi.c - Implement __fixunsxfsi -----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixunsxfsi for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if !_ARCH_PPC + +#include "int_lib.h" + +/* Returns: convert a to a unsigned int, rounding toward zero. + * Negative values all become zero. + */ + +/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes + * su_int is a 32 bit integral type + * value in long double is representable in su_int or is negative + * (no range checking performed) + */ + +/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee | + * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm + */ + +su_int +__fixunsxfsi(long double a) +{ + long_double_bits fb; + fb.f = a; + int e = (fb.u.high.s.low & 0x00007FFF) - 16383; + if (e < 0 || (fb.u.high.s.low & 0x00008000)) + return 0; + return fb.u.low.s.high >> (31 - e); +} + +#endif /* !_ARCH_PPC */ diff --git a/lib/builtins/fixunsxfti.c b/lib/builtins/fixunsxfti.c new file mode 100644 index 000000000..260bfc01f --- /dev/null +++ b/lib/builtins/fixunsxfti.c @@ -0,0 +1,49 @@ +/* ===-- fixunsxfti.c - Implement __fixunsxfti -----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixunsxfti for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: convert a to a unsigned long long, rounding toward zero. + * Negative values all become zero. + */ + +/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes + * tu_int is a 64 bit integral type + * value in long double is representable in tu_int or is negative + * (no range checking performed) + */ + +/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee | + * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm + */ + +tu_int +__fixunsxfti(long double a) +{ + long_double_bits fb; + fb.f = a; + int e = (fb.u.high.s.low & 0x00007FFF) - 16383; + if (e < 0 || (fb.u.high.s.low & 0x00008000)) + return 0; + tu_int r = fb.u.low.all; + if (e > 63) + r <<= (e - 63); + else + r >>= (63 - e); + return r; +} + +#endif diff --git a/lib/builtins/fixxfdi.c b/lib/builtins/fixxfdi.c new file mode 100644 index 000000000..9592ce430 --- /dev/null +++ b/lib/builtins/fixxfdi.c @@ -0,0 +1,44 @@ +/* ===-- fixxfdi.c - Implement __fixxfdi -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixxfdi for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if !_ARCH_PPC + +#include "int_lib.h" + +/* Returns: convert a to a signed long long, rounding toward zero. */ + +/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes + * su_int is a 32 bit integral type + * value in long double is representable in di_int (no range checking performed) + */ + +/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee | + * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm + */ + +di_int +__fixxfdi(long double a) +{ + long_double_bits fb; + fb.f = a; + int e = (fb.u.high.s.low & 0x00007FFF) - 16383; + if (e < 0) + return 0; + di_int s = -(si_int)((fb.u.high.s.low & 0x00008000) >> 15); + di_int r = fb.u.low.all; + r = (du_int)r >> (63 - e); + return (r ^ s) - s; +} + +#endif /* !_ARCH_PPC */ diff --git a/lib/builtins/fixxfti.c b/lib/builtins/fixxfti.c new file mode 100644 index 000000000..973dc31bf --- /dev/null +++ b/lib/builtins/fixxfti.c @@ -0,0 +1,47 @@ +/* ===-- fixxfti.c - Implement __fixxfti -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __fixxfti for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: convert a to a signed long long, rounding toward zero. */ + +/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes + * su_int is a 32 bit integral type + * value in long double is representable in ti_int (no range checking performed) + */ + +/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee | + * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm + */ + +ti_int +__fixxfti(long double a) +{ + long_double_bits fb; + fb.f = a; + int e = (fb.u.high.s.low & 0x00007FFF) - 16383; + if (e < 0) + return 0; + ti_int s = -(si_int)((fb.u.high.s.low & 0x00008000) >> 15); + ti_int r = fb.u.low.all; + if (e > 63) + r <<= (e - 63); + else + r >>= (63 - e); + return (r ^ s) - s; +} + +#endif /* __x86_64 */ diff --git a/lib/builtins/floatdidf.c b/lib/builtins/floatdidf.c new file mode 100644 index 000000000..e53fa2580 --- /dev/null +++ b/lib/builtins/floatdidf.c @@ -0,0 +1,107 @@ +/*===-- floatdidf.c - Implement __floatdidf -------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + *===----------------------------------------------------------------------=== + * + * This file implements __floatdidf for the compiler_rt library. + * + *===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: convert a to a double, rounding toward even. */ + +/* Assumption: double is a IEEE 64 bit floating point type + * di_int is a 64 bit integral type + */ + +/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ + +ARM_EABI_FNALIAS(l2d, floatdidf) + +#ifndef __SOFT_FP__ +/* Support for systems that have hardware floating-point; we'll set the inexact flag + * as a side-effect of this computation. + */ + +COMPILER_RT_ABI double +__floatdidf(di_int a) +{ + static const double twop52 = 0x1.0p52; + static const double twop32 = 0x1.0p32; + + union { int64_t x; double d; } low = { .d = twop52 }; + + const double high = (int32_t)(a >> 32) * twop32; + low.x |= a & INT64_C(0x00000000ffffffff); + + const double result = (high - twop52) + low.d; + return result; +} + +#else +/* Support for systems that don't have hardware floating-point; there are no flags to + * set, and we don't want to code-gen to an unknown soft-float implementation. + */ + +COMPILER_RT_ABI double +__floatdidf(di_int a) +{ + if (a == 0) + return 0.0; + const unsigned N = sizeof(di_int) * CHAR_BIT; + const di_int s = a >> (N-1); + a = (a ^ s) - s; + int sd = N - __builtin_clzll(a); /* number of significant digits */ + int e = sd - 1; /* exponent */ + if (sd > DBL_MANT_DIG) + { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit DBL_MANT_DIG-1 bits to the right of 1 + * Q = bit DBL_MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + switch (sd) + { + case DBL_MANT_DIG + 1: + a <<= 1; + break; + case DBL_MANT_DIG + 2: + break; + default: + a = ((du_int)a >> (sd - (DBL_MANT_DIG+2))) | + ((a & ((du_int)(-1) >> ((N + DBL_MANT_DIG+2) - sd))) != 0); + }; + /* finish: */ + a |= (a & 4) != 0; /* Or P into R */ + ++a; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + /* a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits */ + if (a & ((du_int)1 << DBL_MANT_DIG)) + { + a >>= 1; + ++e; + } + /* a is now rounded to DBL_MANT_DIG bits */ + } + else + { + a <<= (DBL_MANT_DIG - sd); + /* a is now rounded to DBL_MANT_DIG bits */ + } + double_bits fb; + fb.u.high = ((su_int)s & 0x80000000) | /* sign */ + ((e + 1023) << 20) | /* exponent */ + ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */ + fb.u.low = (su_int)a; /* mantissa-low */ + return fb.f; +} +#endif diff --git a/lib/builtins/floatdisf.c b/lib/builtins/floatdisf.c new file mode 100644 index 000000000..3e47580ef --- /dev/null +++ b/lib/builtins/floatdisf.c @@ -0,0 +1,80 @@ +/*===-- floatdisf.c - Implement __floatdisf -------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + *===----------------------------------------------------------------------=== + * + * This file implements __floatdisf for the compiler_rt library. + * + *===----------------------------------------------------------------------=== + */ + +/* Returns: convert a to a float, rounding toward even.*/ + +/* Assumption: float is a IEEE 32 bit floating point type + * di_int is a 64 bit integral type + */ + +/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */ + +#include "int_lib.h" + +ARM_EABI_FNALIAS(l2f, floatdisf) + +COMPILER_RT_ABI float +__floatdisf(di_int a) +{ + if (a == 0) + return 0.0F; + const unsigned N = sizeof(di_int) * CHAR_BIT; + const di_int s = a >> (N-1); + a = (a ^ s) - s; + int sd = N - __builtin_clzll(a); /* number of significant digits */ + int e = sd - 1; /* exponent */ + if (sd > FLT_MANT_DIG) + { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit FLT_MANT_DIG-1 bits to the right of 1 + * Q = bit FLT_MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + switch (sd) + { + case FLT_MANT_DIG + 1: + a <<= 1; + break; + case FLT_MANT_DIG + 2: + break; + default: + a = ((du_int)a >> (sd - (FLT_MANT_DIG+2))) | + ((a & ((du_int)(-1) >> ((N + FLT_MANT_DIG+2) - sd))) != 0); + }; + /* finish: */ + a |= (a & 4) != 0; /* Or P into R */ + ++a; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + /* a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits */ + if (a & ((du_int)1 << FLT_MANT_DIG)) + { + a >>= 1; + ++e; + } + /* a is now rounded to FLT_MANT_DIG bits */ + } + else + { + a <<= (FLT_MANT_DIG - sd); + /* a is now rounded to FLT_MANT_DIG bits */ + } + float_bits fb; + fb.u = ((su_int)s & 0x80000000) | /* sign */ + ((e + 127) << 23) | /* exponent */ + ((su_int)a & 0x007FFFFF); /* mantissa */ + return fb.f; +} diff --git a/lib/builtins/floatdixf.c b/lib/builtins/floatdixf.c new file mode 100644 index 000000000..ebf62dba0 --- /dev/null +++ b/lib/builtins/floatdixf.c @@ -0,0 +1,46 @@ +/* ===-- floatdixf.c - Implement __floatdixf -------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __floatdixf for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if !_ARCH_PPC + +#include "int_lib.h" + +/* Returns: convert a to a long double, rounding toward even. */ + +/* Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits + * di_int is a 64 bit integral type + */ + +/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee | + * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm + */ + +long double +__floatdixf(di_int a) +{ + if (a == 0) + return 0.0; + const unsigned N = sizeof(di_int) * CHAR_BIT; + const di_int s = a >> (N-1); + a = (a ^ s) - s; + int clz = __builtin_clzll(a); + int e = (N - 1) - clz ; /* exponent */ + long_double_bits fb; + fb.u.high.s.low = ((su_int)s & 0x00008000) | /* sign */ + (e + 16383); /* exponent */ + fb.u.low.all = a << clz; /* mantissa */ + return fb.f; +} + +#endif /* !_ARCH_PPC */ diff --git a/lib/builtins/floatsidf.c b/lib/builtins/floatsidf.c new file mode 100644 index 000000000..18f378f2a --- /dev/null +++ b/lib/builtins/floatsidf.c @@ -0,0 +1,52 @@ +//===-- lib/floatsidf.c - integer -> double-precision conversion --*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements integer to double-precision conversion for the +// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even +// mode. +// +//===----------------------------------------------------------------------===// + +#define DOUBLE_PRECISION +#include "fp_lib.h" + +#include "int_lib.h" + +ARM_EABI_FNALIAS(i2d, floatsidf) + +fp_t __floatsidf(int a) { + + const int aWidth = sizeof a * CHAR_BIT; + + // Handle zero as a special case to protect clz + if (a == 0) + return fromRep(0); + + // All other cases begin by extracting the sign and absolute value of a + rep_t sign = 0; + if (a < 0) { + sign = signBit; + a = -a; + } + + // Exponent of (fp_t)a is the width of abs(a). + const int exponent = (aWidth - 1) - __builtin_clz(a); + rep_t result; + + // Shift a into the significand field and clear the implicit bit. Extra + // cast to unsigned int is necessary to get the correct behavior for + // the input INT_MIN. + const int shift = significandBits - exponent; + result = (rep_t)(unsigned int)a << shift ^ implicitBit; + + // Insert the exponent + result += (rep_t)(exponent + exponentBias) << significandBits; + // Insert the sign bit and return + return fromRep(result | sign); +} diff --git a/lib/builtins/floatsisf.c b/lib/builtins/floatsisf.c new file mode 100644 index 000000000..83983934f --- /dev/null +++ b/lib/builtins/floatsisf.c @@ -0,0 +1,58 @@ +//===-- lib/floatsisf.c - integer -> single-precision conversion --*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements integer to single-precision conversion for the +// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even +// mode. +// +//===----------------------------------------------------------------------===// + +#define SINGLE_PRECISION +#include "fp_lib.h" + +#include "int_lib.h" + +ARM_EABI_FNALIAS(i2f, floatsisf) + +fp_t __floatsisf(int a) { + + const int aWidth = sizeof a * CHAR_BIT; + + // Handle zero as a special case to protect clz + if (a == 0) + return fromRep(0); + + // All other cases begin by extracting the sign and absolute value of a + rep_t sign = 0; + if (a < 0) { + sign = signBit; + a = -a; + } + + // Exponent of (fp_t)a is the width of abs(a). + const int exponent = (aWidth - 1) - __builtin_clz(a); + rep_t result; + + // Shift a into the significand field, rounding if it is a right-shift + if (exponent <= significandBits) { + const int shift = significandBits - exponent; + result = (rep_t)a << shift ^ implicitBit; + } else { + const int shift = exponent - significandBits; + result = (rep_t)a >> shift ^ implicitBit; + rep_t round = (rep_t)a << (typeWidth - shift); + if (round > signBit) result++; + if (round == signBit) result += result & 1; + } + + // Insert the exponent + result += (rep_t)(exponent + exponentBias) << significandBits; + // Insert the sign bit and return + return fromRep(result | sign); +} diff --git a/lib/builtins/floattidf.c b/lib/builtins/floattidf.c new file mode 100644 index 000000000..77749f8d3 --- /dev/null +++ b/lib/builtins/floattidf.c @@ -0,0 +1,85 @@ +/* ===-- floattidf.c - Implement __floattidf -------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __floattidf for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: convert a to a double, rounding toward even.*/ + +/* Assumption: double is a IEEE 64 bit floating point type + * ti_int is a 128 bit integral type + */ + +/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ + +si_int __clzti2(ti_int a); + +double +__floattidf(ti_int a) +{ + if (a == 0) + return 0.0; + const unsigned N = sizeof(ti_int) * CHAR_BIT; + const ti_int s = a >> (N-1); + a = (a ^ s) - s; + int sd = N - __clzti2(a); /* number of significant digits */ + int e = sd - 1; /* exponent */ + if (sd > DBL_MANT_DIG) + { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit DBL_MANT_DIG-1 bits to the right of 1 + * Q = bit DBL_MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + switch (sd) + { + case DBL_MANT_DIG + 1: + a <<= 1; + break; + case DBL_MANT_DIG + 2: + break; + default: + a = ((tu_int)a >> (sd - (DBL_MANT_DIG+2))) | + ((a & ((tu_int)(-1) >> ((N + DBL_MANT_DIG+2) - sd))) != 0); + }; + /* finish: */ + a |= (a & 4) != 0; /* Or P into R */ + ++a; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + /* a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits */ + if (a & ((tu_int)1 << DBL_MANT_DIG)) + { + a >>= 1; + ++e; + } + /* a is now rounded to DBL_MANT_DIG bits */ + } + else + { + a <<= (DBL_MANT_DIG - sd); + /* a is now rounded to DBL_MANT_DIG bits */ + } + double_bits fb; + fb.u.s.high = ((su_int)s & 0x80000000) | /* sign */ + ((e + 1023) << 20) | /* exponent */ + ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */ + fb.u.s.low = (su_int)a; /* mantissa-low */ + return fb.f; +} + +#endif diff --git a/lib/builtins/floattisf.c b/lib/builtins/floattisf.c new file mode 100644 index 000000000..4776125de --- /dev/null +++ b/lib/builtins/floattisf.c @@ -0,0 +1,84 @@ +/* ===-- floattisf.c - Implement __floattisf -------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __floattisf for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: convert a to a float, rounding toward even. */ + +/* Assumption: float is a IEEE 32 bit floating point type + * ti_int is a 128 bit integral type + */ + +/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */ + +si_int __clzti2(ti_int a); + +float +__floattisf(ti_int a) +{ + if (a == 0) + return 0.0F; + const unsigned N = sizeof(ti_int) * CHAR_BIT; + const ti_int s = a >> (N-1); + a = (a ^ s) - s; + int sd = N - __clzti2(a); /* number of significant digits */ + int e = sd - 1; /* exponent */ + if (sd > FLT_MANT_DIG) + { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit FLT_MANT_DIG-1 bits to the right of 1 + * Q = bit FLT_MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + switch (sd) + { + case FLT_MANT_DIG + 1: + a <<= 1; + break; + case FLT_MANT_DIG + 2: + break; + default: + a = ((tu_int)a >> (sd - (FLT_MANT_DIG+2))) | + ((a & ((tu_int)(-1) >> ((N + FLT_MANT_DIG+2) - sd))) != 0); + }; + /* finish: */ + a |= (a & 4) != 0; /* Or P into R */ + ++a; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + /* a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits */ + if (a & ((tu_int)1 << FLT_MANT_DIG)) + { + a >>= 1; + ++e; + } + /* a is now rounded to FLT_MANT_DIG bits */ + } + else + { + a <<= (FLT_MANT_DIG - sd); + /* a is now rounded to FLT_MANT_DIG bits */ + } + float_bits fb; + fb.u = ((su_int)s & 0x80000000) | /* sign */ + ((e + 127) << 23) | /* exponent */ + ((su_int)a & 0x007FFFFF); /* mantissa */ + return fb.f; +} + +#endif diff --git a/lib/builtins/floattixf.c b/lib/builtins/floattixf.c new file mode 100644 index 000000000..3813dc6b7 --- /dev/null +++ b/lib/builtins/floattixf.c @@ -0,0 +1,86 @@ +/* ===-- floattixf.c - Implement __floattixf -------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __floattixf for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: convert a to a long double, rounding toward even. */ + +/* Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits + * ti_int is a 128 bit integral type + */ + +/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee | + * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm + */ + +si_int __clzti2(ti_int a); + +long double +__floattixf(ti_int a) +{ + if (a == 0) + return 0.0; + const unsigned N = sizeof(ti_int) * CHAR_BIT; + const ti_int s = a >> (N-1); + a = (a ^ s) - s; + int sd = N - __clzti2(a); /* number of significant digits */ + int e = sd - 1; /* exponent */ + if (sd > LDBL_MANT_DIG) + { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit LDBL_MANT_DIG-1 bits to the right of 1 + * Q = bit LDBL_MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + switch (sd) + { + case LDBL_MANT_DIG + 1: + a <<= 1; + break; + case LDBL_MANT_DIG + 2: + break; + default: + a = ((tu_int)a >> (sd - (LDBL_MANT_DIG+2))) | + ((a & ((tu_int)(-1) >> ((N + LDBL_MANT_DIG+2) - sd))) != 0); + }; + /* finish: */ + a |= (a & 4) != 0; /* Or P into R */ + ++a; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + /* a is now rounded to LDBL_MANT_DIG or LDBL_MANT_DIG+1 bits */ + if (a & ((tu_int)1 << LDBL_MANT_DIG)) + { + a >>= 1; + ++e; + } + /* a is now rounded to LDBL_MANT_DIG bits */ + } + else + { + a <<= (LDBL_MANT_DIG - sd); + /* a is now rounded to LDBL_MANT_DIG bits */ + } + long_double_bits fb; + fb.u.high.s.low = ((su_int)s & 0x8000) | /* sign */ + (e + 16383); /* exponent */ + fb.u.low.all = (du_int)a; /* mantissa */ + return fb.f; +} + +#endif diff --git a/lib/builtins/floatundidf.c b/lib/builtins/floatundidf.c new file mode 100644 index 000000000..e52fa0a33 --- /dev/null +++ b/lib/builtins/floatundidf.c @@ -0,0 +1,107 @@ +/* ===-- floatundidf.c - Implement __floatundidf ---------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __floatundidf for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +/* Returns: convert a to a double, rounding toward even. */ + +/* Assumption: double is a IEEE 64 bit floating point type + * du_int is a 64 bit integral type + */ + +/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ + +#include "int_lib.h" + +ARM_EABI_FNALIAS(ul2d, floatundidf) + +#ifndef __SOFT_FP__ +/* Support for systems that have hardware floating-point; we'll set the inexact flag + * as a side-effect of this computation. + */ + + +COMPILER_RT_ABI double +__floatundidf(du_int a) +{ + static const double twop52 = 0x1.0p52; + static const double twop84 = 0x1.0p84; + static const double twop84_plus_twop52 = 0x1.00000001p84; + + union { uint64_t x; double d; } high = { .d = twop84 }; + union { uint64_t x; double d; } low = { .d = twop52 }; + + high.x |= a >> 32; + low.x |= a & UINT64_C(0x00000000ffffffff); + + const double result = (high.d - twop84_plus_twop52) + low.d; + return result; +} + +#else +/* Support for systems that don't have hardware floating-point; there are no flags to + * set, and we don't want to code-gen to an unknown soft-float implementation. + */ + +COMPILER_RT_ABI double +__floatundidf(du_int a) +{ + if (a == 0) + return 0.0; + const unsigned N = sizeof(du_int) * CHAR_BIT; + int sd = N - __builtin_clzll(a); /* number of significant digits */ + int e = sd - 1; /* exponent */ + if (sd > DBL_MANT_DIG) + { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit DBL_MANT_DIG-1 bits to the right of 1 + * Q = bit DBL_MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + switch (sd) + { + case DBL_MANT_DIG + 1: + a <<= 1; + break; + case DBL_MANT_DIG + 2: + break; + default: + a = (a >> (sd - (DBL_MANT_DIG+2))) | + ((a & ((du_int)(-1) >> ((N + DBL_MANT_DIG+2) - sd))) != 0); + }; + /* finish: */ + a |= (a & 4) != 0; /* Or P into R */ + ++a; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + /* a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits */ + if (a & ((du_int)1 << DBL_MANT_DIG)) + { + a >>= 1; + ++e; + } + /* a is now rounded to DBL_MANT_DIG bits */ + } + else + { + a <<= (DBL_MANT_DIG - sd); + /* a is now rounded to DBL_MANT_DIG bits */ + } + double_bits fb; + fb.u.high = ((e + 1023) << 20) | /* exponent */ + ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */ + fb.u.low = (su_int)a; /* mantissa-low */ + return fb.f; +} +#endif diff --git a/lib/builtins/floatundisf.c b/lib/builtins/floatundisf.c new file mode 100644 index 000000000..713a44abc --- /dev/null +++ b/lib/builtins/floatundisf.c @@ -0,0 +1,77 @@ +/*===-- floatundisf.c - Implement __floatundisf ---------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __floatundisf for the compiler_rt library. + * + *===----------------------------------------------------------------------=== + */ + +/* Returns: convert a to a float, rounding toward even. */ + +/* Assumption: float is a IEEE 32 bit floating point type + * du_int is a 64 bit integral type + */ + +/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */ + +#include "int_lib.h" + +ARM_EABI_FNALIAS(ul2f, floatundisf) + +COMPILER_RT_ABI float +__floatundisf(du_int a) +{ + if (a == 0) + return 0.0F; + const unsigned N = sizeof(du_int) * CHAR_BIT; + int sd = N - __builtin_clzll(a); /* number of significant digits */ + int e = sd - 1; /* 8 exponent */ + if (sd > FLT_MANT_DIG) + { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit FLT_MANT_DIG-1 bits to the right of 1 + * Q = bit FLT_MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + switch (sd) + { + case FLT_MANT_DIG + 1: + a <<= 1; + break; + case FLT_MANT_DIG + 2: + break; + default: + a = (a >> (sd - (FLT_MANT_DIG+2))) | + ((a & ((du_int)(-1) >> ((N + FLT_MANT_DIG+2) - sd))) != 0); + }; + /* finish: */ + a |= (a & 4) != 0; /* Or P into R */ + ++a; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + /* a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits */ + if (a & ((du_int)1 << FLT_MANT_DIG)) + { + a >>= 1; + ++e; + } + /* a is now rounded to FLT_MANT_DIG bits */ + } + else + { + a <<= (FLT_MANT_DIG - sd); + /* a is now rounded to FLT_MANT_DIG bits */ + } + float_bits fb; + fb.u = ((e + 127) << 23) | /* exponent */ + ((su_int)a & 0x007FFFFF); /* mantissa */ + return fb.f; +} diff --git a/lib/builtins/floatundixf.c b/lib/builtins/floatundixf.c new file mode 100644 index 000000000..64f7662d9 --- /dev/null +++ b/lib/builtins/floatundixf.c @@ -0,0 +1,42 @@ +/* ===-- floatundixf.c - Implement __floatundixf ---------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __floatundixf for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if !_ARCH_PPC + +#include "int_lib.h" + +/* Returns: convert a to a long double, rounding toward even. */ + +/* Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits + * du_int is a 64 bit integral type + */ + +/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee | + * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm + */ +long double +__floatundixf(du_int a) +{ + if (a == 0) + return 0.0; + const unsigned N = sizeof(du_int) * CHAR_BIT; + int clz = __builtin_clzll(a); + int e = (N - 1) - clz ; /* exponent */ + long_double_bits fb; + fb.u.high.s.low = (e + 16383); /* exponent */ + fb.u.low.all = a << clz; /* mantissa */ + return fb.f; +} + +#endif /* _ARCH_PPC */ diff --git a/lib/builtins/floatunsidf.c b/lib/builtins/floatunsidf.c new file mode 100644 index 000000000..ba6c2cfd2 --- /dev/null +++ b/lib/builtins/floatunsidf.c @@ -0,0 +1,41 @@ +//===-- lib/floatunsidf.c - uint -> double-precision conversion ---*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements unsigned integer to double-precision conversion for the +// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even +// mode. +// +//===----------------------------------------------------------------------===// + +#define DOUBLE_PRECISION +#include "fp_lib.h" + +#include "int_lib.h" + +ARM_EABI_FNALIAS(ui2d, floatunsidf) + +fp_t __floatunsidf(unsigned int a) { + + const int aWidth = sizeof a * CHAR_BIT; + + // Handle zero as a special case to protect clz + if (a == 0) return fromRep(0); + + // Exponent of (fp_t)a is the width of abs(a). + const int exponent = (aWidth - 1) - __builtin_clz(a); + rep_t result; + + // Shift a into the significand field and clear the implicit bit. + const int shift = significandBits - exponent; + result = (rep_t)a << shift ^ implicitBit; + + // Insert the exponent + result += (rep_t)(exponent + exponentBias) << significandBits; + return fromRep(result); +} diff --git a/lib/builtins/floatunsisf.c b/lib/builtins/floatunsisf.c new file mode 100644 index 000000000..e392c0ecf --- /dev/null +++ b/lib/builtins/floatunsisf.c @@ -0,0 +1,49 @@ +//===-- lib/floatunsisf.c - uint -> single-precision conversion ---*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements unsigned integer to single-precision conversion for the +// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even +// mode. +// +//===----------------------------------------------------------------------===// + +#define SINGLE_PRECISION +#include "fp_lib.h" + +#include "int_lib.h" + +ARM_EABI_FNALIAS(ui2f, floatunsisf) + +fp_t __floatunsisf(unsigned int a) { + + const int aWidth = sizeof a * CHAR_BIT; + + // Handle zero as a special case to protect clz + if (a == 0) return fromRep(0); + + // Exponent of (fp_t)a is the width of abs(a). + const int exponent = (aWidth - 1) - __builtin_clz(a); + rep_t result; + + // Shift a into the significand field, rounding if it is a right-shift + if (exponent <= significandBits) { + const int shift = significandBits - exponent; + result = (rep_t)a << shift ^ implicitBit; + } else { + const int shift = exponent - significandBits; + result = (rep_t)a >> shift ^ implicitBit; + rep_t round = (rep_t)a << (typeWidth - shift); + if (round > signBit) result++; + if (round == signBit) result += result & 1; + } + + // Insert the exponent + result += (rep_t)(exponent + exponentBias) << significandBits; + return fromRep(result); +} diff --git a/lib/builtins/floatuntidf.c b/lib/builtins/floatuntidf.c new file mode 100644 index 000000000..4c1d3289f --- /dev/null +++ b/lib/builtins/floatuntidf.c @@ -0,0 +1,82 @@ +/* ===-- floatuntidf.c - Implement __floatuntidf ---------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __floatuntidf for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: convert a to a double, rounding toward even. */ + +/* Assumption: double is a IEEE 64 bit floating point type + * tu_int is a 128 bit integral type + */ + +/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */ + +si_int __clzti2(ti_int a); + +double +__floatuntidf(tu_int a) +{ + if (a == 0) + return 0.0; + const unsigned N = sizeof(tu_int) * CHAR_BIT; + int sd = N - __clzti2(a); /* number of significant digits */ + int e = sd - 1; /* exponent */ + if (sd > DBL_MANT_DIG) + { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit DBL_MANT_DIG-1 bits to the right of 1 + * Q = bit DBL_MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + switch (sd) + { + case DBL_MANT_DIG + 1: + a <<= 1; + break; + case DBL_MANT_DIG + 2: + break; + default: + a = (a >> (sd - (DBL_MANT_DIG+2))) | + ((a & ((tu_int)(-1) >> ((N + DBL_MANT_DIG+2) - sd))) != 0); + }; + /* finish: */ + a |= (a & 4) != 0; /* Or P into R */ + ++a; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + /* a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits */ + if (a & ((tu_int)1 << DBL_MANT_DIG)) + { + a >>= 1; + ++e; + } + /* a is now rounded to DBL_MANT_DIG bits */ + } + else + { + a <<= (DBL_MANT_DIG - sd); + /* a is now rounded to DBL_MANT_DIG bits */ + } + double_bits fb; + fb.u.s.high = ((e + 1023) << 20) | /* exponent */ + ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */ + fb.u.s.low = (su_int)a; /* mantissa-low */ + return fb.f; +} + +#endif diff --git a/lib/builtins/floatuntisf.c b/lib/builtins/floatuntisf.c new file mode 100644 index 000000000..c8da2601b --- /dev/null +++ b/lib/builtins/floatuntisf.c @@ -0,0 +1,81 @@ +/* ===-- floatuntisf.c - Implement __floatuntisf ---------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __floatuntisf for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: convert a to a float, rounding toward even. */ + +/* Assumption: float is a IEEE 32 bit floating point type + * tu_int is a 128 bit integral type + */ + +/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */ + +si_int __clzti2(ti_int a); + +float +__floatuntisf(tu_int a) +{ + if (a == 0) + return 0.0F; + const unsigned N = sizeof(tu_int) * CHAR_BIT; + int sd = N - __clzti2(a); /* number of significant digits */ + int e = sd - 1; /* exponent */ + if (sd > FLT_MANT_DIG) + { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit FLT_MANT_DIG-1 bits to the right of 1 + * Q = bit FLT_MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + switch (sd) + { + case FLT_MANT_DIG + 1: + a <<= 1; + break; + case FLT_MANT_DIG + 2: + break; + default: + a = (a >> (sd - (FLT_MANT_DIG+2))) | + ((a & ((tu_int)(-1) >> ((N + FLT_MANT_DIG+2) - sd))) != 0); + }; + /* finish: */ + a |= (a & 4) != 0; /* Or P into R */ + ++a; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + /* a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits */ + if (a & ((tu_int)1 << FLT_MANT_DIG)) + { + a >>= 1; + ++e; + } + /* a is now rounded to FLT_MANT_DIG bits */ + } + else + { + a <<= (FLT_MANT_DIG - sd); + /* a is now rounded to FLT_MANT_DIG bits */ + } + float_bits fb; + fb.u = ((e + 127) << 23) | /* exponent */ + ((su_int)a & 0x007FFFFF); /* mantissa */ + return fb.f; +} + +#endif diff --git a/lib/builtins/floatuntixf.c b/lib/builtins/floatuntixf.c new file mode 100644 index 000000000..dbce80f16 --- /dev/null +++ b/lib/builtins/floatuntixf.c @@ -0,0 +1,83 @@ +/* ===-- floatuntixf.c - Implement __floatuntixf ---------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __floatuntixf for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: convert a to a long double, rounding toward even. */ + +/* Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits + * tu_int is a 128 bit integral type + */ + +/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee | + * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm + */ + +si_int __clzti2(ti_int a); + +long double +__floatuntixf(tu_int a) +{ + if (a == 0) + return 0.0; + const unsigned N = sizeof(tu_int) * CHAR_BIT; + int sd = N - __clzti2(a); /* number of significant digits */ + int e = sd - 1; /* exponent */ + if (sd > LDBL_MANT_DIG) + { + /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + * 12345678901234567890123456 + * 1 = msb 1 bit + * P = bit LDBL_MANT_DIG-1 bits to the right of 1 + * Q = bit LDBL_MANT_DIG bits to the right of 1 + * R = "or" of all bits to the right of Q + */ + switch (sd) + { + case LDBL_MANT_DIG + 1: + a <<= 1; + break; + case LDBL_MANT_DIG + 2: + break; + default: + a = (a >> (sd - (LDBL_MANT_DIG+2))) | + ((a & ((tu_int)(-1) >> ((N + LDBL_MANT_DIG+2) - sd))) != 0); + }; + /* finish: */ + a |= (a & 4) != 0; /* Or P into R */ + ++a; /* round - this step may add a significant bit */ + a >>= 2; /* dump Q and R */ + /* a is now rounded to LDBL_MANT_DIG or LDBL_MANT_DIG+1 bits */ + if (a & ((tu_int)1 << LDBL_MANT_DIG)) + { + a >>= 1; + ++e; + } + /* a is now rounded to LDBL_MANT_DIG bits */ + } + else + { + a <<= (LDBL_MANT_DIG - sd); + /* a is now rounded to LDBL_MANT_DIG bits */ + } + long_double_bits fb; + fb.u.high.s.low = (e + 16383); /* exponent */ + fb.u.low.all = (du_int)a; /* mantissa */ + return fb.f; +} + +#endif diff --git a/lib/builtins/fp_lib.h b/lib/builtins/fp_lib.h new file mode 100644 index 000000000..661119ae4 --- /dev/null +++ b/lib/builtins/fp_lib.h @@ -0,0 +1,144 @@ +//===-- lib/fp_lib.h - Floating-point utilities -------------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a configuration header for soft-float routines in compiler-rt. +// This file does not provide any part of the compiler-rt interface, but defines +// many useful constants and utility routines that are used in the +// implementation of the soft-float routines in compiler-rt. +// +// Assumes that float and double correspond to the IEEE-754 binary32 and +// binary64 types, respectively, and that integer endianness matches floating +// point endianness on the target platform. +// +//===----------------------------------------------------------------------===// + +#ifndef FP_LIB_HEADER +#define FP_LIB_HEADER + +#include <stdint.h> +#include <stdbool.h> +#include <limits.h> +#include "int_lib.h" + +#if defined SINGLE_PRECISION + +typedef uint32_t rep_t; +typedef int32_t srep_t; +typedef float fp_t; +#define REP_C UINT32_C +#define significandBits 23 + +static inline int rep_clz(rep_t a) { + return __builtin_clz(a); +} + +// 32x32 --> 64 bit multiply +static inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) { + const uint64_t product = (uint64_t)a*b; + *hi = product >> 32; + *lo = product; +} + +#elif defined DOUBLE_PRECISION + +typedef uint64_t rep_t; +typedef int64_t srep_t; +typedef double fp_t; +#define REP_C UINT64_C +#define significandBits 52 + +static inline int rep_clz(rep_t a) { +#if defined __LP64__ + return __builtin_clzl(a); +#else + if (a & REP_C(0xffffffff00000000)) + return __builtin_clz(a >> 32); + else + return 32 + __builtin_clz(a & REP_C(0xffffffff)); +#endif +} + +#define loWord(a) (a & 0xffffffffU) +#define hiWord(a) (a >> 32) + +// 64x64 -> 128 wide multiply for platforms that don't have such an operation; +// many 64-bit platforms have this operation, but they tend to have hardware +// floating-point, so we don't bother with a special case for them here. +static inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) { + // Each of the component 32x32 -> 64 products + const uint64_t plolo = loWord(a) * loWord(b); + const uint64_t plohi = loWord(a) * hiWord(b); + const uint64_t philo = hiWord(a) * loWord(b); + const uint64_t phihi = hiWord(a) * hiWord(b); + // Sum terms that contribute to lo in a way that allows us to get the carry + const uint64_t r0 = loWord(plolo); + const uint64_t r1 = hiWord(plolo) + loWord(plohi) + loWord(philo); + *lo = r0 + (r1 << 32); + // Sum terms contributing to hi with the carry from lo + *hi = hiWord(plohi) + hiWord(philo) + hiWord(r1) + phihi; +} + +#else +#error Either SINGLE_PRECISION or DOUBLE_PRECISION must be defined. +#endif + +#define typeWidth (sizeof(rep_t)*CHAR_BIT) +#define exponentBits (typeWidth - significandBits - 1) +#define maxExponent ((1 << exponentBits) - 1) +#define exponentBias (maxExponent >> 1) + +#define implicitBit (REP_C(1) << significandBits) +#define significandMask (implicitBit - 1U) +#define signBit (REP_C(1) << (significandBits + exponentBits)) +#define absMask (signBit - 1U) +#define exponentMask (absMask ^ significandMask) +#define oneRep ((rep_t)exponentBias << significandBits) +#define infRep exponentMask +#define quietBit (implicitBit >> 1) +#define qnanRep (exponentMask | quietBit) + +static inline rep_t toRep(fp_t x) { + const union { fp_t f; rep_t i; } rep = {.f = x}; + return rep.i; +} + +static inline fp_t fromRep(rep_t x) { + const union { fp_t f; rep_t i; } rep = {.i = x}; + return rep.f; +} + +static inline int normalize(rep_t *significand) { + const int shift = rep_clz(*significand) - rep_clz(implicitBit); + *significand <<= shift; + return 1 - shift; +} + +static inline void wideLeftShift(rep_t *hi, rep_t *lo, int count) { + *hi = *hi << count | *lo >> (typeWidth - count); + *lo = *lo << count; +} + +static inline void wideRightShiftWithSticky(rep_t *hi, rep_t *lo, unsigned int count) { + if (count < typeWidth) { + const bool sticky = *lo << (typeWidth - count); + *lo = *hi << (typeWidth - count) | *lo >> count | sticky; + *hi = *hi >> count; + } + else if (count < 2*typeWidth) { + const bool sticky = *hi << (2*typeWidth - count) | *lo; + *lo = *hi >> (count - typeWidth) | sticky; + *hi = 0; + } else { + const bool sticky = *hi | *lo; + *lo = sticky; + *hi = 0; + } +} + +#endif // FP_LIB_HEADER diff --git a/lib/builtins/gcc_personality_v0.c b/lib/builtins/gcc_personality_v0.c new file mode 100644 index 000000000..8a708cae5 --- /dev/null +++ b/lib/builtins/gcc_personality_v0.c @@ -0,0 +1,247 @@ +/* ===-- gcc_personality_v0.c - Implement __gcc_personality_v0 -------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + */ + +#include "int_lib.h" + +/* + * _Unwind_* stuff based on C++ ABI public documentation + * http://refspecs.freestandards.org/abi-eh-1.21.html + */ + +typedef enum { + _URC_NO_REASON = 0, + _URC_FOREIGN_EXCEPTION_CAUGHT = 1, + _URC_FATAL_PHASE2_ERROR = 2, + _URC_FATAL_PHASE1_ERROR = 3, + _URC_NORMAL_STOP = 4, + _URC_END_OF_STACK = 5, + _URC_HANDLER_FOUND = 6, + _URC_INSTALL_CONTEXT = 7, + _URC_CONTINUE_UNWIND = 8 +} _Unwind_Reason_Code; + +typedef enum { + _UA_SEARCH_PHASE = 1, + _UA_CLEANUP_PHASE = 2, + _UA_HANDLER_FRAME = 4, + _UA_FORCE_UNWIND = 8, + _UA_END_OF_STACK = 16 +} _Unwind_Action; + +typedef struct _Unwind_Context* _Unwind_Context_t; + +struct _Unwind_Exception { + uint64_t exception_class; + void (*exception_cleanup)(_Unwind_Reason_Code reason, + struct _Unwind_Exception* exc); + uintptr_t private_1; + uintptr_t private_2; +}; + +extern const uint8_t* _Unwind_GetLanguageSpecificData(_Unwind_Context_t c); +extern void _Unwind_SetGR(_Unwind_Context_t c, int i, uintptr_t n); +extern void _Unwind_SetIP(_Unwind_Context_t, uintptr_t new_value); +extern uintptr_t _Unwind_GetIP(_Unwind_Context_t context); +extern uintptr_t _Unwind_GetRegionStart(_Unwind_Context_t context); + + +/* + * Pointer encodings documented at: + * http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html + */ + +#define DW_EH_PE_omit 0xff /* no data follows */ + +#define DW_EH_PE_absptr 0x00 +#define DW_EH_PE_uleb128 0x01 +#define DW_EH_PE_udata2 0x02 +#define DW_EH_PE_udata4 0x03 +#define DW_EH_PE_udata8 0x04 +#define DW_EH_PE_sleb128 0x09 +#define DW_EH_PE_sdata2 0x0A +#define DW_EH_PE_sdata4 0x0B +#define DW_EH_PE_sdata8 0x0C + +#define DW_EH_PE_pcrel 0x10 +#define DW_EH_PE_textrel 0x20 +#define DW_EH_PE_datarel 0x30 +#define DW_EH_PE_funcrel 0x40 +#define DW_EH_PE_aligned 0x50 +#define DW_EH_PE_indirect 0x80 /* gcc extension */ + + + +/* read a uleb128 encoded value and advance pointer */ +static uintptr_t readULEB128(const uint8_t** data) +{ + uintptr_t result = 0; + uintptr_t shift = 0; + unsigned char byte; + const uint8_t* p = *data; + do { + byte = *p++; + result |= (byte & 0x7f) << shift; + shift += 7; + } while (byte & 0x80); + *data = p; + return result; +} + +/* read a pointer encoded value and advance pointer */ +static uintptr_t readEncodedPointer(const uint8_t** data, uint8_t encoding) +{ + const uint8_t* p = *data; + uintptr_t result = 0; + + if ( encoding == DW_EH_PE_omit ) + return 0; + + /* first get value */ + switch (encoding & 0x0F) { + case DW_EH_PE_absptr: + result = *((uintptr_t*)p); + p += sizeof(uintptr_t); + break; + case DW_EH_PE_uleb128: + result = readULEB128(&p); + break; + case DW_EH_PE_udata2: + result = *((uint16_t*)p); + p += sizeof(uint16_t); + break; + case DW_EH_PE_udata4: + result = *((uint32_t*)p); + p += sizeof(uint32_t); + break; + case DW_EH_PE_udata8: + result = *((uint64_t*)p); + p += sizeof(uint64_t); + break; + case DW_EH_PE_sdata2: + result = *((int16_t*)p); + p += sizeof(int16_t); + break; + case DW_EH_PE_sdata4: + result = *((int32_t*)p); + p += sizeof(int32_t); + break; + case DW_EH_PE_sdata8: + result = *((int64_t*)p); + p += sizeof(int64_t); + break; + case DW_EH_PE_sleb128: + default: + /* not supported */ + compilerrt_abort(); + break; + } + + /* then add relative offset */ + switch ( encoding & 0x70 ) { + case DW_EH_PE_absptr: + /* do nothing */ + break; + case DW_EH_PE_pcrel: + result += (uintptr_t)(*data); + break; + case DW_EH_PE_textrel: + case DW_EH_PE_datarel: + case DW_EH_PE_funcrel: + case DW_EH_PE_aligned: + default: + /* not supported */ + compilerrt_abort(); + break; + } + + /* then apply indirection */ + if (encoding & DW_EH_PE_indirect) { + result = *((uintptr_t*)result); + } + + *data = p; + return result; +} + + +/* + * The C compiler makes references to __gcc_personality_v0 in + * the dwarf unwind information for translation units that use + * __attribute__((cleanup(xx))) on local variables. + * This personality routine is called by the system unwinder + * on each frame as the stack is unwound during a C++ exception + * throw through a C function compiled with -fexceptions. + */ +#if __arm__ +// the setjump-longjump based exceptions personality routine has a different name +_Unwind_Reason_Code __gcc_personality_sj0(int version, _Unwind_Action actions, + uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject, + _Unwind_Context_t context) +#else +_Unwind_Reason_Code __gcc_personality_v0(int version, _Unwind_Action actions, + uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject, + _Unwind_Context_t context) +#endif +{ + /* Since C does not have catch clauses, there is nothing to do during */ + /* phase 1 (the search phase). */ + if ( actions & _UA_SEARCH_PHASE ) + return _URC_CONTINUE_UNWIND; + + /* There is nothing to do if there is no LSDA for this frame. */ + const uint8_t* lsda = _Unwind_GetLanguageSpecificData(context); + if ( lsda == (uint8_t*) 0 ) + return _URC_CONTINUE_UNWIND; + + uintptr_t pc = _Unwind_GetIP(context)-1; + uintptr_t funcStart = _Unwind_GetRegionStart(context); + uintptr_t pcOffset = pc - funcStart; + + /* Parse LSDA header. */ + uint8_t lpStartEncoding = *lsda++; + if (lpStartEncoding != DW_EH_PE_omit) { + readEncodedPointer(&lsda, lpStartEncoding); + } + uint8_t ttypeEncoding = *lsda++; + if (ttypeEncoding != DW_EH_PE_omit) { + readULEB128(&lsda); + } + /* Walk call-site table looking for range that includes current PC. */ + uint8_t callSiteEncoding = *lsda++; + uint32_t callSiteTableLength = readULEB128(&lsda); + const uint8_t* callSiteTableStart = lsda; + const uint8_t* callSiteTableEnd = callSiteTableStart + callSiteTableLength; + const uint8_t* p=callSiteTableStart; + while (p < callSiteTableEnd) { + uintptr_t start = readEncodedPointer(&p, callSiteEncoding); + uintptr_t length = readEncodedPointer(&p, callSiteEncoding); + uintptr_t landingPad = readEncodedPointer(&p, callSiteEncoding); + readULEB128(&p); /* action value not used for C code */ + if ( landingPad == 0 ) + continue; /* no landing pad for this entry */ + if ( (start <= pcOffset) && (pcOffset < (start+length)) ) { + /* Found landing pad for the PC. + * Set Instruction Pointer to so we re-enter function + * at landing pad. The landing pad is created by the compiler + * to take two parameters in registers. + */ + _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), + (uintptr_t)exceptionObject); + _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0); + _Unwind_SetIP(context, funcStart+landingPad); + return _URC_INSTALL_CONTEXT; + } + } + + /* No landing pad found, continue unwinding. */ + return _URC_CONTINUE_UNWIND; +} + diff --git a/lib/builtins/i386/Makefile.mk b/lib/builtins/i386/Makefile.mk new file mode 100644 index 000000000..f3776a02c --- /dev/null +++ b/lib/builtins/i386/Makefile.mk @@ -0,0 +1,20 @@ +#===- lib/builtins/i386/Makefile.mk ------------------------*- Makefile -*--===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# + +ModuleName := builtins +SubDirs := +OnlyArchs := i386 + +AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file))) +Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file))) +ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o) +Implementation := Optimized + +# FIXME: use automatic dependencies? +Dependencies := $(wildcard lib/*.h $(Dir)/*.h) diff --git a/lib/builtins/i386/ashldi3.S b/lib/builtins/i386/ashldi3.S new file mode 100644 index 000000000..a5da1ace1 --- /dev/null +++ b/lib/builtins/i386/ashldi3.S @@ -0,0 +1,58 @@ +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. + +#include "../assembly.h" + +// di_int __ashldi3(di_int input, int count); + +// This routine has some extra memory traffic, loading the 64-bit input via two +// 32-bit loads, then immediately storing it back to the stack via a single 64-bit +// store. This is to avoid a write-small, read-large stall. +// However, if callers of this routine can be safely assumed to store the argument +// via a 64-bt store, this is unnecessary memory traffic, and should be avoided. +// It can be turned off by defining the TRUST_CALLERS_USE_64_BIT_STORES macro. + +#ifdef __i386__ +#ifdef __SSE2__ + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__ashldi3) + movd 12(%esp), %xmm2 // Load count +#ifndef TRUST_CALLERS_USE_64_BIT_STORES + movd 4(%esp), %xmm0 + movd 8(%esp), %xmm1 + punpckldq %xmm1, %xmm0 // Load input +#else + movq 4(%esp), %xmm0 // Load input +#endif + psllq %xmm2, %xmm0 // shift input by count + movd %xmm0, %eax + psrlq $32, %xmm0 + movd %xmm0, %edx + ret +END_COMPILERRT_FUNCTION(__ashldi3) + +#else // Use GPRs instead of SSE2 instructions, if they aren't available. + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__ashldi3) + movl 12(%esp), %ecx // Load count + movl 8(%esp), %edx // Load high + movl 4(%esp), %eax // Load low + + testl $0x20, %ecx // If count >= 32 + jnz 1f // goto 1 + shldl %cl, %eax, %edx // left shift high by count + shll %cl, %eax // left shift low by count + ret + +1: movl %eax, %edx // Move low to high + xorl %eax, %eax // clear low + shll %cl, %edx // shift high by count - 32 + ret +END_COMPILERRT_FUNCTION(__ashldi3) + +#endif // __SSE2__ +#endif // __i386__ diff --git a/lib/builtins/i386/ashrdi3.S b/lib/builtins/i386/ashrdi3.S new file mode 100644 index 000000000..ab0fcfcc9 --- /dev/null +++ b/lib/builtins/i386/ashrdi3.S @@ -0,0 +1,69 @@ +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. + +#include "../assembly.h" + +// di_int __ashrdi3(di_int input, int count); + +#ifdef __i386__ +#ifdef __SSE2__ + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__ashrdi3) + movd 12(%esp), %xmm2 // Load count + movl 8(%esp), %eax +#ifndef TRUST_CALLERS_USE_64_BIT_STORES + movd 4(%esp), %xmm0 + movd 8(%esp), %xmm1 + punpckldq %xmm1, %xmm0 // Load input +#else + movq 4(%esp), %xmm0 // Load input +#endif + + psrlq %xmm2, %xmm0 // unsigned shift input by count + + testl %eax, %eax // check the sign-bit of the input + jns 1f // early out for positive inputs + + // If the input is negative, we need to construct the shifted sign bit + // to or into the result, as xmm does not have a signed right shift. + pcmpeqb %xmm1, %xmm1 // -1ULL + psrlq $58, %xmm1 // 0x3f + pandn %xmm1, %xmm2 // 63 - count + pcmpeqb %xmm1, %xmm1 // -1ULL + psubq %xmm1, %xmm2 // 64 - count + psllq %xmm2, %xmm1 // -1 << (64 - count) = leading sign bits + por %xmm1, %xmm0 + + // Move the result back to the general purpose registers and return +1: movd %xmm0, %eax + psrlq $32, %xmm0 + movd %xmm0, %edx + ret +END_COMPILERRT_FUNCTION(__ashrdi3) + +#else // Use GPRs instead of SSE2 instructions, if they aren't available. + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__ashrdi3) + movl 12(%esp), %ecx // Load count + movl 8(%esp), %edx // Load high + movl 4(%esp), %eax // Load low + + testl $0x20, %ecx // If count >= 32 + jnz 1f // goto 1 + + shrdl %cl, %edx, %eax // right shift low by count + sarl %cl, %edx // right shift high by count + ret + +1: movl %edx, %eax // Move high to low + sarl $31, %edx // clear high + sarl %cl, %eax // shift low by count - 32 + ret +END_COMPILERRT_FUNCTION(__ashrdi3) + +#endif // __SSE2__ +#endif // __i386__ diff --git a/lib/builtins/i386/divdi3.S b/lib/builtins/i386/divdi3.S new file mode 100644 index 000000000..5afec5f9c --- /dev/null +++ b/lib/builtins/i386/divdi3.S @@ -0,0 +1,162 @@ +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. + +#include "../assembly.h" + +// di_int __divdi3(di_int a, di_int b); + +// result = a / b. +// both inputs and the output are 64-bit signed integers. +// This will do whatever the underlying hardware is set to do on division by zero. +// No other exceptions are generated, as the divide cannot overflow. +// +// This is targeted at 32-bit x86 *only*, as this can be done directly in hardware +// on x86_64. The performance goal is ~40 cycles per divide, which is faster than +// currently possible via simulation of integer divides on the x87 unit. +// +// Stephen Canon, December 2008 + +#ifdef __i386__ + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__divdi3) + +/* This is currently implemented by wrapping the unsigned divide up in an absolute + value, then restoring the correct sign at the end of the computation. This could + certainly be improved upon. */ + + pushl %esi + movl 20(%esp), %edx // high word of b + movl 16(%esp), %eax // low word of b + movl %edx, %ecx + sarl $31, %ecx // (b < 0) ? -1 : 0 + xorl %ecx, %eax + xorl %ecx, %edx // EDX:EAX = (b < 0) ? not(b) : b + subl %ecx, %eax + sbbl %ecx, %edx // EDX:EAX = abs(b) + movl %edx, 20(%esp) + movl %eax, 16(%esp) // store abs(b) back to stack + movl %ecx, %esi // set aside sign of b + + movl 12(%esp), %edx // high word of b + movl 8(%esp), %eax // low word of b + movl %edx, %ecx + sarl $31, %ecx // (a < 0) ? -1 : 0 + xorl %ecx, %eax + xorl %ecx, %edx // EDX:EAX = (a < 0) ? not(a) : a + subl %ecx, %eax + sbbl %ecx, %edx // EDX:EAX = abs(a) + movl %edx, 12(%esp) + movl %eax, 8(%esp) // store abs(a) back to stack + xorl %ecx, %esi // sign of result = (sign of a) ^ (sign of b) + + pushl %ebx + movl 24(%esp), %ebx // Find the index i of the leading bit in b. + bsrl %ebx, %ecx // If the high word of b is zero, jump to + jz 9f // the code to handle that special case [9]. + + /* High word of b is known to be non-zero on this branch */ + + movl 20(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b + + shrl %cl, %eax // Practically, this means that bhi is given by: + shrl %eax // + notl %ecx // bhi = (high word of b) << (31 - i) | + shll %cl, %ebx // (low word of b) >> (1 + i) + orl %eax, %ebx // + movl 16(%esp), %edx // Load the high and low words of a, and jump + movl 12(%esp), %eax // to [1] if the high word is larger than bhi + cmpl %ebx, %edx // to avoid overflowing the upcoming divide. + jae 1f + + /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */ + + divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r + + pushl %edi + notl %ecx + shrl %eax + shrl %cl, %eax // q = qs >> (1 + i) + movl %eax, %edi + mull 24(%esp) // q*blo + movl 16(%esp), %ebx + movl 20(%esp), %ecx // ECX:EBX = a + subl %eax, %ebx + sbbl %edx, %ecx // ECX:EBX = a - q*blo + movl 28(%esp), %eax + imull %edi, %eax // q*bhi + subl %eax, %ecx // ECX:EBX = a - q*b + sbbl $0, %edi // decrement q if remainder is negative + xorl %edx, %edx + movl %edi, %eax + + addl %esi, %eax // Restore correct sign to result + adcl %esi, %edx + xorl %esi, %eax + xorl %esi, %edx + popl %edi // Restore callee-save registers + popl %ebx + popl %esi + retl // Return + + +1: /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */ + + subl %ebx, %edx // subtract bhi from ahi so that divide will not + divl %ebx // overflow, and find q and r such that + // + // ahi:alo = (1:q)*bhi + r + // + // Note that q is a number in (31-i).(1+i) + // fix point. + + pushl %edi + notl %ecx + shrl %eax + orl $0x80000000, %eax + shrl %cl, %eax // q = (1:qs) >> (1 + i) + movl %eax, %edi + mull 24(%esp) // q*blo + movl 16(%esp), %ebx + movl 20(%esp), %ecx // ECX:EBX = a + subl %eax, %ebx + sbbl %edx, %ecx // ECX:EBX = a - q*blo + movl 28(%esp), %eax + imull %edi, %eax // q*bhi + subl %eax, %ecx // ECX:EBX = a - q*b + sbbl $0, %edi // decrement q if remainder is negative + xorl %edx, %edx + movl %edi, %eax + + addl %esi, %eax // Restore correct sign to result + adcl %esi, %edx + xorl %esi, %eax + xorl %esi, %edx + popl %edi // Restore callee-save registers + popl %ebx + popl %esi + retl // Return + + +9: /* High word of b is zero on this branch */ + + movl 16(%esp), %eax // Find qhi and rhi such that + movl 20(%esp), %ecx // + xorl %edx, %edx // ahi = qhi*b + rhi with 0 ≤ rhi < b + divl %ecx // + movl %eax, %ebx // + movl 12(%esp), %eax // Find qlo such that + divl %ecx // + movl %ebx, %edx // rhi:alo = qlo*b + rlo with 0 ≤ rlo < b + + addl %esi, %eax // Restore correct sign to result + adcl %esi, %edx + xorl %esi, %eax + xorl %esi, %edx + popl %ebx // Restore callee-save registers + popl %esi + retl // Return +END_COMPILERRT_FUNCTION(__divdi3) + +#endif // __i386__ diff --git a/lib/builtins/i386/floatdidf.S b/lib/builtins/i386/floatdidf.S new file mode 100644 index 000000000..493608886 --- /dev/null +++ b/lib/builtins/i386/floatdidf.S @@ -0,0 +1,36 @@ +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. + +#include "../assembly.h" + +// double __floatundidf(du_int a); + +#ifdef __i386__ + +#ifndef __ELF__ +.const +#endif +.align 4 +twop52: .quad 0x4330000000000000 +twop32: .quad 0x41f0000000000000 + +#define REL_ADDR(_a) (_a)-0b(%eax) + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__floatdidf) + cvtsi2sd 8(%esp), %xmm1 + movss 4(%esp), %xmm0 // low 32 bits of a + calll 0f +0: popl %eax + mulsd REL_ADDR(twop32), %xmm1 // a_hi as a double (without rounding) + movsd REL_ADDR(twop52), %xmm2 // 0x1.0p52 + subsd %xmm2, %xmm1 // a_hi - 0x1p52 (no rounding occurs) + orpd %xmm2, %xmm0 // 0x1p52 + a_lo (no rounding occurs) + addsd %xmm1, %xmm0 // a_hi + a_lo (round happens here) + movsd %xmm0, 4(%esp) + fldl 4(%esp) + ret +END_COMPILERRT_FUNCTION(__floatdidf) + +#endif // __i386__ diff --git a/lib/builtins/i386/floatdisf.S b/lib/builtins/i386/floatdisf.S new file mode 100644 index 000000000..8340331b8 --- /dev/null +++ b/lib/builtins/i386/floatdisf.S @@ -0,0 +1,32 @@ +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. + +#include "../assembly.h" + +// float __floatdisf(di_int a); + +// This routine has some extra memory traffic, loading the 64-bit input via two +// 32-bit loads, then immediately storing it back to the stack via a single 64-bit +// store. This is to avoid a write-small, read-large stall. +// However, if callers of this routine can be safely assumed to store the argument +// via a 64-bt store, this is unnecessary memory traffic, and should be avoided. +// It can be turned off by defining the TRUST_CALLERS_USE_64_BIT_STORES macro. + +#ifdef __i386__ + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__floatdisf) +#ifndef TRUST_CALLERS_USE_64_BIT_STORES + movd 4(%esp), %xmm0 + movd 8(%esp), %xmm1 + punpckldq %xmm1, %xmm0 + movq %xmm0, 4(%esp) +#endif + fildll 4(%esp) + fstps 4(%esp) + flds 4(%esp) + ret +END_COMPILERRT_FUNCTION(__floatdisf) + +#endif // __i386__ diff --git a/lib/builtins/i386/floatdixf.S b/lib/builtins/i386/floatdixf.S new file mode 100644 index 000000000..eaa34d744 --- /dev/null +++ b/lib/builtins/i386/floatdixf.S @@ -0,0 +1,30 @@ +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. + +#include "../assembly.h" + +// float __floatdixf(di_int a); + +#ifdef __i386__ + +// This routine has some extra memory traffic, loading the 64-bit input via two +// 32-bit loads, then immediately storing it back to the stack via a single 64-bit +// store. This is to avoid a write-small, read-large stall. +// However, if callers of this routine can be safely assumed to store the argument +// via a 64-bt store, this is unnecessary memory traffic, and should be avoided. +// It can be turned off by defining the TRUST_CALLERS_USE_64_BIT_STORES macro. + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__floatdixf) +#ifndef TRUST_CALLERS_USE_64_BIT_STORES + movd 4(%esp), %xmm0 + movd 8(%esp), %xmm1 + punpckldq %xmm1, %xmm0 + movq %xmm0, 4(%esp) +#endif + fildll 4(%esp) + ret +END_COMPILERRT_FUNCTION(__floatdixf) + +#endif // __i386__ diff --git a/lib/builtins/i386/floatundidf.S b/lib/builtins/i386/floatundidf.S new file mode 100644 index 000000000..5b8787ba6 --- /dev/null +++ b/lib/builtins/i386/floatundidf.S @@ -0,0 +1,47 @@ +//===-- floatundidf.S - Implement __floatundidf for i386 ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements __floatundidf for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// double __floatundidf(du_int a); + +#ifdef __i386__ + +#ifndef __ELF__ +.const +#endif +.align 4 +twop52: .quad 0x4330000000000000 +twop84_plus_twop52: + .quad 0x4530000000100000 +twop84: .quad 0x4530000000000000 + +#define REL_ADDR(_a) (_a)-0b(%eax) + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__floatundidf) + movss 8(%esp), %xmm1 // high 32 bits of a + movss 4(%esp), %xmm0 // low 32 bits of a + calll 0f +0: popl %eax + orpd REL_ADDR(twop84), %xmm1 // 0x1p84 + a_hi (no rounding occurs) + subsd REL_ADDR(twop84_plus_twop52), %xmm1 // a_hi - 0x1p52 (no rounding occurs) + orpd REL_ADDR(twop52), %xmm0 // 0x1p52 + a_lo (no rounding occurs) + addsd %xmm1, %xmm0 // a_hi + a_lo (round happens here) + movsd %xmm0, 4(%esp) + fldl 4(%esp) + ret +END_COMPILERRT_FUNCTION(__floatundidf) + +#endif // __i386__ diff --git a/lib/builtins/i386/floatundisf.S b/lib/builtins/i386/floatundisf.S new file mode 100644 index 000000000..2253021bc --- /dev/null +++ b/lib/builtins/i386/floatundisf.S @@ -0,0 +1,101 @@ +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. + +#include "../assembly.h" + +// float __floatundisf(du_int a); + +// Note that there is a hardware instruction, fildll, that does most of what +// this function needs to do. However, because of our ia32 ABI, it will take +// a write-small read-large stall, so the software implementation here is +// actually several cycles faster. + +// This is a branch-free implementation. A branchy implementation might be +// faster for the common case if you know something a priori about the input +// distribution. + +/* branch-free x87 implementation - one cycle slower than without x87. + +#ifdef __i386__ + +.const +.align 3 + + .quad 0x43f0000000000000 +twop64: .quad 0x0000000000000000 + +#define TWOp64 twop64-0b(%ecx,%eax,8) + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__floatundisf) + movl 8(%esp), %eax + movd 8(%esp), %xmm1 + movd 4(%esp), %xmm0 + punpckldq %xmm1, %xmm0 + calll 0f +0: popl %ecx + sarl $31, %eax + movq %xmm0, 4(%esp) + fildll 4(%esp) + faddl TWOp64 + fstps 4(%esp) + flds 4(%esp) + ret +END_COMPILERRT_FUNCTION(__floatundisf) + +#endif // __i386__ + +*/ + +/* branch-free, x87-free implementation - faster at the expense of code size */ + +#ifdef __i386__ + +#ifndef __ELF__ +.const +.align 3 +#else +.align 8 +#endif +twop52: .quad 0x4330000000000000 + .quad 0x0000000000000fff +sticky: .quad 0x0000000000000000 + .long 0x00000012 +twelve: .long 0x00000000 + +#define TWOp52 twop52-0b(%ecx) +#define STICKY sticky-0b(%ecx,%eax,8) + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__floatundisf) + movl 8(%esp), %eax + movd 8(%esp), %xmm1 + movd 4(%esp), %xmm0 + punpckldq %xmm1, %xmm0 + + calll 0f +0: popl %ecx + shrl %eax // high 31 bits of input as sint32 + addl $0x7ff80000, %eax + sarl $31, %eax // (big input) ? -1 : 0 + movsd STICKY, %xmm1 // (big input) ? 0xfff : 0 + movl $12, %edx + andl %eax, %edx // (big input) ? 12 : 0 + movd %edx, %xmm3 + andpd %xmm0, %xmm1 // (big input) ? input & 0xfff : 0 + movsd TWOp52, %xmm2 // 0x1.0p52 + psrlq %xmm3, %xmm0 // (big input) ? input >> 12 : input + orpd %xmm2, %xmm1 // 0x1.0p52 + ((big input) ? input & 0xfff : input) + orpd %xmm1, %xmm0 // 0x1.0p52 + ((big input) ? (input >> 12 | input & 0xfff) : input) + subsd %xmm2, %xmm0 // (double)((big input) ? (input >> 12 | input & 0xfff) : input) + cvtsd2ss %xmm0, %xmm0 // (float)((big input) ? (input >> 12 | input & 0xfff) : input) + pslld $23, %xmm3 + paddd %xmm3, %xmm0 // (float)input + movd %xmm0, 4(%esp) + flds 4(%esp) + ret +END_COMPILERRT_FUNCTION(__floatundisf) + +#endif // __i386__ diff --git a/lib/builtins/i386/floatundixf.S b/lib/builtins/i386/floatundixf.S new file mode 100644 index 000000000..b728d0697 --- /dev/null +++ b/lib/builtins/i386/floatundixf.S @@ -0,0 +1,38 @@ +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. + +#include "../assembly.h" + +// long double __floatundixf(du_int a);16 + +#ifdef __i386__ + +#ifndef __ELF__ +.const +#endif +.align 4 +twop52: .quad 0x4330000000000000 +twop84_plus_twop52_neg: + .quad 0xc530000000100000 +twop84: .quad 0x4530000000000000 + +#define REL_ADDR(_a) (_a)-0b(%eax) + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__floatundixf) + calll 0f +0: popl %eax + movss 8(%esp), %xmm0 // hi 32 bits of input + movss 4(%esp), %xmm1 // lo 32 bits of input + orpd REL_ADDR(twop84), %xmm0 // 2^84 + hi (as a double) + orpd REL_ADDR(twop52), %xmm1 // 2^52 + lo (as a double) + addsd REL_ADDR(twop84_plus_twop52_neg), %xmm0 // hi - 2^52 (no rounding occurs) + movsd %xmm1, 4(%esp) + fldl 4(%esp) + movsd %xmm0, 4(%esp) + faddl 4(%esp) + ret +END_COMPILERRT_FUNCTION(__floatundixf) + +#endif // __i386__ diff --git a/lib/builtins/i386/lshrdi3.S b/lib/builtins/i386/lshrdi3.S new file mode 100644 index 000000000..dcfc33169 --- /dev/null +++ b/lib/builtins/i386/lshrdi3.S @@ -0,0 +1,59 @@ +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. + +#include "../assembly.h" + +// di_int __lshrdi3(di_int input, int count); + +// This routine has some extra memory traffic, loading the 64-bit input via two +// 32-bit loads, then immediately storing it back to the stack via a single 64-bit +// store. This is to avoid a write-small, read-large stall. +// However, if callers of this routine can be safely assumed to store the argument +// via a 64-bt store, this is unnecessary memory traffic, and should be avoided. +// It can be turned off by defining the TRUST_CALLERS_USE_64_BIT_STORES macro. + +#ifdef __i386__ +#ifdef __SSE2__ + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__lshrdi3) + movd 12(%esp), %xmm2 // Load count +#ifndef TRUST_CALLERS_USE_64_BIT_STORES + movd 4(%esp), %xmm0 + movd 8(%esp), %xmm1 + punpckldq %xmm1, %xmm0 // Load input +#else + movq 4(%esp), %xmm0 // Load input +#endif + psrlq %xmm2, %xmm0 // shift input by count + movd %xmm0, %eax + psrlq $32, %xmm0 + movd %xmm0, %edx + ret +END_COMPILERRT_FUNCTION(__lshrdi3) + +#else // Use GPRs instead of SSE2 instructions, if they aren't available. + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__lshrdi3) + movl 12(%esp), %ecx // Load count + movl 8(%esp), %edx // Load high + movl 4(%esp), %eax // Load low + + testl $0x20, %ecx // If count >= 32 + jnz 1f // goto 1 + + shrdl %cl, %edx, %eax // right shift low by count + shrl %cl, %edx // right shift high by count + ret + +1: movl %edx, %eax // Move high to low + xorl %edx, %edx // clear high + shrl %cl, %eax // shift low by count - 32 + ret +END_COMPILERRT_FUNCTION(__lshrdi3) + +#endif // __SSE2__ +#endif // __i386__ diff --git a/lib/builtins/i386/moddi3.S b/lib/builtins/i386/moddi3.S new file mode 100644 index 000000000..79e4fc213 --- /dev/null +++ b/lib/builtins/i386/moddi3.S @@ -0,0 +1,166 @@ +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. + +#include "../assembly.h" + +// di_int __moddi3(di_int a, di_int b); + +// result = remainder of a / b. +// both inputs and the output are 64-bit signed integers. +// This will do whatever the underlying hardware is set to do on division by zero. +// No other exceptions are generated, as the divide cannot overflow. +// +// This is targeted at 32-bit x86 *only*, as this can be done directly in hardware +// on x86_64. The performance goal is ~40 cycles per divide, which is faster than +// currently possible via simulation of integer divides on the x87 unit. +// + +// Stephen Canon, December 2008 + +#ifdef __i386__ + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__moddi3) + +/* This is currently implemented by wrapping the unsigned modulus up in an absolute + value. This could certainly be improved upon. */ + + pushl %esi + movl 20(%esp), %edx // high word of b + movl 16(%esp), %eax // low word of b + movl %edx, %ecx + sarl $31, %ecx // (b < 0) ? -1 : 0 + xorl %ecx, %eax + xorl %ecx, %edx // EDX:EAX = (b < 0) ? not(b) : b + subl %ecx, %eax + sbbl %ecx, %edx // EDX:EAX = abs(b) + movl %edx, 20(%esp) + movl %eax, 16(%esp) // store abs(b) back to stack + + movl 12(%esp), %edx // high word of b + movl 8(%esp), %eax // low word of b + movl %edx, %ecx + sarl $31, %ecx // (a < 0) ? -1 : 0 + xorl %ecx, %eax + xorl %ecx, %edx // EDX:EAX = (a < 0) ? not(a) : a + subl %ecx, %eax + sbbl %ecx, %edx // EDX:EAX = abs(a) + movl %edx, 12(%esp) + movl %eax, 8(%esp) // store abs(a) back to stack + movl %ecx, %esi // set aside sign of a + + pushl %ebx + movl 24(%esp), %ebx // Find the index i of the leading bit in b. + bsrl %ebx, %ecx // If the high word of b is zero, jump to + jz 9f // the code to handle that special case [9]. + + /* High word of b is known to be non-zero on this branch */ + + movl 20(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b + + shrl %cl, %eax // Practically, this means that bhi is given by: + shrl %eax // + notl %ecx // bhi = (high word of b) << (31 - i) | + shll %cl, %ebx // (low word of b) >> (1 + i) + orl %eax, %ebx // + movl 16(%esp), %edx // Load the high and low words of a, and jump + movl 12(%esp), %eax // to [2] if the high word is larger than bhi + cmpl %ebx, %edx // to avoid overflowing the upcoming divide. + jae 2f + + /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */ + + divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r + + pushl %edi + notl %ecx + shrl %eax + shrl %cl, %eax // q = qs >> (1 + i) + movl %eax, %edi + mull 24(%esp) // q*blo + movl 16(%esp), %ebx + movl 20(%esp), %ecx // ECX:EBX = a + subl %eax, %ebx + sbbl %edx, %ecx // ECX:EBX = a - q*blo + movl 28(%esp), %eax + imull %edi, %eax // q*bhi + subl %eax, %ecx // ECX:EBX = a - q*b + + jnc 1f // if positive, this is the result. + addl 24(%esp), %ebx // otherwise + adcl 28(%esp), %ecx // ECX:EBX = a - (q-1)*b = result +1: movl %ebx, %eax + movl %ecx, %edx + + addl %esi, %eax // Restore correct sign to result + adcl %esi, %edx + xorl %esi, %eax + xorl %esi, %edx + popl %edi // Restore callee-save registers + popl %ebx + popl %esi + retl // Return + +2: /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */ + + subl %ebx, %edx // subtract bhi from ahi so that divide will not + divl %ebx // overflow, and find q and r such that + // + // ahi:alo = (1:q)*bhi + r + // + // Note that q is a number in (31-i).(1+i) + // fix point. + + pushl %edi + notl %ecx + shrl %eax + orl $0x80000000, %eax + shrl %cl, %eax // q = (1:qs) >> (1 + i) + movl %eax, %edi + mull 24(%esp) // q*blo + movl 16(%esp), %ebx + movl 20(%esp), %ecx // ECX:EBX = a + subl %eax, %ebx + sbbl %edx, %ecx // ECX:EBX = a - q*blo + movl 28(%esp), %eax + imull %edi, %eax // q*bhi + subl %eax, %ecx // ECX:EBX = a - q*b + + jnc 3f // if positive, this is the result. + addl 24(%esp), %ebx // otherwise + adcl 28(%esp), %ecx // ECX:EBX = a - (q-1)*b = result +3: movl %ebx, %eax + movl %ecx, %edx + + addl %esi, %eax // Restore correct sign to result + adcl %esi, %edx + xorl %esi, %eax + xorl %esi, %edx + popl %edi // Restore callee-save registers + popl %ebx + popl %esi + retl // Return + +9: /* High word of b is zero on this branch */ + + movl 16(%esp), %eax // Find qhi and rhi such that + movl 20(%esp), %ecx // + xorl %edx, %edx // ahi = qhi*b + rhi with 0 ≤ rhi < b + divl %ecx // + movl %eax, %ebx // + movl 12(%esp), %eax // Find rlo such that + divl %ecx // + movl %edx, %eax // rhi:alo = qlo*b + rlo with 0 ≤ rlo < b + popl %ebx // + xorl %edx, %edx // and return 0:rlo + + addl %esi, %eax // Restore correct sign to result + adcl %esi, %edx + xorl %esi, %eax + xorl %esi, %edx + popl %esi + retl // Return +END_COMPILERRT_FUNCTION(__moddi3) + +#endif // __i386__ diff --git a/lib/builtins/i386/muldi3.S b/lib/builtins/i386/muldi3.S new file mode 100644 index 000000000..5af1136c1 --- /dev/null +++ b/lib/builtins/i386/muldi3.S @@ -0,0 +1,30 @@ +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. + +#include "../assembly.h" + +// di_int __muldi3(di_int a, di_int b); + +#ifdef __i386__ + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__muldi3) + pushl %ebx + movl 16(%esp), %eax // b.lo + movl 12(%esp), %ecx // a.hi + imull %eax, %ecx // b.lo * a.hi + + movl 8(%esp), %edx // a.lo + movl 20(%esp), %ebx // b.hi + imull %edx, %ebx // a.lo * b.hi + + mull %edx // EDX:EAX = a.lo * b.lo + addl %ecx, %ebx // EBX = (a.lo*b.hi + a.hi*b.lo) + addl %ebx, %edx + + popl %ebx + retl +END_COMPILERRT_FUNCTION(__muldi3) + +#endif // __i386__ diff --git a/lib/builtins/i386/udivdi3.S b/lib/builtins/i386/udivdi3.S new file mode 100644 index 000000000..5072b221c --- /dev/null +++ b/lib/builtins/i386/udivdi3.S @@ -0,0 +1,115 @@ +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. + +#include "../assembly.h" + +// du_int __udivdi3(du_int a, du_int b); + +// result = a / b. +// both inputs and the output are 64-bit unsigned integers. +// This will do whatever the underlying hardware is set to do on division by zero. +// No other exceptions are generated, as the divide cannot overflow. +// +// This is targeted at 32-bit x86 *only*, as this can be done directly in hardware +// on x86_64. The performance goal is ~40 cycles per divide, which is faster than +// currently possible via simulation of integer divides on the x87 unit. +// +// Stephen Canon, December 2008 + +#ifdef __i386__ + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__udivdi3) + + pushl %ebx + movl 20(%esp), %ebx // Find the index i of the leading bit in b. + bsrl %ebx, %ecx // If the high word of b is zero, jump to + jz 9f // the code to handle that special case [9]. + + /* High word of b is known to be non-zero on this branch */ + + movl 16(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b + + shrl %cl, %eax // Practically, this means that bhi is given by: + shrl %eax // + notl %ecx // bhi = (high word of b) << (31 - i) | + shll %cl, %ebx // (low word of b) >> (1 + i) + orl %eax, %ebx // + movl 12(%esp), %edx // Load the high and low words of a, and jump + movl 8(%esp), %eax // to [1] if the high word is larger than bhi + cmpl %ebx, %edx // to avoid overflowing the upcoming divide. + jae 1f + + /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */ + + divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r + + pushl %edi + notl %ecx + shrl %eax + shrl %cl, %eax // q = qs >> (1 + i) + movl %eax, %edi + mull 20(%esp) // q*blo + movl 12(%esp), %ebx + movl 16(%esp), %ecx // ECX:EBX = a + subl %eax, %ebx + sbbl %edx, %ecx // ECX:EBX = a - q*blo + movl 24(%esp), %eax + imull %edi, %eax // q*bhi + subl %eax, %ecx // ECX:EBX = a - q*b + sbbl $0, %edi // decrement q if remainder is negative + xorl %edx, %edx + movl %edi, %eax + popl %edi + popl %ebx + retl + + +1: /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */ + + subl %ebx, %edx // subtract bhi from ahi so that divide will not + divl %ebx // overflow, and find q and r such that + // + // ahi:alo = (1:q)*bhi + r + // + // Note that q is a number in (31-i).(1+i) + // fix point. + + pushl %edi + notl %ecx + shrl %eax + orl $0x80000000, %eax + shrl %cl, %eax // q = (1:qs) >> (1 + i) + movl %eax, %edi + mull 20(%esp) // q*blo + movl 12(%esp), %ebx + movl 16(%esp), %ecx // ECX:EBX = a + subl %eax, %ebx + sbbl %edx, %ecx // ECX:EBX = a - q*blo + movl 24(%esp), %eax + imull %edi, %eax // q*bhi + subl %eax, %ecx // ECX:EBX = a - q*b + sbbl $0, %edi // decrement q if remainder is negative + xorl %edx, %edx + movl %edi, %eax + popl %edi + popl %ebx + retl + + +9: /* High word of b is zero on this branch */ + + movl 12(%esp), %eax // Find qhi and rhi such that + movl 16(%esp), %ecx // + xorl %edx, %edx // ahi = qhi*b + rhi with 0 ≤ rhi < b + divl %ecx // + movl %eax, %ebx // + movl 8(%esp), %eax // Find qlo such that + divl %ecx // + movl %ebx, %edx // rhi:alo = qlo*b + rlo with 0 ≤ rlo < b + popl %ebx // + retl // and return qhi:qlo +END_COMPILERRT_FUNCTION(__udivdi3) + +#endif // __i386__ diff --git a/lib/builtins/i386/umoddi3.S b/lib/builtins/i386/umoddi3.S new file mode 100644 index 000000000..63cefc207 --- /dev/null +++ b/lib/builtins/i386/umoddi3.S @@ -0,0 +1,126 @@ +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. + +#include "../assembly.h" + +// du_int __umoddi3(du_int a, du_int b); + +// result = remainder of a / b. +// both inputs and the output are 64-bit unsigned integers. +// This will do whatever the underlying hardware is set to do on division by zero. +// No other exceptions are generated, as the divide cannot overflow. +// +// This is targeted at 32-bit x86 *only*, as this can be done directly in hardware +// on x86_64. The performance goal is ~40 cycles per divide, which is faster than +// currently possible via simulation of integer divides on the x87 unit. +// + +// Stephen Canon, December 2008 + +#ifdef __i386__ + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__umoddi3) + + pushl %ebx + movl 20(%esp), %ebx // Find the index i of the leading bit in b. + bsrl %ebx, %ecx // If the high word of b is zero, jump to + jz 9f // the code to handle that special case [9]. + + /* High word of b is known to be non-zero on this branch */ + + movl 16(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b + + shrl %cl, %eax // Practically, this means that bhi is given by: + shrl %eax // + notl %ecx // bhi = (high word of b) << (31 - i) | + shll %cl, %ebx // (low word of b) >> (1 + i) + orl %eax, %ebx // + movl 12(%esp), %edx // Load the high and low words of a, and jump + movl 8(%esp), %eax // to [2] if the high word is larger than bhi + cmpl %ebx, %edx // to avoid overflowing the upcoming divide. + jae 2f + + /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */ + + divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r + + pushl %edi + notl %ecx + shrl %eax + shrl %cl, %eax // q = qs >> (1 + i) + movl %eax, %edi + mull 20(%esp) // q*blo + movl 12(%esp), %ebx + movl 16(%esp), %ecx // ECX:EBX = a + subl %eax, %ebx + sbbl %edx, %ecx // ECX:EBX = a - q*blo + movl 24(%esp), %eax + imull %edi, %eax // q*bhi + subl %eax, %ecx // ECX:EBX = a - q*b + + jnc 1f // if positive, this is the result. + addl 20(%esp), %ebx // otherwise + adcl 24(%esp), %ecx // ECX:EBX = a - (q-1)*b = result +1: movl %ebx, %eax + movl %ecx, %edx + + popl %edi + popl %ebx + retl + + +2: /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */ + + subl %ebx, %edx // subtract bhi from ahi so that divide will not + divl %ebx // overflow, and find q and r such that + // + // ahi:alo = (1:q)*bhi + r + // + // Note that q is a number in (31-i).(1+i) + // fix point. + + pushl %edi + notl %ecx + shrl %eax + orl $0x80000000, %eax + shrl %cl, %eax // q = (1:qs) >> (1 + i) + movl %eax, %edi + mull 20(%esp) // q*blo + movl 12(%esp), %ebx + movl 16(%esp), %ecx // ECX:EBX = a + subl %eax, %ebx + sbbl %edx, %ecx // ECX:EBX = a - q*blo + movl 24(%esp), %eax + imull %edi, %eax // q*bhi + subl %eax, %ecx // ECX:EBX = a - q*b + + jnc 3f // if positive, this is the result. + addl 20(%esp), %ebx // otherwise + adcl 24(%esp), %ecx // ECX:EBX = a - (q-1)*b = result +3: movl %ebx, %eax + movl %ecx, %edx + + popl %edi + popl %ebx + retl + + + +9: /* High word of b is zero on this branch */ + + movl 12(%esp), %eax // Find qhi and rhi such that + movl 16(%esp), %ecx // + xorl %edx, %edx // ahi = qhi*b + rhi with 0 ≤ rhi < b + divl %ecx // + movl %eax, %ebx // + movl 8(%esp), %eax // Find rlo such that + divl %ecx // + movl %edx, %eax // rhi:alo = qlo*b + rlo with 0 ≤ rlo < b + popl %ebx // + xorl %edx, %edx // and return 0:rlo + retl // +END_COMPILERRT_FUNCTION(__umoddi3) + +#endif // __i386__ diff --git a/lib/builtins/int_endianness.h b/lib/builtins/int_endianness.h new file mode 100644 index 000000000..c465a985e --- /dev/null +++ b/lib/builtins/int_endianness.h @@ -0,0 +1,111 @@ +/* ===-- int_endianness.h - configuration header for compiler-rt ------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file is a configuration header for compiler-rt. + * This file is not part of the interface of this library. + * + * ===----------------------------------------------------------------------=== + */ + +#ifndef INT_ENDIANNESS_H +#define INT_ENDIANNESS_H + +#if defined(__SVR4) && defined(__sun) +#include <sys/byteorder.h> + +#if defined(_BIG_ENDIAN) +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#elif defined(_LITTLE_ENDIAN) +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#else /* !_LITTLE_ENDIAN */ +#error "unknown endianness" +#endif /* !_LITTLE_ENDIAN */ + +#endif /* Solaris and AuroraUX. */ + +/* .. */ + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__minix) +#include <sys/endian.h> + +#if _BYTE_ORDER == _BIG_ENDIAN +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#elif _BYTE_ORDER == _LITTLE_ENDIAN +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif /* _BYTE_ORDER */ + +#endif /* *BSD */ + +#if defined(__OpenBSD__) || defined(__Bitrig__) +#include <machine/endian.h> + +#if _BYTE_ORDER == _BIG_ENDIAN +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#elif _BYTE_ORDER == _LITTLE_ENDIAN +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif /* _BYTE_ORDER */ + +#endif /* OpenBSD and Bitrig. */ + +/* .. */ + +/* Mac OSX has __BIG_ENDIAN__ or __LITTLE_ENDIAN__ automatically set by the compiler (at least with GCC) */ +#if defined(__APPLE__) || defined(__ellcc__ ) + +#ifdef __BIG_ENDIAN__ +#if __BIG_ENDIAN__ +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#endif +#endif /* __BIG_ENDIAN__ */ + +#ifdef __LITTLE_ENDIAN__ +#if __LITTLE_ENDIAN__ +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif +#endif /* __LITTLE_ENDIAN__ */ + +#endif /* Mac OSX */ + +/* .. */ + +#if defined(__linux__) +#include <endian.h> + +#if __BYTE_ORDER == __BIG_ENDIAN +#define _YUGA_LITTLE_ENDIAN 0 +#define _YUGA_BIG_ENDIAN 1 +#elif __BYTE_ORDER == __LITTLE_ENDIAN +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 +#endif /* __BYTE_ORDER */ + +#endif /* GNU/Linux */ + +#if defined(_WIN32) + +#define _YUGA_LITTLE_ENDIAN 1 +#define _YUGA_BIG_ENDIAN 0 + +#endif /* Windows */ + +/* . */ + +#if !defined(_YUGA_LITTLE_ENDIAN) || !defined(_YUGA_BIG_ENDIAN) +#error Unable to determine endian +#endif /* Check we found an endianness correctly. */ + +#endif /* INT_ENDIANNESS_H */ diff --git a/lib/builtins/int_lib.h b/lib/builtins/int_lib.h new file mode 100644 index 000000000..daeaa9e57 --- /dev/null +++ b/lib/builtins/int_lib.h @@ -0,0 +1,56 @@ +/* ===-- int_lib.h - configuration header for compiler-rt -----------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file is a configuration header for compiler-rt. + * This file is not part of the interface of this library. + * + * ===----------------------------------------------------------------------=== + */ + +#ifndef INT_LIB_H +#define INT_LIB_H + +/* Assumption: Signed integral is 2's complement. */ +/* Assumption: Right shift of signed negative is arithmetic shift. */ +/* Assumption: Endianness is little or big (not mixed). */ + +/* ABI macro definitions */ + +#if __ARM_EABI__ +# define ARM_EABI_FNALIAS(aeabi_name, name) \ + void __aeabi_##aeabi_name() __attribute__((alias("__" #name))); +# define COMPILER_RT_ABI __attribute__((pcs("aapcs"))) +#else +# define ARM_EABI_FNALIAS(aeabi_name, name) +# define COMPILER_RT_ABI +#endif + +#if defined(__NetBSD__) && (defined(_KERNEL) || defined(_STANDALONE)) +/* + * Kernel and boot environment can't use normal headers, + * so use the equivalent system headers. + */ +# include <machine/limits.h> +# include <sys/stdint.h> +# include <sys/types.h> +#else +/* Include the standard compiler builtin headers we use functionality from. */ +# include <limits.h> +# include <stdint.h> +# include <stdbool.h> +# include <float.h> +#endif + +/* Include the commonly used internal type definitions. */ +#include "int_types.h" + +/* Include internal utility function declarations. */ +#include "int_util.h" + +#endif /* INT_LIB_H */ diff --git a/lib/builtins/int_math.h b/lib/builtins/int_math.h new file mode 100644 index 000000000..d6b4bdae1 --- /dev/null +++ b/lib/builtins/int_math.h @@ -0,0 +1,67 @@ +/* ===-- int_math.h - internal math inlines ---------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===-----------------------------------------------------------------------=== + * + * This file is not part of the interface of this library. + * + * This file defines substitutes for the libm functions used in some of the + * compiler-rt implementations, defined in such a way that there is not a direct + * dependency on libm or math.h. Instead, we use the compiler builtin versions + * where available. This reduces our dependencies on the system SDK by foisting + * the responsibility onto the compiler. + * + * ===-----------------------------------------------------------------------=== + */ + +#ifndef INT_MATH_H +#define INT_MATH_H + +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif + +#define CRT_INFINITY __builtin_huge_valf() + +#define crt_isinf(x) __builtin_isinf((x)) +#define crt_isnan(x) __builtin_isnan((x)) + +/* Define crt_isfinite in terms of the builtin if available, otherwise provide + * an alternate version in terms of our other functions. This supports some + * versions of GCC which didn't have __builtin_isfinite. + */ +#if __has_builtin(__builtin_isfinite) +# define crt_isfinite(x) __builtin_isfinite((x)) +#else +# define crt_isfinite(x) \ + __extension__(({ \ + __typeof((x)) x_ = (x); \ + !crt_isinf(x_) && !crt_isnan(x_); \ + })) +#endif + +#define crt_copysign(x, y) __builtin_copysign((x), (y)) +#define crt_copysignf(x, y) __builtin_copysignf((x), (y)) +#define crt_copysignl(x, y) __builtin_copysignl((x), (y)) + +#define crt_fabs(x) __builtin_fabs((x)) +#define crt_fabsf(x) __builtin_fabsf((x)) +#define crt_fabsl(x) __builtin_fabsl((x)) + +#define crt_fmax(x, y) __builtin_fmax((x), (y)) +#define crt_fmaxf(x, y) __builtin_fmaxf((x), (y)) +#define crt_fmaxl(x, y) __builtin_fmaxl((x), (y)) + +#define crt_logb(x) __builtin_logb((x)) +#define crt_logbf(x) __builtin_logbf((x)) +#define crt_logbl(x) __builtin_logbl((x)) + +#define crt_scalbn(x, y) __builtin_scalbn((x), (y)) +#define crt_scalbnf(x, y) __builtin_scalbnf((x), (y)) +#define crt_scalbnl(x, y) __builtin_scalbnl((x), (y)) + +#endif /* INT_MATH_H */ diff --git a/lib/builtins/int_types.h b/lib/builtins/int_types.h new file mode 100644 index 000000000..fcce390f9 --- /dev/null +++ b/lib/builtins/int_types.h @@ -0,0 +1,140 @@ +/* ===-- int_lib.h - configuration header for compiler-rt -----------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file is not part of the interface of this library. + * + * This file defines various standard types, most importantly a number of unions + * used to access parts of larger types. + * + * ===----------------------------------------------------------------------=== + */ + +#ifndef INT_TYPES_H +#define INT_TYPES_H + +#include "int_endianness.h" + +typedef int si_int; +typedef unsigned su_int; + +typedef long long di_int; +typedef unsigned long long du_int; + +typedef union +{ + di_int all; + struct + { +#if _YUGA_LITTLE_ENDIAN + su_int low; + si_int high; +#else + si_int high; + su_int low; +#endif /* _YUGA_LITTLE_ENDIAN */ + }s; +} dwords; + +typedef union +{ + du_int all; + struct + { +#if _YUGA_LITTLE_ENDIAN + su_int low; + su_int high; +#else + su_int high; + su_int low; +#endif /* _YUGA_LITTLE_ENDIAN */ + }s; +} udwords; + +#if __x86_64 + +typedef int ti_int __attribute__ ((mode (TI))); +typedef unsigned tu_int __attribute__ ((mode (TI))); + +typedef union +{ + ti_int all; + struct + { +#if _YUGA_LITTLE_ENDIAN + du_int low; + di_int high; +#else + di_int high; + du_int low; +#endif /* _YUGA_LITTLE_ENDIAN */ + }s; +} twords; + +typedef union +{ + tu_int all; + struct + { +#if _YUGA_LITTLE_ENDIAN + du_int low; + du_int high; +#else + du_int high; + du_int low; +#endif /* _YUGA_LITTLE_ENDIAN */ + }s; +} utwords; + +static inline ti_int make_ti(di_int h, di_int l) { + twords r; + r.s.high = h; + r.s.low = l; + return r.all; +} + +static inline tu_int make_tu(du_int h, du_int l) { + utwords r; + r.s.high = h; + r.s.low = l; + return r.all; +} + +#endif /* __x86_64 */ + +typedef union +{ + su_int u; + float f; +} float_bits; + +typedef union +{ + udwords u; + double f; +} double_bits; + +typedef struct +{ +#if _YUGA_LITTLE_ENDIAN + udwords low; + udwords high; +#else + udwords high; + udwords low; +#endif /* _YUGA_LITTLE_ENDIAN */ +} uqwords; + +typedef union +{ + uqwords u; + long double f; +} long_double_bits; + +#endif /* INT_TYPES_H */ + diff --git a/lib/builtins/int_util.c b/lib/builtins/int_util.c new file mode 100644 index 000000000..323e46179 --- /dev/null +++ b/lib/builtins/int_util.c @@ -0,0 +1,61 @@ +/* ===-- int_util.c - Implement internal utilities --------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_util.h" +#include "int_lib.h" + +/* NOTE: The definitions in this file are declared weak because we clients to be + * able to arbitrarily package individual functions into separate .a files. If + * we did not declare these weak, some link situations might end up seeing + * duplicate strong definitions of the same symbol. + * + * We can't use this solution for kernel use (which may not support weak), but + * currently expect that when built for kernel use all the functionality is + * packaged into a single library. + */ + +#ifdef KERNEL_USE + +extern void panic(const char *, ...) __attribute__((noreturn)); +#ifndef _WIN32 +__attribute__((visibility("hidden"))) +#endif +void compilerrt_abort_impl(const char *file, int line, const char *function) { + panic("%s:%d: abort in %s", file, line, function); +} + +#elif __APPLE__ + +/* from libSystem.dylib */ +extern void __assert_rtn(const char *func, const char *file, + int line, const char * message) __attribute__((noreturn)); + +#ifndef _WIN32 +__attribute__((weak)) +__attribute__((visibility("hidden"))) +#endif +void compilerrt_abort_impl(const char *file, int line, const char *function) { + __assert_rtn(function, file, line, "libcompiler_rt abort"); +} + +#else + +/* Get the system definition of abort() */ +#include <stdlib.h> + +#ifndef _WIN32 +__attribute__((weak)) +__attribute__((visibility("hidden"))) +#endif +void compilerrt_abort_impl(const char *file, int line, const char *function) { + abort(); +} + +#endif diff --git a/lib/builtins/int_util.h b/lib/builtins/int_util.h new file mode 100644 index 000000000..1348b85eb --- /dev/null +++ b/lib/builtins/int_util.h @@ -0,0 +1,29 @@ +/* ===-- int_util.h - internal utility functions ----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===-----------------------------------------------------------------------=== + * + * This file is not part of the interface of this library. + * + * This file defines non-inline utilities which are available for use in the + * library. The function definitions themselves are all contained in int_util.c + * which will always be compiled into any compiler-rt library. + * + * ===-----------------------------------------------------------------------=== + */ + +#ifndef INT_UTIL_H +#define INT_UTIL_H + +/** \brief Trigger a program abort (or panic for kernel code). */ +#define compilerrt_abort() compilerrt_abort_impl(__FILE__, __LINE__, \ + __FUNCTION__) + +void compilerrt_abort_impl(const char *file, int line, + const char *function) __attribute__((noreturn)); + +#endif /* INT_UTIL_H */ diff --git a/lib/builtins/lshrdi3.c b/lib/builtins/lshrdi3.c new file mode 100644 index 000000000..6b1ea923b --- /dev/null +++ b/lib/builtins/lshrdi3.c @@ -0,0 +1,43 @@ +/* ===-- lshrdi3.c - Implement __lshrdi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __lshrdi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: logical a >> b */ + +/* Precondition: 0 <= b < bits_in_dword */ + +ARM_EABI_FNALIAS(llsr, lshrdi3) + +COMPILER_RT_ABI di_int +__lshrdi3(di_int a, si_int b) +{ + const int bits_in_word = (int)(sizeof(si_int) * CHAR_BIT); + udwords input; + udwords result; + input.all = a; + if (b & bits_in_word) /* bits_in_word <= b < bits_in_dword */ + { + result.s.high = 0; + result.s.low = input.s.high >> (b - bits_in_word); + } + else /* 0 <= b < bits_in_word */ + { + if (b == 0) + return a; + result.s.high = input.s.high >> b; + result.s.low = (input.s.high << (bits_in_word - b)) | (input.s.low >> b); + } + return result.all; +} diff --git a/lib/builtins/lshrti3.c b/lib/builtins/lshrti3.c new file mode 100644 index 000000000..be768143b --- /dev/null +++ b/lib/builtins/lshrti3.c @@ -0,0 +1,45 @@ +/* ===-- lshrti3.c - Implement __lshrti3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __lshrti3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: logical a >> b */ + +/* Precondition: 0 <= b < bits_in_tword */ + +ti_int +__lshrti3(ti_int a, si_int b) +{ + const int bits_in_dword = (int)(sizeof(di_int) * CHAR_BIT); + utwords input; + utwords result; + input.all = a; + if (b & bits_in_dword) /* bits_in_dword <= b < bits_in_tword */ + { + result.s.high = 0; + result.s.low = input.s.high >> (b - bits_in_dword); + } + else /* 0 <= b < bits_in_dword */ + { + if (b == 0) + return a; + result.s.high = input.s.high >> b; + result.s.low = (input.s.high << (bits_in_dword - b)) | (input.s.low >> b); + } + return result.all; +} + +#endif /* __x86_64 */ diff --git a/lib/builtins/moddi3.c b/lib/builtins/moddi3.c new file mode 100644 index 000000000..2f3b9cc4f --- /dev/null +++ b/lib/builtins/moddi3.c @@ -0,0 +1,32 @@ +/*===-- moddi3.c - Implement __moddi3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __moddi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int* rem); + +/* Returns: a % b */ + +COMPILER_RT_ABI di_int +__moddi3(di_int a, di_int b) +{ + const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1; + di_int s = b >> bits_in_dword_m1; /* s = b < 0 ? -1 : 0 */ + b = (b ^ s) - s; /* negate if s == -1 */ + s = a >> bits_in_dword_m1; /* s = a < 0 ? -1 : 0 */ + a = (a ^ s) - s; /* negate if s == -1 */ + di_int r; + __udivmoddi4(a, b, (du_int*)&r); + return (r ^ s) - s; /* negate if s == -1 */ +} diff --git a/lib/builtins/modsi3.c b/lib/builtins/modsi3.c new file mode 100644 index 000000000..d16213c49 --- /dev/null +++ b/lib/builtins/modsi3.c @@ -0,0 +1,25 @@ +/* ===-- modsi3.c - Implement __modsi3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __modsi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +su_int COMPILER_RT_ABI __divsi3(si_int a, si_int b); + +/* Returns: a % b */ + +COMPILER_RT_ABI si_int +__modsi3(si_int a, si_int b) +{ + return a - __divsi3(a, b) * b; +} diff --git a/lib/builtins/modti3.c b/lib/builtins/modti3.c new file mode 100644 index 000000000..752202d45 --- /dev/null +++ b/lib/builtins/modti3.c @@ -0,0 +1,36 @@ +/* ===-- modti3.c - Implement __modti3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __modti3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem); + +/*Returns: a % b */ + +ti_int +__modti3(ti_int a, ti_int b) +{ + const int bits_in_tword_m1 = (int)(sizeof(ti_int) * CHAR_BIT) - 1; + ti_int s = b >> bits_in_tword_m1; /* s = b < 0 ? -1 : 0 */ + b = (b ^ s) - s; /* negate if s == -1 */ + s = a >> bits_in_tword_m1; /* s = a < 0 ? -1 : 0 */ + a = (a ^ s) - s; /* negate if s == -1 */ + ti_int r; + __udivmodti4(a, b, (tu_int*)&r); + return (r ^ s) - s; /* negate if s == -1 */ +} + +#endif diff --git a/lib/builtins/muldc3.c b/lib/builtins/muldc3.c new file mode 100644 index 000000000..5f4a6d16e --- /dev/null +++ b/lib/builtins/muldc3.c @@ -0,0 +1,73 @@ +/* ===-- muldc3.c - Implement __muldc3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __muldc3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" +#include "int_math.h" + +/* Returns: the product of a + ib and c + id */ + +double _Complex +__muldc3(double __a, double __b, double __c, double __d) +{ + double __ac = __a * __c; + double __bd = __b * __d; + double __ad = __a * __d; + double __bc = __b * __c; + double _Complex z; + __real__ z = __ac - __bd; + __imag__ z = __ad + __bc; + if (crt_isnan(__real__ z) && crt_isnan(__imag__ z)) + { + int __recalc = 0; + if (crt_isinf(__a) || crt_isinf(__b)) + { + __a = crt_copysign(crt_isinf(__a) ? 1 : 0, __a); + __b = crt_copysign(crt_isinf(__b) ? 1 : 0, __b); + if (crt_isnan(__c)) + __c = crt_copysign(0, __c); + if (crt_isnan(__d)) + __d = crt_copysign(0, __d); + __recalc = 1; + } + if (crt_isinf(__c) || crt_isinf(__d)) + { + __c = crt_copysign(crt_isinf(__c) ? 1 : 0, __c); + __d = crt_copysign(crt_isinf(__d) ? 1 : 0, __d); + if (crt_isnan(__a)) + __a = crt_copysign(0, __a); + if (crt_isnan(__b)) + __b = crt_copysign(0, __b); + __recalc = 1; + } + if (!__recalc && (crt_isinf(__ac) || crt_isinf(__bd) || + crt_isinf(__ad) || crt_isinf(__bc))) + { + if (crt_isnan(__a)) + __a = crt_copysign(0, __a); + if (crt_isnan(__b)) + __b = crt_copysign(0, __b); + if (crt_isnan(__c)) + __c = crt_copysign(0, __c); + if (crt_isnan(__d)) + __d = crt_copysign(0, __d); + __recalc = 1; + } + if (__recalc) + { + __real__ z = CRT_INFINITY * (__a * __c - __b * __d); + __imag__ z = CRT_INFINITY * (__a * __d + __b * __c); + } + } + return z; +} diff --git a/lib/builtins/muldf3.c b/lib/builtins/muldf3.c new file mode 100644 index 000000000..c38edba90 --- /dev/null +++ b/lib/builtins/muldf3.c @@ -0,0 +1,122 @@ +//===-- lib/muldf3.c - Double-precision multiplication ------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements double-precision soft-float multiplication +// with the IEEE-754 default rounding (to nearest, ties to even). +// +//===----------------------------------------------------------------------===// + +#define DOUBLE_PRECISION +#include "fp_lib.h" + +ARM_EABI_FNALIAS(dmul, muldf3) + +COMPILER_RT_ABI fp_t +__muldf3(fp_t a, fp_t b) { + + const unsigned int aExponent = toRep(a) >> significandBits & maxExponent; + const unsigned int bExponent = toRep(b) >> significandBits & maxExponent; + const rep_t productSign = (toRep(a) ^ toRep(b)) & signBit; + + rep_t aSignificand = toRep(a) & significandMask; + rep_t bSignificand = toRep(b) & significandMask; + int scale = 0; + + // Detect if a or b is zero, denormal, infinity, or NaN. + if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) { + + const rep_t aAbs = toRep(a) & absMask; + const rep_t bAbs = toRep(b) & absMask; + + // NaN * anything = qNaN + if (aAbs > infRep) return fromRep(toRep(a) | quietBit); + // anything * NaN = qNaN + if (bAbs > infRep) return fromRep(toRep(b) | quietBit); + + if (aAbs == infRep) { + // infinity * non-zero = +/- infinity + if (bAbs) return fromRep(aAbs | productSign); + // infinity * zero = NaN + else return fromRep(qnanRep); + } + + if (bAbs == infRep) { + // non-zero * infinity = +/- infinity + if (aAbs) return fromRep(bAbs | productSign); + // zero * infinity = NaN + else return fromRep(qnanRep); + } + + // zero * anything = +/- zero + if (!aAbs) return fromRep(productSign); + // anything * zero = +/- zero + if (!bAbs) return fromRep(productSign); + + // one or both of a or b is denormal, the other (if applicable) is a + // normal number. Renormalize one or both of a and b, and set scale to + // include the necessary exponent adjustment. + if (aAbs < implicitBit) scale += normalize(&aSignificand); + if (bAbs < implicitBit) scale += normalize(&bSignificand); + } + + // Or in the implicit significand bit. (If we fell through from the + // denormal path it was already set by normalize( ), but setting it twice + // won't hurt anything.) + aSignificand |= implicitBit; + bSignificand |= implicitBit; + + // Get the significand of a*b. Before multiplying the significands, shift + // one of them left to left-align it in the field. Thus, the product will + // have (exponentBits + 2) integral digits, all but two of which must be + // zero. Normalizing this result is just a conditional left-shift by one + // and bumping the exponent accordingly. + rep_t productHi, productLo; + wideMultiply(aSignificand, bSignificand << exponentBits, + &productHi, &productLo); + + int productExponent = aExponent + bExponent - exponentBias + scale; + + // Normalize the significand, adjust exponent if needed. + if (productHi & implicitBit) productExponent++; + else wideLeftShift(&productHi, &productLo, 1); + + // If we have overflowed the type, return +/- infinity. + if (productExponent >= maxExponent) return fromRep(infRep | productSign); + + if (productExponent <= 0) { + // Result is denormal before rounding + // + // If the result is so small that it just underflows to zero, return + // a zero of the appropriate sign. Mathematically there is no need to + // handle this case separately, but we make it a special case to + // simplify the shift logic. + const unsigned int shift = 1U - (unsigned int)productExponent; + if (shift >= typeWidth) return fromRep(productSign); + + // Otherwise, shift the significand of the result so that the round + // bit is the high bit of productLo. + wideRightShiftWithSticky(&productHi, &productLo, shift); + } + + else { + // Result is normal before rounding; insert the exponent. + productHi &= significandMask; + productHi |= (rep_t)productExponent << significandBits; + } + + // Insert the sign of the result: + productHi |= productSign; + + // Final rounding. The final result may overflow to infinity, or underflow + // to zero, but those are the correct results in those cases. We use the + // default IEEE-754 round-to-nearest, ties-to-even rounding mode. + if (productLo > signBit) productHi++; + if (productLo == signBit) productHi += productHi & 1; + return fromRep(productHi); +} diff --git a/lib/builtins/muldi3.c b/lib/builtins/muldi3.c new file mode 100644 index 000000000..2dae44c11 --- /dev/null +++ b/lib/builtins/muldi3.c @@ -0,0 +1,56 @@ +/* ===-- muldi3.c - Implement __muldi3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __muldi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: a * b */ + +static +di_int +__muldsi3(su_int a, su_int b) +{ + dwords r; + const int bits_in_word_2 = (int)(sizeof(si_int) * CHAR_BIT) / 2; + const su_int lower_mask = (su_int)~0 >> bits_in_word_2; + r.s.low = (a & lower_mask) * (b & lower_mask); + su_int t = r.s.low >> bits_in_word_2; + r.s.low &= lower_mask; + t += (a >> bits_in_word_2) * (b & lower_mask); + r.s.low += (t & lower_mask) << bits_in_word_2; + r.s.high = t >> bits_in_word_2; + t = r.s.low >> bits_in_word_2; + r.s.low &= lower_mask; + t += (b >> bits_in_word_2) * (a & lower_mask); + r.s.low += (t & lower_mask) << bits_in_word_2; + r.s.high += t >> bits_in_word_2; + r.s.high += (a >> bits_in_word_2) * (b >> bits_in_word_2); + return r.all; +} + +/* Returns: a * b */ + +ARM_EABI_FNALIAS(lmul, muldi3) + +COMPILER_RT_ABI di_int +__muldi3(di_int a, di_int b) +{ + dwords x; + x.all = a; + dwords y; + y.all = b; + dwords r; + r.all = __muldsi3(x.s.low, y.s.low); + r.s.high += x.s.high * y.s.low + x.s.low * y.s.high; + return r.all; +} diff --git a/lib/builtins/mulodi4.c b/lib/builtins/mulodi4.c new file mode 100644 index 000000000..0c1b5cdae --- /dev/null +++ b/lib/builtins/mulodi4.c @@ -0,0 +1,58 @@ +/*===-- mulodi4.c - Implement __mulodi4 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __mulodi4 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: a * b */ + +/* Effects: sets *overflow to 1 if a * b overflows */ + +di_int +__mulodi4(di_int a, di_int b, int* overflow) +{ + const int N = (int)(sizeof(di_int) * CHAR_BIT); + const di_int MIN = (di_int)1 << (N-1); + const di_int MAX = ~MIN; + *overflow = 0; + di_int result = a * b; + if (a == MIN) + { + if (b != 0 && b != 1) + *overflow = 1; + return result; + } + if (b == MIN) + { + if (a != 0 && a != 1) + *overflow = 1; + return result; + } + di_int sa = a >> (N - 1); + di_int abs_a = (a ^ sa) - sa; + di_int sb = b >> (N - 1); + di_int abs_b = (b ^ sb) - sb; + if (abs_a < 2 || abs_b < 2) + return result; + if (sa == sb) + { + if (abs_a > MAX / abs_b) + *overflow = 1; + } + else + { + if (abs_a > MIN / -abs_b) + *overflow = 1; + } + return result; +} diff --git a/lib/builtins/mulosi4.c b/lib/builtins/mulosi4.c new file mode 100644 index 000000000..f3398d1fc --- /dev/null +++ b/lib/builtins/mulosi4.c @@ -0,0 +1,58 @@ +/*===-- mulosi4.c - Implement __mulosi4 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __mulosi4 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: a * b */ + +/* Effects: sets *overflow to 1 if a * b overflows */ + +si_int +__mulosi4(si_int a, si_int b, int* overflow) +{ + const int N = (int)(sizeof(si_int) * CHAR_BIT); + const si_int MIN = (si_int)1 << (N-1); + const si_int MAX = ~MIN; + *overflow = 0; + si_int result = a * b; + if (a == MIN) + { + if (b != 0 && b != 1) + *overflow = 1; + return result; + } + if (b == MIN) + { + if (a != 0 && a != 1) + *overflow = 1; + return result; + } + si_int sa = a >> (N - 1); + si_int abs_a = (a ^ sa) - sa; + si_int sb = b >> (N - 1); + si_int abs_b = (b ^ sb) - sb; + if (abs_a < 2 || abs_b < 2) + return result; + if (sa == sb) + { + if (abs_a > MAX / abs_b) + *overflow = 1; + } + else + { + if (abs_a > MIN / -abs_b) + *overflow = 1; + } + return result; +} diff --git a/lib/builtins/muloti4.c b/lib/builtins/muloti4.c new file mode 100644 index 000000000..f58dd074e --- /dev/null +++ b/lib/builtins/muloti4.c @@ -0,0 +1,62 @@ +/*===-- muloti4.c - Implement __muloti4 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __muloti4 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: a * b */ + +/* Effects: sets *overflow to 1 if a * b overflows */ + +ti_int +__muloti4(ti_int a, ti_int b, int* overflow) +{ + const int N = (int)(sizeof(ti_int) * CHAR_BIT); + const ti_int MIN = (ti_int)1 << (N-1); + const ti_int MAX = ~MIN; + *overflow = 0; + ti_int result = a * b; + if (a == MIN) + { + if (b != 0 && b != 1) + *overflow = 1; + return result; + } + if (b == MIN) + { + if (a != 0 && a != 1) + *overflow = 1; + return result; + } + ti_int sa = a >> (N - 1); + ti_int abs_a = (a ^ sa) - sa; + ti_int sb = b >> (N - 1); + ti_int abs_b = (b ^ sb) - sb; + if (abs_a < 2 || abs_b < 2) + return result; + if (sa == sb) + { + if (abs_a > MAX / abs_b) + *overflow = 1; + } + else + { + if (abs_a > MIN / -abs_b) + *overflow = 1; + } + return result; +} + +#endif diff --git a/lib/builtins/mulsc3.c b/lib/builtins/mulsc3.c new file mode 100644 index 000000000..6d433fbc4 --- /dev/null +++ b/lib/builtins/mulsc3.c @@ -0,0 +1,73 @@ +/* ===-- mulsc3.c - Implement __mulsc3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __mulsc3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" +#include "int_math.h" + +/* Returns: the product of a + ib and c + id */ + +float _Complex +__mulsc3(float __a, float __b, float __c, float __d) +{ + float __ac = __a * __c; + float __bd = __b * __d; + float __ad = __a * __d; + float __bc = __b * __c; + float _Complex z; + __real__ z = __ac - __bd; + __imag__ z = __ad + __bc; + if (crt_isnan(__real__ z) && crt_isnan(__imag__ z)) + { + int __recalc = 0; + if (crt_isinf(__a) || crt_isinf(__b)) + { + __a = crt_copysignf(crt_isinf(__a) ? 1 : 0, __a); + __b = crt_copysignf(crt_isinf(__b) ? 1 : 0, __b); + if (crt_isnan(__c)) + __c = crt_copysignf(0, __c); + if (crt_isnan(__d)) + __d = crt_copysignf(0, __d); + __recalc = 1; + } + if (crt_isinf(__c) || crt_isinf(__d)) + { + __c = crt_copysignf(crt_isinf(__c) ? 1 : 0, __c); + __d = crt_copysignf(crt_isinf(__d) ? 1 : 0, __d); + if (crt_isnan(__a)) + __a = crt_copysignf(0, __a); + if (crt_isnan(__b)) + __b = crt_copysignf(0, __b); + __recalc = 1; + } + if (!__recalc && (crt_isinf(__ac) || crt_isinf(__bd) || + crt_isinf(__ad) || crt_isinf(__bc))) + { + if (crt_isnan(__a)) + __a = crt_copysignf(0, __a); + if (crt_isnan(__b)) + __b = crt_copysignf(0, __b); + if (crt_isnan(__c)) + __c = crt_copysignf(0, __c); + if (crt_isnan(__d)) + __d = crt_copysignf(0, __d); + __recalc = 1; + } + if (__recalc) + { + __real__ z = CRT_INFINITY * (__a * __c - __b * __d); + __imag__ z = CRT_INFINITY * (__a * __d + __b * __c); + } + } + return z; +} diff --git a/lib/builtins/mulsf3.c b/lib/builtins/mulsf3.c new file mode 100644 index 000000000..861a9ba5f --- /dev/null +++ b/lib/builtins/mulsf3.c @@ -0,0 +1,112 @@ +//===-- lib/mulsf3.c - Single-precision multiplication ------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements single-precision soft-float multiplication +// with the IEEE-754 default rounding (to nearest, ties to even). +// +//===----------------------------------------------------------------------===// + +#define SINGLE_PRECISION +#include "fp_lib.h" + +ARM_EABI_FNALIAS(fmul, mulsf3) + +COMPILER_RT_ABI fp_t +__mulsf3(fp_t a, fp_t b) { + + const unsigned int aExponent = toRep(a) >> significandBits & maxExponent; + const unsigned int bExponent = toRep(b) >> significandBits & maxExponent; + const rep_t productSign = (toRep(a) ^ toRep(b)) & signBit; + + rep_t aSignificand = toRep(a) & significandMask; + rep_t bSignificand = toRep(b) & significandMask; + int scale = 0; + + // Detect if a or b is zero, denormal, infinity, or NaN. + if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) { + + const rep_t aAbs = toRep(a) & absMask; + const rep_t bAbs = toRep(b) & absMask; + + // NaN * anything = qNaN + if (aAbs > infRep) return fromRep(toRep(a) | quietBit); + // anything * NaN = qNaN + if (bAbs > infRep) return fromRep(toRep(b) | quietBit); + + if (aAbs == infRep) { + // infinity * non-zero = +/- infinity + if (bAbs) return fromRep(aAbs | productSign); + // infinity * zero = NaN + else return fromRep(qnanRep); + } + + if (bAbs == infRep) { + // non-zero * infinity = +/- infinity + if (aAbs) return fromRep(bAbs | productSign); + // zero * infinity = NaN + else return fromRep(qnanRep); + } + + // zero * anything = +/- zero + if (!aAbs) return fromRep(productSign); + // anything * zero = +/- zero + if (!bAbs) return fromRep(productSign); + + // one or both of a or b is denormal, the other (if applicable) is a + // normal number. Renormalize one or both of a and b, and set scale to + // include the necessary exponent adjustment. + if (aAbs < implicitBit) scale += normalize(&aSignificand); + if (bAbs < implicitBit) scale += normalize(&bSignificand); + } + + // Or in the implicit significand bit. (If we fell through from the + // denormal path it was already set by normalize( ), but setting it twice + // won't hurt anything.) + aSignificand |= implicitBit; + bSignificand |= implicitBit; + + // Get the significand of a*b. Before multiplying the significands, shift + // one of them left to left-align it in the field. Thus, the product will + // have (exponentBits + 2) integral digits, all but two of which must be + // zero. Normalizing this result is just a conditional left-shift by one + // and bumping the exponent accordingly. + rep_t productHi, productLo; + wideMultiply(aSignificand, bSignificand << exponentBits, + &productHi, &productLo); + + int productExponent = aExponent + bExponent - exponentBias + scale; + + // Normalize the significand, adjust exponent if needed. + if (productHi & implicitBit) productExponent++; + else wideLeftShift(&productHi, &productLo, 1); + + // If we have overflowed the type, return +/- infinity. + if (productExponent >= maxExponent) return fromRep(infRep | productSign); + + if (productExponent <= 0) { + // Result is denormal before rounding, the exponent is zero and we + // need to shift the significand. + wideRightShiftWithSticky(&productHi, &productLo, 1U - (unsigned)productExponent); + } + + else { + // Result is normal before rounding; insert the exponent. + productHi &= significandMask; + productHi |= (rep_t)productExponent << significandBits; + } + + // Insert the sign of the result: + productHi |= productSign; + + // Final rounding. The final result may overflow to infinity, or underflow + // to zero, but those are the correct results in those cases. + if (productLo > signBit) productHi++; + if (productLo == signBit) productHi += productHi & 1; + return fromRep(productHi); +} diff --git a/lib/builtins/multi3.c b/lib/builtins/multi3.c new file mode 100644 index 000000000..0b8730f08 --- /dev/null +++ b/lib/builtins/multi3.c @@ -0,0 +1,58 @@ +/* ===-- multi3.c - Implement __multi3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + + * This file implements __multi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: a * b */ + +static +ti_int +__mulddi3(du_int a, du_int b) +{ + twords r; + const int bits_in_dword_2 = (int)(sizeof(di_int) * CHAR_BIT) / 2; + const du_int lower_mask = (du_int)~0 >> bits_in_dword_2; + r.s.low = (a & lower_mask) * (b & lower_mask); + du_int t = r.s.low >> bits_in_dword_2; + r.s.low &= lower_mask; + t += (a >> bits_in_dword_2) * (b & lower_mask); + r.s.low += (t & lower_mask) << bits_in_dword_2; + r.s.high = t >> bits_in_dword_2; + t = r.s.low >> bits_in_dword_2; + r.s.low &= lower_mask; + t += (b >> bits_in_dword_2) * (a & lower_mask); + r.s.low += (t & lower_mask) << bits_in_dword_2; + r.s.high += t >> bits_in_dword_2; + r.s.high += (a >> bits_in_dword_2) * (b >> bits_in_dword_2); + return r.all; +} + +/* Returns: a * b */ + +ti_int +__multi3(ti_int a, ti_int b) +{ + twords x; + x.all = a; + twords y; + y.all = b; + twords r; + r.all = __mulddi3(x.s.low, y.s.low); + r.s.high += x.s.high * y.s.low + x.s.low * y.s.high; + return r.all; +} + +#endif /* __x86_64 */ diff --git a/lib/builtins/mulvdi3.c b/lib/builtins/mulvdi3.c new file mode 100644 index 000000000..bcc8e659b --- /dev/null +++ b/lib/builtins/mulvdi3.c @@ -0,0 +1,56 @@ +/*===-- mulvdi3.c - Implement __mulvdi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __mulvdi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: a * b */ + +/* Effects: aborts if a * b overflows */ + +di_int +__mulvdi3(di_int a, di_int b) +{ + const int N = (int)(sizeof(di_int) * CHAR_BIT); + const di_int MIN = (di_int)1 << (N-1); + const di_int MAX = ~MIN; + if (a == MIN) + { + if (b == 0 || b == 1) + return a * b; + compilerrt_abort(); + } + if (b == MIN) + { + if (a == 0 || a == 1) + return a * b; + compilerrt_abort(); + } + di_int sa = a >> (N - 1); + di_int abs_a = (a ^ sa) - sa; + di_int sb = b >> (N - 1); + di_int abs_b = (b ^ sb) - sb; + if (abs_a < 2 || abs_b < 2) + return a * b; + if (sa == sb) + { + if (abs_a > MAX / abs_b) + compilerrt_abort(); + } + else + { + if (abs_a > MIN / -abs_b) + compilerrt_abort(); + } + return a * b; +} diff --git a/lib/builtins/mulvsi3.c b/lib/builtins/mulvsi3.c new file mode 100644 index 000000000..d372b2017 --- /dev/null +++ b/lib/builtins/mulvsi3.c @@ -0,0 +1,56 @@ +/* ===-- mulvsi3.c - Implement __mulvsi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __mulvsi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: a * b */ + +/* Effects: aborts if a * b overflows */ + +si_int +__mulvsi3(si_int a, si_int b) +{ + const int N = (int)(sizeof(si_int) * CHAR_BIT); + const si_int MIN = (si_int)1 << (N-1); + const si_int MAX = ~MIN; + if (a == MIN) + { + if (b == 0 || b == 1) + return a * b; + compilerrt_abort(); + } + if (b == MIN) + { + if (a == 0 || a == 1) + return a * b; + compilerrt_abort(); + } + si_int sa = a >> (N - 1); + si_int abs_a = (a ^ sa) - sa; + si_int sb = b >> (N - 1); + si_int abs_b = (b ^ sb) - sb; + if (abs_a < 2 || abs_b < 2) + return a * b; + if (sa == sb) + { + if (abs_a > MAX / abs_b) + compilerrt_abort(); + } + else + { + if (abs_a > MIN / -abs_b) + compilerrt_abort(); + } + return a * b; +} diff --git a/lib/builtins/mulvti3.c b/lib/builtins/mulvti3.c new file mode 100644 index 000000000..31f7d2fd3 --- /dev/null +++ b/lib/builtins/mulvti3.c @@ -0,0 +1,60 @@ +/* ===-- mulvti3.c - Implement __mulvti3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __mulvti3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: a * b */ + +/* Effects: aborts if a * b overflows */ + +ti_int +__mulvti3(ti_int a, ti_int b) +{ + const int N = (int)(sizeof(ti_int) * CHAR_BIT); + const ti_int MIN = (ti_int)1 << (N-1); + const ti_int MAX = ~MIN; + if (a == MIN) + { + if (b == 0 || b == 1) + return a * b; + compilerrt_abort(); + } + if (b == MIN) + { + if (a == 0 || a == 1) + return a * b; + compilerrt_abort(); + } + ti_int sa = a >> (N - 1); + ti_int abs_a = (a ^ sa) - sa; + ti_int sb = b >> (N - 1); + ti_int abs_b = (b ^ sb) - sb; + if (abs_a < 2 || abs_b < 2) + return a * b; + if (sa == sb) + { + if (abs_a > MAX / abs_b) + compilerrt_abort(); + } + else + { + if (abs_a > MIN / -abs_b) + compilerrt_abort(); + } + return a * b; +} + +#endif diff --git a/lib/builtins/mulxc3.c b/lib/builtins/mulxc3.c new file mode 100644 index 000000000..cec057368 --- /dev/null +++ b/lib/builtins/mulxc3.c @@ -0,0 +1,77 @@ +/* ===-- mulxc3.c - Implement __mulxc3 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __mulxc3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if !_ARCH_PPC + +#include "int_lib.h" +#include "int_math.h" + +/* Returns: the product of a + ib and c + id */ + +long double _Complex +__mulxc3(long double __a, long double __b, long double __c, long double __d) +{ + long double __ac = __a * __c; + long double __bd = __b * __d; + long double __ad = __a * __d; + long double __bc = __b * __c; + long double _Complex z; + __real__ z = __ac - __bd; + __imag__ z = __ad + __bc; + if (crt_isnan(__real__ z) && crt_isnan(__imag__ z)) + { + int __recalc = 0; + if (crt_isinf(__a) || crt_isinf(__b)) + { + __a = crt_copysignl(crt_isinf(__a) ? 1 : 0, __a); + __b = crt_copysignl(crt_isinf(__b) ? 1 : 0, __b); + if (crt_isnan(__c)) + __c = crt_copysignl(0, __c); + if (crt_isnan(__d)) + __d = crt_copysignl(0, __d); + __recalc = 1; + } + if (crt_isinf(__c) || crt_isinf(__d)) + { + __c = crt_copysignl(crt_isinf(__c) ? 1 : 0, __c); + __d = crt_copysignl(crt_isinf(__d) ? 1 : 0, __d); + if (crt_isnan(__a)) + __a = crt_copysignl(0, __a); + if (crt_isnan(__b)) + __b = crt_copysignl(0, __b); + __recalc = 1; + } + if (!__recalc && (crt_isinf(__ac) || crt_isinf(__bd) || + crt_isinf(__ad) || crt_isinf(__bc))) + { + if (crt_isnan(__a)) + __a = crt_copysignl(0, __a); + if (crt_isnan(__b)) + __b = crt_copysignl(0, __b); + if (crt_isnan(__c)) + __c = crt_copysignl(0, __c); + if (crt_isnan(__d)) + __d = crt_copysignl(0, __d); + __recalc = 1; + } + if (__recalc) + { + __real__ z = CRT_INFINITY * (__a * __c - __b * __d); + __imag__ z = CRT_INFINITY * (__a * __d + __b * __c); + } + } + return z; +} + +#endif diff --git a/lib/builtins/negdf2.c b/lib/builtins/negdf2.c new file mode 100644 index 000000000..4e17513a9 --- /dev/null +++ b/lib/builtins/negdf2.c @@ -0,0 +1,21 @@ +//===-- lib/negdf2.c - double-precision negation ------------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements double-precision soft-float negation. +// +//===----------------------------------------------------------------------===// + +#define DOUBLE_PRECISION +#include "fp_lib.h" + +ARM_EABI_FNALIAS(dneg, negdf2) + +fp_t __negdf2(fp_t a) { + return fromRep(toRep(a) ^ signBit); +} diff --git a/lib/builtins/negdi2.c b/lib/builtins/negdi2.c new file mode 100644 index 000000000..b000dda3b --- /dev/null +++ b/lib/builtins/negdi2.c @@ -0,0 +1,26 @@ +/* ===-- negdi2.c - Implement __negdi2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __negdi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: -a */ + +di_int +__negdi2(di_int a) +{ + /* Note: this routine is here for API compatibility; any sane compiler + * should expand it inline. + */ + return -a; +} diff --git a/lib/builtins/negsf2.c b/lib/builtins/negsf2.c new file mode 100644 index 000000000..29c17be41 --- /dev/null +++ b/lib/builtins/negsf2.c @@ -0,0 +1,22 @@ +//===-- lib/negsf2.c - single-precision negation ------------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements single-precision soft-float negation. +// +//===----------------------------------------------------------------------===// + +#define SINGLE_PRECISION +#include "fp_lib.h" + +ARM_EABI_FNALIAS(fneg, negsf2) + +COMPILER_RT_ABI fp_t +__negsf2(fp_t a) { + return fromRep(toRep(a) ^ signBit); +} diff --git a/lib/builtins/negti2.c b/lib/builtins/negti2.c new file mode 100644 index 000000000..f7e4ad3b9 --- /dev/null +++ b/lib/builtins/negti2.c @@ -0,0 +1,30 @@ +/* ===-- negti2.c - Implement __negti2 -------------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __negti2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: -a */ + +ti_int +__negti2(ti_int a) +{ + /* Note: this routine is here for API compatibility; any sane compiler + * should expand it inline. + */ + return -a; +} + +#endif diff --git a/lib/builtins/negvdi2.c b/lib/builtins/negvdi2.c new file mode 100644 index 000000000..e336ecf28 --- /dev/null +++ b/lib/builtins/negvdi2.c @@ -0,0 +1,28 @@ +/* ===-- negvdi2.c - Implement __negvdi2 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __negvdi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: -a */ + +/* Effects: aborts if -a overflows */ + +COMPILER_RT_ABI di_int +__negvdi2(di_int a) +{ + const di_int MIN = (di_int)1 << ((int)(sizeof(di_int) * CHAR_BIT)-1); + if (a == MIN) + compilerrt_abort(); + return -a; +} diff --git a/lib/builtins/negvsi2.c b/lib/builtins/negvsi2.c new file mode 100644 index 000000000..b9e93fef0 --- /dev/null +++ b/lib/builtins/negvsi2.c @@ -0,0 +1,28 @@ +/* ===-- negvsi2.c - Implement __negvsi2 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __negvsi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: -a */ + +/* Effects: aborts if -a overflows */ + +COMPILER_RT_ABI si_int +__negvsi2(si_int a) +{ + const si_int MIN = (si_int)1 << ((int)(sizeof(si_int) * CHAR_BIT)-1); + if (a == MIN) + compilerrt_abort(); + return -a; +} diff --git a/lib/builtins/negvti2.c b/lib/builtins/negvti2.c new file mode 100644 index 000000000..05df6152f --- /dev/null +++ b/lib/builtins/negvti2.c @@ -0,0 +1,32 @@ +/*===-- negvti2.c - Implement __negvti2 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + *===----------------------------------------------------------------------=== + * + *This file implements __negvti2 for the compiler_rt library. + * + *===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: -a */ + +/* Effects: aborts if -a overflows */ + +ti_int +__negvti2(ti_int a) +{ + const ti_int MIN = (ti_int)1 << ((int)(sizeof(ti_int) * CHAR_BIT)-1); + if (a == MIN) + compilerrt_abort(); + return -a; +} + +#endif diff --git a/lib/builtins/paritydi2.c b/lib/builtins/paritydi2.c new file mode 100644 index 000000000..2ded54c90 --- /dev/null +++ b/lib/builtins/paritydi2.c @@ -0,0 +1,27 @@ +/* ===-- paritydi2.c - Implement __paritydi2 -------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __paritydi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: 1 if number of bits is odd else returns 0 */ + +si_int COMPILER_RT_ABI __paritysi2(si_int a); + +COMPILER_RT_ABI si_int +__paritydi2(di_int a) +{ + dwords x; + x.all = a; + return __paritysi2(x.s.high ^ x.s.low); +} diff --git a/lib/builtins/paritysi2.c b/lib/builtins/paritysi2.c new file mode 100644 index 000000000..599984663 --- /dev/null +++ b/lib/builtins/paritysi2.c @@ -0,0 +1,27 @@ +/* ===-- paritysi2.c - Implement __paritysi2 -------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __paritysi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: 1 if number of bits is odd else returns 0 */ + +COMPILER_RT_ABI si_int +__paritysi2(si_int a) +{ + su_int x = (su_int)a; + x ^= x >> 16; + x ^= x >> 8; + x ^= x >> 4; + return (0x6996 >> (x & 0xF)) & 1; +} diff --git a/lib/builtins/parityti2.c b/lib/builtins/parityti2.c new file mode 100644 index 000000000..a1f47b1d9 --- /dev/null +++ b/lib/builtins/parityti2.c @@ -0,0 +1,31 @@ +/* ===-- parityti2.c - Implement __parityti2 -------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __parityti2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: 1 if number of bits is odd else returns 0 */ + +si_int __paritydi2(di_int a); + +si_int +__parityti2(ti_int a) +{ + twords x; + x.all = a; + return __paritydi2(x.s.high ^ x.s.low); +} + +#endif diff --git a/lib/builtins/popcountdi2.c b/lib/builtins/popcountdi2.c new file mode 100644 index 000000000..5e8a62f07 --- /dev/null +++ b/lib/builtins/popcountdi2.c @@ -0,0 +1,36 @@ +/* ===-- popcountdi2.c - Implement __popcountdi2 ----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __popcountdi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: count of 1 bits */ + +COMPILER_RT_ABI si_int +__popcountdi2(di_int a) +{ + du_int x2 = (du_int)a; + x2 = x2 - ((x2 >> 1) & 0x5555555555555555uLL); + /* Every 2 bits holds the sum of every pair of bits (32) */ + x2 = ((x2 >> 2) & 0x3333333333333333uLL) + (x2 & 0x3333333333333333uLL); + /* Every 4 bits holds the sum of every 4-set of bits (3 significant bits) (16) */ + x2 = (x2 + (x2 >> 4)) & 0x0F0F0F0F0F0F0F0FuLL; + /* Every 8 bits holds the sum of every 8-set of bits (4 significant bits) (8) */ + su_int x = (su_int)(x2 + (x2 >> 32)); + /* The lower 32 bits hold four 16 bit sums (5 significant bits). */ + /* Upper 32 bits are garbage */ + x = x + (x >> 16); + /* The lower 16 bits hold two 32 bit sums (6 significant bits). */ + /* Upper 16 bits are garbage */ + return (x + (x >> 8)) & 0x0000007F; /* (7 significant bits) */ +} diff --git a/lib/builtins/popcountsi2.c b/lib/builtins/popcountsi2.c new file mode 100644 index 000000000..44544ff49 --- /dev/null +++ b/lib/builtins/popcountsi2.c @@ -0,0 +1,33 @@ +/* ===-- popcountsi2.c - Implement __popcountsi2 ---------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __popcountsi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: count of 1 bits */ + +COMPILER_RT_ABI si_int +__popcountsi2(si_int a) +{ + su_int x = (su_int)a; + x = x - ((x >> 1) & 0x55555555); + /* Every 2 bits holds the sum of every pair of bits */ + x = ((x >> 2) & 0x33333333) + (x & 0x33333333); + /* Every 4 bits holds the sum of every 4-set of bits (3 significant bits) */ + x = (x + (x >> 4)) & 0x0F0F0F0F; + /* Every 8 bits holds the sum of every 8-set of bits (4 significant bits) */ + x = (x + (x >> 16)); + /* The lower 16 bits hold two 8 bit sums (5 significant bits).*/ + /* Upper 16 bits are garbage */ + return (x + (x >> 8)) & 0x0000003F; /* (6 significant bits) */ +} diff --git a/lib/builtins/popcountti2.c b/lib/builtins/popcountti2.c new file mode 100644 index 000000000..95666738f --- /dev/null +++ b/lib/builtins/popcountti2.c @@ -0,0 +1,44 @@ +/* ===-- popcountti2.c - Implement __popcountti2 ----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __popcountti2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: count of 1 bits */ + +si_int +__popcountti2(ti_int a) +{ + tu_int x3 = (tu_int)a; + x3 = x3 - ((x3 >> 1) & (((tu_int)0x5555555555555555uLL << 64) | + 0x5555555555555555uLL)); + /* Every 2 bits holds the sum of every pair of bits (64) */ + x3 = ((x3 >> 2) & (((tu_int)0x3333333333333333uLL << 64) | 0x3333333333333333uLL)) + + (x3 & (((tu_int)0x3333333333333333uLL << 64) | 0x3333333333333333uLL)); + /* Every 4 bits holds the sum of every 4-set of bits (3 significant bits) (32) */ + x3 = (x3 + (x3 >> 4)) + & (((tu_int)0x0F0F0F0F0F0F0F0FuLL << 64) | 0x0F0F0F0F0F0F0F0FuLL); + /* Every 8 bits holds the sum of every 8-set of bits (4 significant bits) (16) */ + du_int x2 = (du_int)(x3 + (x3 >> 64)); + /* Every 8 bits holds the sum of every 8-set of bits (5 significant bits) (8) */ + su_int x = (su_int)(x2 + (x2 >> 32)); + /* Every 8 bits holds the sum of every 8-set of bits (6 significant bits) (4) */ + x = x + (x >> 16); + /* Every 8 bits holds the sum of every 8-set of bits (7 significant bits) (2) */ + /* Upper 16 bits are garbage */ + return (x + (x >> 8)) & 0xFF; /* (8 significant bits) */ +} + +#endif diff --git a/lib/builtins/powidf2.c b/lib/builtins/powidf2.c new file mode 100644 index 000000000..ac13b172b --- /dev/null +++ b/lib/builtins/powidf2.c @@ -0,0 +1,34 @@ +/* ===-- powidf2.cpp - Implement __powidf2 ---------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __powidf2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: a ^ b */ + +COMPILER_RT_ABI double +__powidf2(double a, si_int b) +{ + const int recip = b < 0; + double r = 1; + while (1) + { + if (b & 1) + r *= a; + b /= 2; + if (b == 0) + break; + a *= a; + } + return recip ? 1/r : r; +} diff --git a/lib/builtins/powisf2.c b/lib/builtins/powisf2.c new file mode 100644 index 000000000..0c400ec6d --- /dev/null +++ b/lib/builtins/powisf2.c @@ -0,0 +1,34 @@ +/*===-- powisf2.cpp - Implement __powisf2 ---------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __powisf2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: a ^ b */ + +COMPILER_RT_ABI float +__powisf2(float a, si_int b) +{ + const int recip = b < 0; + float r = 1; + while (1) + { + if (b & 1) + r *= a; + b /= 2; + if (b == 0) + break; + a *= a; + } + return recip ? 1/r : r; +} diff --git a/lib/builtins/powitf2.c b/lib/builtins/powitf2.c new file mode 100644 index 000000000..d3b934924 --- /dev/null +++ b/lib/builtins/powitf2.c @@ -0,0 +1,38 @@ +/* ===-- powitf2.cpp - Implement __powitf2 ---------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __powitf2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if _ARCH_PPC + +/* Returns: a ^ b */ + +long double +__powitf2(long double a, si_int b) +{ + const int recip = b < 0; + long double r = 1; + while (1) + { + if (b & 1) + r *= a; + b /= 2; + if (b == 0) + break; + a *= a; + } + return recip ? 1/r : r; +} + +#endif diff --git a/lib/builtins/powixf2.c b/lib/builtins/powixf2.c new file mode 100644 index 000000000..f050964d3 --- /dev/null +++ b/lib/builtins/powixf2.c @@ -0,0 +1,38 @@ +/* ===-- powixf2.cpp - Implement __powixf2 ---------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __powixf2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#if !_ARCH_PPC + +#include "int_lib.h" + +/* Returns: a ^ b */ + +long double +__powixf2(long double a, si_int b) +{ + const int recip = b < 0; + long double r = 1; + while (1) + { + if (b & 1) + r *= a; + b /= 2; + if (b == 0) + break; + a *= a; + } + return recip ? 1/r : r; +} + +#endif diff --git a/lib/builtins/ppc/DD.h b/lib/builtins/ppc/DD.h new file mode 100644 index 000000000..fc3e41cbe --- /dev/null +++ b/lib/builtins/ppc/DD.h @@ -0,0 +1,46 @@ +#ifndef __DD_HEADER +#define __DD_HEADER + +#include "../int_lib.h" + +typedef union { + long double ld; + struct { + double hi; + double lo; + }s; +}DD; + +typedef union { + double d; + uint64_t x; +} doublebits; + +#define LOWORDER(xy,xHi,xLo,yHi,yLo) \ + (((((xHi)*(yHi) - (xy)) + (xHi)*(yLo)) + (xLo)*(yHi)) + (xLo)*(yLo)) + +static inline double __attribute__((always_inline)) +local_fabs(double x) +{ + doublebits result = { .d = x }; + result.x &= UINT64_C(0x7fffffffffffffff); + return result.d; +} + +static inline double __attribute__((always_inline)) +high26bits(double x) +{ + doublebits result = { .d = x }; + result.x &= UINT64_C(0xfffffffff8000000); + return result.d; +} + +static inline int __attribute__((always_inline)) +different_sign(double x, double y) +{ + doublebits xsignbit = { .d = x }, ysignbit = { .d = y }; + int result = (int)(xsignbit.x >> 63) ^ (int)(ysignbit.x >> 63); + return result; +} + +#endif /* __DD_HEADER */ diff --git a/lib/builtins/ppc/Makefile.mk b/lib/builtins/ppc/Makefile.mk new file mode 100644 index 000000000..0adc623aa --- /dev/null +++ b/lib/builtins/ppc/Makefile.mk @@ -0,0 +1,20 @@ +#===- lib/builtins/ppc/Makefile.mk -------------------------*- Makefile -*--===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# + +ModuleName := builtins +SubDirs := +OnlyArchs := ppc + +AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file))) +Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file))) +ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o) +Implementation := Optimized + +# FIXME: use automatic dependencies? +Dependencies := $(wildcard lib/*.h $(Dir)/*.h) diff --git a/lib/builtins/ppc/divtc3.c b/lib/builtins/ppc/divtc3.c new file mode 100644 index 000000000..299128186 --- /dev/null +++ b/lib/builtins/ppc/divtc3.c @@ -0,0 +1,96 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +#include "DD.h" +#include "../int_math.h" + +#if !defined(CRT_INFINITY) && defined(HUGE_VAL) +#define CRT_INFINITY HUGE_VAL +#endif /* CRT_INFINITY */ + +#define makeFinite(x) { \ + (x).s.hi = crt_copysign(crt_isinf((x).s.hi) ? 1.0 : 0.0, (x).s.hi); \ + (x).s.lo = 0.0; \ + } + +long double __gcc_qadd(long double, long double); +long double __gcc_qsub(long double, long double); +long double __gcc_qmul(long double, long double); +long double __gcc_qdiv(long double, long double); + +long double _Complex +__divtc3(long double a, long double b, long double c, long double d) +{ + DD cDD = { .ld = c }; + DD dDD = { .ld = d }; + + int ilogbw = 0; + const double logbw = crt_logb(crt_fmax(crt_fabs(cDD.s.hi), crt_fabs(dDD.s.hi) )); + + if (crt_isfinite(logbw)) + { + ilogbw = (int)logbw; + + cDD.s.hi = crt_scalbn(cDD.s.hi, -ilogbw); + cDD.s.lo = crt_scalbn(cDD.s.lo, -ilogbw); + dDD.s.hi = crt_scalbn(dDD.s.hi, -ilogbw); + dDD.s.lo = crt_scalbn(dDD.s.lo, -ilogbw); + } + + const long double denom = __gcc_qadd(__gcc_qmul(cDD.ld, cDD.ld), __gcc_qmul(dDD.ld, dDD.ld)); + const long double realNumerator = __gcc_qadd(__gcc_qmul(a,cDD.ld), __gcc_qmul(b,dDD.ld)); + const long double imagNumerator = __gcc_qsub(__gcc_qmul(b,cDD.ld), __gcc_qmul(a,dDD.ld)); + + DD real = { .ld = __gcc_qdiv(realNumerator, denom) }; + DD imag = { .ld = __gcc_qdiv(imagNumerator, denom) }; + + real.s.hi = crt_scalbn(real.s.hi, -ilogbw); + real.s.lo = crt_scalbn(real.s.lo, -ilogbw); + imag.s.hi = crt_scalbn(imag.s.hi, -ilogbw); + imag.s.lo = crt_scalbn(imag.s.lo, -ilogbw); + + if (crt_isnan(real.s.hi) && crt_isnan(imag.s.hi)) + { + DD aDD = { .ld = a }; + DD bDD = { .ld = b }; + DD rDD = { .ld = denom }; + + if ((rDD.s.hi == 0.0) && (!crt_isnan(aDD.s.hi) || + !crt_isnan(bDD.s.hi))) + { + real.s.hi = crt_copysign(CRT_INFINITY,cDD.s.hi) * aDD.s.hi; + real.s.lo = 0.0; + imag.s.hi = crt_copysign(CRT_INFINITY,cDD.s.hi) * bDD.s.hi; + imag.s.lo = 0.0; + } + + else if ((crt_isinf(aDD.s.hi) || crt_isinf(bDD.s.hi)) && + crt_isfinite(cDD.s.hi) && crt_isfinite(dDD.s.hi)) + { + makeFinite(aDD); + makeFinite(bDD); + real.s.hi = CRT_INFINITY * (aDD.s.hi*cDD.s.hi + bDD.s.hi*dDD.s.hi); + real.s.lo = 0.0; + imag.s.hi = CRT_INFINITY * (bDD.s.hi*cDD.s.hi - aDD.s.hi*dDD.s.hi); + imag.s.lo = 0.0; + } + + else if ((crt_isinf(cDD.s.hi) || crt_isinf(dDD.s.hi)) && + crt_isfinite(aDD.s.hi) && crt_isfinite(bDD.s.hi)) + { + makeFinite(cDD); + makeFinite(dDD); + real.s.hi = crt_copysign(0.0,(aDD.s.hi*cDD.s.hi + bDD.s.hi*dDD.s.hi)); + real.s.lo = 0.0; + imag.s.hi = crt_copysign(0.0,(bDD.s.hi*cDD.s.hi - aDD.s.hi*dDD.s.hi)); + imag.s.lo = 0.0; + } + } + + long double _Complex z; + __real__ z = real.ld; + __imag__ z = imag.ld; + + return z; +} diff --git a/lib/builtins/ppc/fixtfdi.c b/lib/builtins/ppc/fixtfdi.c new file mode 100644 index 000000000..56e7b3fbf --- /dev/null +++ b/lib/builtins/ppc/fixtfdi.c @@ -0,0 +1,104 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +/* int64_t __fixunstfdi(long double x); + * This file implements the PowerPC 128-bit double-double -> int64_t conversion + */ + +#include "DD.h" +#include "../int_math.h" + +uint64_t __fixtfdi(long double input) +{ + const DD x = { .ld = input }; + const doublebits hibits = { .d = x.s.hi }; + + const uint32_t absHighWord = (uint32_t)(hibits.x >> 32) & UINT32_C(0x7fffffff); + const uint32_t absHighWordMinusOne = absHighWord - UINT32_C(0x3ff00000); + + /* If (1.0 - tiny) <= input < 0x1.0p63: */ + if (UINT32_C(0x03f00000) > absHighWordMinusOne) + { + /* Do an unsigned conversion of the absolute value, then restore the sign. */ + const int unbiasedHeadExponent = absHighWordMinusOne >> 20; + + int64_t result = hibits.x & INT64_C(0x000fffffffffffff); /* mantissa(hi) */ + result |= INT64_C(0x0010000000000000); /* matissa(hi) with implicit bit */ + result <<= 10; /* mantissa(hi) with one zero preceeding bit. */ + + const int64_t hiNegationMask = ((int64_t)(hibits.x)) >> 63; + + /* If the tail is non-zero, we need to patch in the tail bits. */ + if (0.0 != x.s.lo) + { + const doublebits lobits = { .d = x.s.lo }; + int64_t tailMantissa = lobits.x & INT64_C(0x000fffffffffffff); + tailMantissa |= INT64_C(0x0010000000000000); + + /* At this point we have the mantissa of |tail| */ + /* We need to negate it if head and tail have different signs. */ + const int64_t loNegationMask = ((int64_t)(lobits.x)) >> 63; + const int64_t negationMask = loNegationMask ^ hiNegationMask; + tailMantissa = (tailMantissa ^ negationMask) - negationMask; + + /* Now we have the mantissa of tail as a signed 2s-complement integer */ + + const int biasedTailExponent = (int)(lobits.x >> 52) & 0x7ff; + + /* Shift the tail mantissa into the right position, accounting for the + * bias of 10 that we shifted the head mantissa by. + */ + tailMantissa >>= (unbiasedHeadExponent - (biasedTailExponent - (1023 - 10))); + + result += tailMantissa; + } + + result >>= (62 - unbiasedHeadExponent); + + /* Restore the sign of the result and return */ + result = (result ^ hiNegationMask) - hiNegationMask; + return result; + + } + + /* Edge cases handled here: */ + + /* |x| < 1, result is zero. */ + if (1.0 > crt_fabs(x.s.hi)) + return INT64_C(0); + + /* x very close to INT64_MIN, care must be taken to see which side we are on. */ + if (x.s.hi == -0x1.0p63) { + + int64_t result = INT64_MIN; + + if (0.0 < x.s.lo) + { + /* If the tail is positive, the correct result is something other than INT64_MIN. + * we'll need to figure out what it is. + */ + + const doublebits lobits = { .d = x.s.lo }; + int64_t tailMantissa = lobits.x & INT64_C(0x000fffffffffffff); + tailMantissa |= INT64_C(0x0010000000000000); + + /* Now we negate the tailMantissa */ + tailMantissa = (tailMantissa ^ INT64_C(-1)) + INT64_C(1); + + /* And shift it by the appropriate amount */ + const int biasedTailExponent = (int)(lobits.x >> 52) & 0x7ff; + tailMantissa >>= 1075 - biasedTailExponent; + + result -= tailMantissa; + } + + return result; + } + + /* Signed overflows, infinities, and NaNs */ + if (x.s.hi > 0.0) + return INT64_MAX; + else + return INT64_MIN; +} diff --git a/lib/builtins/ppc/fixunstfdi.c b/lib/builtins/ppc/fixunstfdi.c new file mode 100644 index 000000000..5e6e2cedf --- /dev/null +++ b/lib/builtins/ppc/fixunstfdi.c @@ -0,0 +1,59 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +/* uint64_t __fixunstfdi(long double x); */ +/* This file implements the PowerPC 128-bit double-double -> uint64_t conversion */ + +#include "DD.h" + +uint64_t __fixunstfdi(long double input) +{ + const DD x = { .ld = input }; + const doublebits hibits = { .d = x.s.hi }; + + const uint32_t highWordMinusOne = (uint32_t)(hibits.x >> 32) - UINT32_C(0x3ff00000); + + /* If (1.0 - tiny) <= input < 0x1.0p64: */ + if (UINT32_C(0x04000000) > highWordMinusOne) + { + const int unbiasedHeadExponent = highWordMinusOne >> 20; + + uint64_t result = hibits.x & UINT64_C(0x000fffffffffffff); /* mantissa(hi) */ + result |= UINT64_C(0x0010000000000000); /* matissa(hi) with implicit bit */ + result <<= 11; /* mantissa(hi) left aligned in the int64 field. */ + + /* If the tail is non-zero, we need to patch in the tail bits. */ + if (0.0 != x.s.lo) + { + const doublebits lobits = { .d = x.s.lo }; + int64_t tailMantissa = lobits.x & INT64_C(0x000fffffffffffff); + tailMantissa |= INT64_C(0x0010000000000000); + + /* At this point we have the mantissa of |tail| */ + + const int64_t negationMask = ((int64_t)(lobits.x)) >> 63; + tailMantissa = (tailMantissa ^ negationMask) - negationMask; + + /* Now we have the mantissa of tail as a signed 2s-complement integer */ + + const int biasedTailExponent = (int)(lobits.x >> 52) & 0x7ff; + + /* Shift the tail mantissa into the right position, accounting for the + * bias of 11 that we shifted the head mantissa by. + */ + tailMantissa >>= (unbiasedHeadExponent - (biasedTailExponent - (1023 - 11))); + + result += tailMantissa; + } + + result >>= (63 - unbiasedHeadExponent); + return result; + } + + /* Edge cases are handled here, with saturation. */ + if (1.0 > x.s.hi) + return UINT64_C(0); + else + return UINT64_MAX; +} diff --git a/lib/builtins/ppc/floatditf.c b/lib/builtins/ppc/floatditf.c new file mode 100644 index 000000000..beabdd017 --- /dev/null +++ b/lib/builtins/ppc/floatditf.c @@ -0,0 +1,36 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +/* long double __floatditf(long long x); */ +/* This file implements the PowerPC long long -> long double conversion */ + +#include "DD.h" + +long double __floatditf(int64_t a) { + + static const double twop32 = 0x1.0p32; + static const double twop52 = 0x1.0p52; + + doublebits low = { .d = twop52 }; + low.x |= a & UINT64_C(0x00000000ffffffff); /* 0x1.0p52 + low 32 bits of a. */ + + const double high_addend = (double)((int32_t)(a >> 32))*twop32 - twop52; + + /* At this point, we have two double precision numbers + * high_addend and low.d, and we wish to return their sum + * as a canonicalized long double: + */ + + /* This implementation sets the inexact flag spuriously. + * This could be avoided, but at some substantial cost. + */ + + DD result; + + result.s.hi = high_addend + low.d; + result.s.lo = (high_addend - result.s.hi) + low.d; + + return result.ld; + +} diff --git a/lib/builtins/ppc/floatunditf.c b/lib/builtins/ppc/floatunditf.c new file mode 100644 index 000000000..b12e1e738 --- /dev/null +++ b/lib/builtins/ppc/floatunditf.c @@ -0,0 +1,41 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +/* long double __floatunditf(unsigned long long x); */ +/* This file implements the PowerPC unsigned long long -> long double conversion */ + +#include "DD.h" + +long double __floatunditf(uint64_t a) { + + /* Begins with an exact copy of the code from __floatundidf */ + + static const double twop52 = 0x1.0p52; + static const double twop84 = 0x1.0p84; + static const double twop84_plus_twop52 = 0x1.00000001p84; + + doublebits high = { .d = twop84 }; + doublebits low = { .d = twop52 }; + + high.x |= a >> 32; /* 0x1.0p84 + high 32 bits of a */ + low.x |= a & UINT64_C(0x00000000ffffffff); /* 0x1.0p52 + low 32 bits of a */ + + const double high_addend = high.d - twop84_plus_twop52; + + /* At this point, we have two double precision numbers + * high_addend and low.d, and we wish to return their sum + * as a canonicalized long double: + */ + + /* This implementation sets the inexact flag spuriously. */ + /* This could be avoided, but at some substantial cost. */ + + DD result; + + result.s.hi = high_addend + low.d; + result.s.lo = (high_addend - result.s.hi) + low.d; + + return result.ld; + +} diff --git a/lib/builtins/ppc/gcc_qadd.c b/lib/builtins/ppc/gcc_qadd.c new file mode 100644 index 000000000..32e16e9d1 --- /dev/null +++ b/lib/builtins/ppc/gcc_qadd.c @@ -0,0 +1,76 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +/* long double __gcc_qadd(long double x, long double y); + * This file implements the PowerPC 128-bit double-double add operation. + * This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!) + */ + +#include "DD.h" + +long double __gcc_qadd(long double x, long double y) +{ + static const uint32_t infinityHi = UINT32_C(0x7ff00000); + + DD dst = { .ld = x }, src = { .ld = y }; + + register double A = dst.s.hi, a = dst.s.lo, + B = src.s.hi, b = src.s.lo; + + /* If both operands are zero: */ + if ((A == 0.0) && (B == 0.0)) { + dst.s.hi = A + B; + dst.s.lo = 0.0; + return dst.ld; + } + + /* If either operand is NaN or infinity: */ + const doublebits abits = { .d = A }; + const doublebits bbits = { .d = B }; + if ((((uint32_t)(abits.x >> 32) & infinityHi) == infinityHi) || + (((uint32_t)(bbits.x >> 32) & infinityHi) == infinityHi)) { + dst.s.hi = A + B; + dst.s.lo = 0.0; + return dst.ld; + } + + /* If the computation overflows: */ + /* This may be playing things a little bit fast and loose, but it will do for a start. */ + const double testForOverflow = A + (B + (a + b)); + const doublebits testbits = { .d = testForOverflow }; + if (((uint32_t)(testbits.x >> 32) & infinityHi) == infinityHi) { + dst.s.hi = testForOverflow; + dst.s.lo = 0.0; + return dst.ld; + } + + double H, h; + double T, t; + double W, w; + double Y; + + H = B + (A - (A + B)); + T = b + (a - (a + b)); + h = A + (B - (A + B)); + t = a + (b - (a + b)); + + if (local_fabs(A) <= local_fabs(B)) + w = (a + b) + h; + else + w = (a + b) + H; + + W = (A + B) + w; + Y = (A + B) - W; + Y += w; + + if (local_fabs(a) <= local_fabs(b)) + w = t + Y; + else + w = T + Y; + + dst.s.hi = Y = W + w; + dst.s.lo = (W - Y) + w; + + return dst.ld; +} diff --git a/lib/builtins/ppc/gcc_qdiv.c b/lib/builtins/ppc/gcc_qdiv.c new file mode 100644 index 000000000..70aa00b64 --- /dev/null +++ b/lib/builtins/ppc/gcc_qdiv.c @@ -0,0 +1,55 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +/* long double __gcc_qdiv(long double x, long double y); + * This file implements the PowerPC 128-bit double-double division operation. + * This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!) + */ + +#include "DD.h" + +long double __gcc_qdiv(long double a, long double b) +{ + static const uint32_t infinityHi = UINT32_C(0x7ff00000); + DD dst = { .ld = a }, src = { .ld = b }; + + register double x = dst.s.hi, x1 = dst.s.lo, + y = src.s.hi, y1 = src.s.lo; + + double yHi, yLo, qHi, qLo; + double yq, tmp, q; + + q = x / y; + + /* Detect special cases */ + if (q == 0.0) { + dst.s.hi = q; + dst.s.lo = 0.0; + return dst.ld; + } + + const doublebits qBits = { .d = q }; + if (((uint32_t)(qBits.x >> 32) & infinityHi) == infinityHi) { + dst.s.hi = q; + dst.s.lo = 0.0; + return dst.ld; + } + + yHi = high26bits(y); + qHi = high26bits(q); + + yq = y * q; + yLo = y - yHi; + qLo = q - qHi; + + tmp = LOWORDER(yq, yHi, yLo, qHi, qLo); + tmp = (x - yq) - tmp; + tmp = ((tmp + x1) - y1 * q) / y; + x = q + tmp; + + dst.s.lo = (q - x) + tmp; + dst.s.hi = x; + + return dst.ld; +} diff --git a/lib/builtins/ppc/gcc_qmul.c b/lib/builtins/ppc/gcc_qmul.c new file mode 100644 index 000000000..fb4c5164c --- /dev/null +++ b/lib/builtins/ppc/gcc_qmul.c @@ -0,0 +1,53 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +/* long double __gcc_qmul(long double x, long double y); + * This file implements the PowerPC 128-bit double-double multiply operation. + * This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!) + */ + +#include "DD.h" + +long double __gcc_qmul(long double x, long double y) +{ + static const uint32_t infinityHi = UINT32_C(0x7ff00000); + DD dst = { .ld = x }, src = { .ld = y }; + + register double A = dst.s.hi, a = dst.s.lo, + B = src.s.hi, b = src.s.lo; + + double aHi, aLo, bHi, bLo; + double ab, tmp, tau; + + ab = A * B; + + /* Detect special cases */ + if (ab == 0.0) { + dst.s.hi = ab; + dst.s.lo = 0.0; + return dst.ld; + } + + const doublebits abBits = { .d = ab }; + if (((uint32_t)(abBits.x >> 32) & infinityHi) == infinityHi) { + dst.s.hi = ab; + dst.s.lo = 0.0; + return dst.ld; + } + + /* Generic cases handled here. */ + aHi = high26bits(A); + bHi = high26bits(B); + aLo = A - aHi; + bLo = B - bHi; + + tmp = LOWORDER(ab, aHi, aLo, bHi, bLo); + tmp += (A * b + a * B); + tau = ab + tmp; + + dst.s.lo = (ab - tau) + tmp; + dst.s.hi = tau; + + return dst.ld; +} diff --git a/lib/builtins/ppc/gcc_qsub.c b/lib/builtins/ppc/gcc_qsub.c new file mode 100644 index 000000000..c092e24db --- /dev/null +++ b/lib/builtins/ppc/gcc_qsub.c @@ -0,0 +1,76 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +/* long double __gcc_qsub(long double x, long double y); + * This file implements the PowerPC 128-bit double-double add operation. + * This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!) + */ + +#include "DD.h" + +long double __gcc_qsub(long double x, long double y) +{ + static const uint32_t infinityHi = UINT32_C(0x7ff00000); + + DD dst = { .ld = x }, src = { .ld = y }; + + register double A = dst.s.hi, a = dst.s.lo, + B = -src.s.hi, b = -src.s.lo; + + /* If both operands are zero: */ + if ((A == 0.0) && (B == 0.0)) { + dst.s.hi = A + B; + dst.s.lo = 0.0; + return dst.ld; + } + + /* If either operand is NaN or infinity: */ + const doublebits abits = { .d = A }; + const doublebits bbits = { .d = B }; + if ((((uint32_t)(abits.x >> 32) & infinityHi) == infinityHi) || + (((uint32_t)(bbits.x >> 32) & infinityHi) == infinityHi)) { + dst.s.hi = A + B; + dst.s.lo = 0.0; + return dst.ld; + } + + /* If the computation overflows: */ + /* This may be playing things a little bit fast and loose, but it will do for a start. */ + const double testForOverflow = A + (B + (a + b)); + const doublebits testbits = { .d = testForOverflow }; + if (((uint32_t)(testbits.x >> 32) & infinityHi) == infinityHi) { + dst.s.hi = testForOverflow; + dst.s.lo = 0.0; + return dst.ld; + } + + double H, h; + double T, t; + double W, w; + double Y; + + H = B + (A - (A + B)); + T = b + (a - (a + b)); + h = A + (B - (A + B)); + t = a + (b - (a + b)); + + if (local_fabs(A) <= local_fabs(B)) + w = (a + b) + h; + else + w = (a + b) + H; + + W = (A + B) + w; + Y = (A + B) - W; + Y += w; + + if (local_fabs(a) <= local_fabs(b)) + w = t + Y; + else + w = T + Y; + + dst.s.hi = Y = W + w; + dst.s.lo = (W - Y) + w; + + return dst.ld; +} diff --git a/lib/builtins/ppc/multc3.c b/lib/builtins/ppc/multc3.c new file mode 100644 index 000000000..738b65a83 --- /dev/null +++ b/lib/builtins/ppc/multc3.c @@ -0,0 +1,94 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +#include "DD.h" +#include "../int_math.h" + +#define makeFinite(x) { \ + (x).s.hi = crt_copysign(crt_isinf((x).s.hi) ? 1.0 : 0.0, (x).s.hi); \ + (x).s.lo = 0.0; \ + } + +#define zeroNaN(x) { \ + if (crt_isnan((x).s.hi)) { \ + (x).s.hi = crt_copysign(0.0, (x).s.hi); \ + (x).s.lo = 0.0; \ + } \ + } + +long double __gcc_qadd(long double, long double); +long double __gcc_qsub(long double, long double); +long double __gcc_qmul(long double, long double); + +long double _Complex +__multc3(long double a, long double b, long double c, long double d) +{ + long double ac = __gcc_qmul(a,c); + long double bd = __gcc_qmul(b,d); + long double ad = __gcc_qmul(a,d); + long double bc = __gcc_qmul(b,c); + + DD real = { .ld = __gcc_qsub(ac,bd) }; + DD imag = { .ld = __gcc_qadd(ad,bc) }; + + if (crt_isnan(real.s.hi) && crt_isnan(imag.s.hi)) + { + int recalc = 0; + + DD aDD = { .ld = a }; + DD bDD = { .ld = b }; + DD cDD = { .ld = c }; + DD dDD = { .ld = d }; + + if (crt_isinf(aDD.s.hi) || crt_isinf(bDD.s.hi)) + { + makeFinite(aDD); + makeFinite(bDD); + zeroNaN(cDD); + zeroNaN(dDD); + recalc = 1; + } + + if (crt_isinf(cDD.s.hi) || crt_isinf(dDD.s.hi)) + { + makeFinite(cDD); + makeFinite(dDD); + zeroNaN(aDD); + zeroNaN(bDD); + recalc = 1; + } + + if (!recalc) + { + DD acDD = { .ld = ac }; + DD bdDD = { .ld = bd }; + DD adDD = { .ld = ad }; + DD bcDD = { .ld = bc }; + + if (crt_isinf(acDD.s.hi) || crt_isinf(bdDD.s.hi) || + crt_isinf(adDD.s.hi) || crt_isinf(bcDD.s.hi)) + { + zeroNaN(aDD); + zeroNaN(bDD); + zeroNaN(cDD); + zeroNaN(dDD); + recalc = 1; + } + } + + if (recalc) + { + real.s.hi = CRT_INFINITY * (aDD.s.hi*cDD.s.hi - bDD.s.hi*dDD.s.hi); + real.s.lo = 0.0; + imag.s.hi = CRT_INFINITY * (aDD.s.hi*dDD.s.hi + bDD.s.hi*cDD.s.hi); + imag.s.lo = 0.0; + } + } + + long double _Complex z; + __real__ z = real.ld; + __imag__ z = imag.ld; + + return z; +} diff --git a/lib/builtins/ppc/restFP.S b/lib/builtins/ppc/restFP.S new file mode 100644 index 000000000..95032897c --- /dev/null +++ b/lib/builtins/ppc/restFP.S @@ -0,0 +1,43 @@ +//===-- restFP.S - Implement restFP ---------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// Helper function used by compiler to restore ppc floating point registers at +// the end of the function epilog. This function returns to the address +// in the LR slot. So a function epilog must branch (b) not branch and link +// (bl) to this function. +// If the compiler wants to restore f27..f31, it does a "b restFP+52" +// +// This function should never be exported by a shared library. Each linkage +// unit carries its own copy of this function. +// +DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(restFP) + lfd f14,-144(r1) + lfd f15,-136(r1) + lfd f16,-128(r1) + lfd f17,-120(r1) + lfd f18,-112(r1) + lfd f19,-104(r1) + lfd f20,-96(r1) + lfd f21,-88(r1) + lfd f22,-80(r1) + lfd f23,-72(r1) + lfd f24,-64(r1) + lfd f25,-56(r1) + lfd f26,-48(r1) + lfd f27,-40(r1) + lfd f28,-32(r1) + lfd f29,-24(r1) + lfd f30,-16(r1) + lfd f31,-8(r1) + lwz r0,8(r1) + mtlr r0 + blr diff --git a/lib/builtins/ppc/saveFP.S b/lib/builtins/ppc/saveFP.S new file mode 100644 index 000000000..72bd459f4 --- /dev/null +++ b/lib/builtins/ppc/saveFP.S @@ -0,0 +1,40 @@ +//===-- saveFP.S - Implement saveFP ---------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// +// Helper function used by compiler to save ppc floating point registers in +// function prologs. This routines also saves r0 in the LR slot. +// If the compiler wants to save f27..f31, it does a "bl saveFP+52" +// +// This function should never be exported by a shared library. Each linkage +// unit carries its own copy of this function. +// +DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(saveFP) + stfd f14,-144(r1) + stfd f15,-136(r1) + stfd f16,-128(r1) + stfd f17,-120(r1) + stfd f18,-112(r1) + stfd f19,-104(r1) + stfd f20,-96(r1) + stfd f21,-88(r1) + stfd f22,-80(r1) + stfd f23,-72(r1) + stfd f24,-64(r1) + stfd f25,-56(r1) + stfd f26,-48(r1) + stfd f27,-40(r1) + stfd f28,-32(r1) + stfd f29,-24(r1) + stfd f30,-16(r1) + stfd f31,-8(r1) + stw r0,8(r1) + blr diff --git a/lib/builtins/subdf3.c b/lib/builtins/subdf3.c new file mode 100644 index 000000000..66fb1a54f --- /dev/null +++ b/lib/builtins/subdf3.c @@ -0,0 +1,29 @@ +//===-- lib/adddf3.c - Double-precision subtraction ---------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements double-precision soft-float subtraction with the +// IEEE-754 default rounding (to nearest, ties to even). +// +//===----------------------------------------------------------------------===// + +#define DOUBLE_PRECISION +#include "fp_lib.h" + +fp_t COMPILER_RT_ABI __adddf3(fp_t a, fp_t b); + + +ARM_EABI_FNALIAS(dsub, subdf3) + +// Subtraction; flip the sign bit of b and add. +COMPILER_RT_ABI fp_t +__subdf3(fp_t a, fp_t b) { + return __adddf3(a, fromRep(toRep(b) ^ signBit)); +} + +/* FIXME: rsub for ARM EABI */ diff --git a/lib/builtins/subsf3.c b/lib/builtins/subsf3.c new file mode 100644 index 000000000..3659cd8b8 --- /dev/null +++ b/lib/builtins/subsf3.c @@ -0,0 +1,28 @@ +//===-- lib/subsf3.c - Single-precision subtraction ---------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements single-precision soft-float subtraction with the +// IEEE-754 default rounding (to nearest, ties to even). +// +//===----------------------------------------------------------------------===// + +#define SINGLE_PRECISION +#include "fp_lib.h" + +fp_t COMPILER_RT_ABI __addsf3(fp_t a, fp_t b); + +ARM_EABI_FNALIAS(fsub, subsf3) + +// Subtraction; flip the sign bit of b and add. +COMPILER_RT_ABI fp_t +__subsf3(fp_t a, fp_t b) { + return __addsf3(a, fromRep(toRep(b) ^ signBit)); +} + +/* FIXME: rsub for ARM EABI */ diff --git a/lib/builtins/subvdi3.c b/lib/builtins/subvdi3.c new file mode 100644 index 000000000..0f1f924ef --- /dev/null +++ b/lib/builtins/subvdi3.c @@ -0,0 +1,36 @@ +/* ===-- subvdi3.c - Implement __subvdi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __subvdi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: a - b */ + +/* Effects: aborts if a - b overflows */ + +COMPILER_RT_ABI di_int +__subvdi3(di_int a, di_int b) +{ + di_int s = a - b; + if (b >= 0) + { + if (s > a) + compilerrt_abort(); + } + else + { + if (s <= a) + compilerrt_abort(); + } + return s; +} diff --git a/lib/builtins/subvsi3.c b/lib/builtins/subvsi3.c new file mode 100644 index 000000000..ec4594c9f --- /dev/null +++ b/lib/builtins/subvsi3.c @@ -0,0 +1,36 @@ +/* ===-- subvsi3.c - Implement __subvsi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __subvsi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: a - b */ + +/* Effects: aborts if a - b overflows */ + +COMPILER_RT_ABI si_int +__subvsi3(si_int a, si_int b) +{ + si_int s = a - b; + if (b >= 0) + { + if (s > a) + compilerrt_abort(); + } + else + { + if (s <= a) + compilerrt_abort(); + } + return s; +} diff --git a/lib/builtins/subvti3.c b/lib/builtins/subvti3.c new file mode 100644 index 000000000..b32df5e6c --- /dev/null +++ b/lib/builtins/subvti3.c @@ -0,0 +1,40 @@ +/* ===-- subvti3.c - Implement __subvti3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __subvti3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: a - b */ + +/* Effects: aborts if a - b overflows */ + +ti_int +__subvti3(ti_int a, ti_int b) +{ + ti_int s = a - b; + if (b >= 0) + { + if (s > a) + compilerrt_abort(); + } + else + { + if (s <= a) + compilerrt_abort(); + } + return s; +} + +#endif /* __x86_64 */ diff --git a/lib/builtins/trampoline_setup.c b/lib/builtins/trampoline_setup.c new file mode 100644 index 000000000..e0765b16b --- /dev/null +++ b/lib/builtins/trampoline_setup.c @@ -0,0 +1,47 @@ +/* ===----- trampoline_setup.c - Implement __trampoline_setup -------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +extern void __clear_cache(void* start, void* end); + +/* + * The ppc compiler generates calls to __trampoline_setup() when creating + * trampoline functions on the stack for use with nested functions. + * This function creates a custom 40-byte trampoline function on the stack + * which loads r11 with a pointer to the outer function's locals + * and then jumps to the target nested function. + */ + +#if __ppc__ && !defined(__powerpc64__) +void __trampoline_setup(uint32_t* trampOnStack, int trampSizeAllocated, + const void* realFunc, void* localsPtr) +{ + /* should never happen, but if compiler did not allocate */ + /* enough space on stack for the trampoline, abort */ + if ( trampSizeAllocated < 40 ) + compilerrt_abort(); + + /* create trampoline */ + trampOnStack[0] = 0x7c0802a6; /* mflr r0 */ + trampOnStack[1] = 0x4800000d; /* bl Lbase */ + trampOnStack[2] = (uint32_t)realFunc; + trampOnStack[3] = (uint32_t)localsPtr; + trampOnStack[4] = 0x7d6802a6; /* Lbase: mflr r11 */ + trampOnStack[5] = 0x818b0000; /* lwz r12,0(r11) */ + trampOnStack[6] = 0x7c0803a6; /* mtlr r0 */ + trampOnStack[7] = 0x7d8903a6; /* mtctr r12 */ + trampOnStack[8] = 0x816b0004; /* lwz r11,4(r11) */ + trampOnStack[9] = 0x4e800420; /* bctr */ + + /* clear instruction cache */ + __clear_cache(trampOnStack, &trampOnStack[10]); +} +#endif /* __ppc__ && !defined(__powerpc64__) */ diff --git a/lib/builtins/truncdfsf2.c b/lib/builtins/truncdfsf2.c new file mode 100644 index 000000000..61c909a22 --- /dev/null +++ b/lib/builtins/truncdfsf2.c @@ -0,0 +1,168 @@ +//===-- lib/truncdfsf2.c - double -> single conversion ------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a fairly generic conversion from a wider to a narrower +// IEEE-754 floating-point type in the default (round to nearest, ties to even) +// rounding mode. The constants and types defined following the includes below +// parameterize the conversion. +// +// This routine can be trivially adapted to support conversions to +// half-precision or from quad-precision. It does not support types that don't +// use the usual IEEE-754 interchange formats; specifically, some work would be +// needed to adapt it to (for example) the Intel 80-bit format or PowerPC +// double-double format. +// +// Note please, however, that this implementation is only intended to support +// *narrowing* operations; if you need to convert to a *wider* floating-point +// type (e.g. float -> double), then this routine will not do what you want it +// to. +// +// It also requires that integer types at least as large as both formats +// are available on the target platform; this may pose a problem when trying +// to add support for quad on some 32-bit systems, for example. +// +// Finally, the following assumptions are made: +// +// 1. floating-point types and integer types have the same endianness on the +// target platform +// +// 2. quiet NaNs, if supported, are indicated by the leading bit of the +// significand field being set +// +//===----------------------------------------------------------------------===// + +#include "int_lib.h" + +typedef double src_t; +typedef uint64_t src_rep_t; +#define SRC_REP_C UINT64_C +static const int srcSigBits = 52; + +typedef float dst_t; +typedef uint32_t dst_rep_t; +#define DST_REP_C UINT32_C +static const int dstSigBits = 23; + +// End of specialization parameters. Two helper routines for conversion to and +// from the representation of floating-point data as integer values follow. + +static inline src_rep_t srcToRep(src_t x) { + const union { src_t f; src_rep_t i; } rep = {.f = x}; + return rep.i; +} + +static inline dst_t dstFromRep(dst_rep_t x) { + const union { dst_t f; dst_rep_t i; } rep = {.i = x}; + return rep.f; +} + +// End helper routines. Conversion implementation follows. + +ARM_EABI_FNALIAS(d2f, truncdfsf2) + +COMPILER_RT_ABI dst_t +__truncdfsf2(src_t a) { + + // Various constants whose values follow from the type parameters. + // Any reasonable optimizer will fold and propagate all of these. + const int srcBits = sizeof(src_t)*CHAR_BIT; + const int srcExpBits = srcBits - srcSigBits - 1; + const int srcInfExp = (1 << srcExpBits) - 1; + const int srcExpBias = srcInfExp >> 1; + + const src_rep_t srcMinNormal = SRC_REP_C(1) << srcSigBits; + const src_rep_t significandMask = srcMinNormal - 1; + const src_rep_t srcInfinity = (src_rep_t)srcInfExp << srcSigBits; + const src_rep_t srcSignMask = SRC_REP_C(1) << (srcSigBits + srcExpBits); + const src_rep_t srcAbsMask = srcSignMask - 1; + const src_rep_t roundMask = (SRC_REP_C(1) << (srcSigBits - dstSigBits)) - 1; + const src_rep_t halfway = SRC_REP_C(1) << (srcSigBits - dstSigBits - 1); + + const int dstBits = sizeof(dst_t)*CHAR_BIT; + const int dstExpBits = dstBits - dstSigBits - 1; + const int dstInfExp = (1 << dstExpBits) - 1; + const int dstExpBias = dstInfExp >> 1; + + const int underflowExponent = srcExpBias + 1 - dstExpBias; + const int overflowExponent = srcExpBias + dstInfExp - dstExpBias; + const src_rep_t underflow = (src_rep_t)underflowExponent << srcSigBits; + const src_rep_t overflow = (src_rep_t)overflowExponent << srcSigBits; + + const dst_rep_t dstQNaN = DST_REP_C(1) << (dstSigBits - 1); + const dst_rep_t dstNaNCode = dstQNaN - 1; + + // Break a into a sign and representation of the absolute value + const src_rep_t aRep = srcToRep(a); + const src_rep_t aAbs = aRep & srcAbsMask; + const src_rep_t sign = aRep & srcSignMask; + dst_rep_t absResult; + + if (aAbs - underflow < aAbs - overflow) { + // The exponent of a is within the range of normal numbers in the + // destination format. We can convert by simply right-shifting with + // rounding and adjusting the exponent. + absResult = aAbs >> (srcSigBits - dstSigBits); + absResult -= (dst_rep_t)(srcExpBias - dstExpBias) << dstSigBits; + + const src_rep_t roundBits = aAbs & roundMask; + + // Round to nearest + if (roundBits > halfway) + absResult++; + + // Ties to even + else if (roundBits == halfway) + absResult += absResult & 1; + } + + else if (aAbs > srcInfinity) { + // a is NaN. + // Conjure the result by beginning with infinity, setting the qNaN + // bit and inserting the (truncated) trailing NaN field. + absResult = (dst_rep_t)dstInfExp << dstSigBits; + absResult |= dstQNaN; + absResult |= aAbs & dstNaNCode; + } + + else if (aAbs > overflow) { + // a overflows to infinity. + absResult = (dst_rep_t)dstInfExp << dstSigBits; + } + + else { + // a underflows on conversion to the destination type or is an exact + // zero. The result may be a denormal or zero. Extract the exponent + // to get the shift amount for the denormalization. + const int aExp = aAbs >> srcSigBits; + const int shift = srcExpBias - dstExpBias - aExp + 1; + + const src_rep_t significand = (aRep & significandMask) | srcMinNormal; + + // Right shift by the denormalization amount with sticky. + if (shift > srcSigBits) { + absResult = 0; + } else { + const bool sticky = significand << (srcBits - shift); + src_rep_t denormalizedSignificand = significand >> shift | sticky; + absResult = denormalizedSignificand >> (srcSigBits - dstSigBits); + const src_rep_t roundBits = denormalizedSignificand & roundMask; + // Round to nearest + if (roundBits > halfway) + absResult++; + // Ties to even + else if (roundBits == halfway) + absResult += absResult & 1; + } + } + + // Apply the signbit to (dst_t)abs(a). + const dst_rep_t result = absResult | sign >> (srcBits - dstBits); + return dstFromRep(result); + +} diff --git a/lib/builtins/ucmpdi2.c b/lib/builtins/ucmpdi2.c new file mode 100644 index 000000000..40af23613 --- /dev/null +++ b/lib/builtins/ucmpdi2.c @@ -0,0 +1,51 @@ +/* ===-- ucmpdi2.c - Implement __ucmpdi2 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __ucmpdi2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: if (a < b) returns 0 + * if (a == b) returns 1 + * if (a > b) returns 2 + */ + +COMPILER_RT_ABI si_int +__ucmpdi2(du_int a, du_int b) +{ + udwords x; + x.all = a; + udwords y; + y.all = b; + if (x.s.high < y.s.high) + return 0; + if (x.s.high > y.s.high) + return 2; + if (x.s.low < y.s.low) + return 0; + if (x.s.low > y.s.low) + return 2; + return 1; +} + +#ifdef __ARM_EABI__ +/* Returns: if (a < b) returns -1 +* if (a == b) returns 0 +* if (a > b) returns 1 +*/ +COMPILER_RT_ABI si_int +__aeabi_ulcmp(di_int a, di_int b) +{ + return __ucmpdi2(a, b) - 1; +} +#endif + diff --git a/lib/builtins/ucmpti2.c b/lib/builtins/ucmpti2.c new file mode 100644 index 000000000..5466d2174 --- /dev/null +++ b/lib/builtins/ucmpti2.c @@ -0,0 +1,42 @@ +/* ===-- ucmpti2.c - Implement __ucmpti2 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __ucmpti2 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Returns: if (a < b) returns 0 + * if (a == b) returns 1 + * if (a > b) returns 2 + */ + +si_int +__ucmpti2(tu_int a, tu_int b) +{ + utwords x; + x.all = a; + utwords y; + y.all = b; + if (x.s.high < y.s.high) + return 0; + if (x.s.high > y.s.high) + return 2; + if (x.s.low < y.s.low) + return 0; + if (x.s.low > y.s.low) + return 2; + return 1; +} + +#endif diff --git a/lib/builtins/udivdi3.c b/lib/builtins/udivdi3.c new file mode 100644 index 000000000..6c0303df3 --- /dev/null +++ b/lib/builtins/udivdi3.c @@ -0,0 +1,25 @@ +/* ===-- udivdi3.c - Implement __udivdi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __udivdi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +du_int COMPILER_RT_ABI __udivmoddi4(du_int a, du_int b, du_int* rem); + +/* Returns: a / b */ + +COMPILER_RT_ABI du_int +__udivdi3(du_int a, du_int b) +{ + return __udivmoddi4(a, b, 0); +} diff --git a/lib/builtins/udivmoddi4.c b/lib/builtins/udivmoddi4.c new file mode 100644 index 000000000..57282d5b5 --- /dev/null +++ b/lib/builtins/udivmoddi4.c @@ -0,0 +1,251 @@ +/* ===-- udivmoddi4.c - Implement __udivmoddi4 -----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __udivmoddi4 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Effects: if rem != 0, *rem = a % b + * Returns: a / b + */ + +/* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */ + +COMPILER_RT_ABI du_int +__udivmoddi4(du_int a, du_int b, du_int* rem) +{ + const unsigned n_uword_bits = sizeof(su_int) * CHAR_BIT; + const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT; + udwords n; + n.all = a; + udwords d; + d.all = b; + udwords q; + udwords r; + unsigned sr; + /* special cases, X is unknown, K != 0 */ + if (n.s.high == 0) + { + if (d.s.high == 0) + { + /* 0 X + * --- + * 0 X + */ + if (rem) + *rem = n.s.low % d.s.low; + return n.s.low / d.s.low; + } + /* 0 X + * --- + * K X + */ + if (rem) + *rem = n.s.low; + return 0; + } + /* n.s.high != 0 */ + if (d.s.low == 0) + { + if (d.s.high == 0) + { + /* K X + * --- + * 0 0 + */ + if (rem) + *rem = n.s.high % d.s.low; + return n.s.high / d.s.low; + } + /* d.s.high != 0 */ + if (n.s.low == 0) + { + /* K 0 + * --- + * K 0 + */ + if (rem) + { + r.s.high = n.s.high % d.s.high; + r.s.low = 0; + *rem = r.all; + } + return n.s.high / d.s.high; + } + /* K K + * --- + * K 0 + */ + if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */ + { + if (rem) + { + r.s.low = n.s.low; + r.s.high = n.s.high & (d.s.high - 1); + *rem = r.all; + } + return n.s.high >> __builtin_ctz(d.s.high); + } + /* K K + * --- + * K 0 + */ + sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high); + /* 0 <= sr <= n_uword_bits - 2 or sr large */ + if (sr > n_uword_bits - 2) + { + if (rem) + *rem = n.all; + return 0; + } + ++sr; + /* 1 <= sr <= n_uword_bits - 1 */ + /* q.all = n.all << (n_udword_bits - sr); */ + q.s.low = 0; + q.s.high = n.s.low << (n_uword_bits - sr); + /* r.all = n.all >> sr; */ + r.s.high = n.s.high >> sr; + r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + } + else /* d.s.low != 0 */ + { + if (d.s.high == 0) + { + /* K X + * --- + * 0 K + */ + if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */ + { + if (rem) + *rem = n.s.low & (d.s.low - 1); + if (d.s.low == 1) + return n.all; + sr = __builtin_ctz(d.s.low); + q.s.high = n.s.high >> sr; + q.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + return q.all; + } + /* K X + * --- + *0 K + */ + sr = 1 + n_uword_bits + __builtin_clz(d.s.low) - __builtin_clz(n.s.high); + /* 2 <= sr <= n_udword_bits - 1 + * q.all = n.all << (n_udword_bits - sr); + * r.all = n.all >> sr; + * if (sr == n_uword_bits) + * { + * q.s.low = 0; + * q.s.high = n.s.low; + * r.s.high = 0; + * r.s.low = n.s.high; + * } + * else if (sr < n_uword_bits) // 2 <= sr <= n_uword_bits - 1 + * { + * q.s.low = 0; + * q.s.high = n.s.low << (n_uword_bits - sr); + * r.s.high = n.s.high >> sr; + * r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + * } + * else // n_uword_bits + 1 <= sr <= n_udword_bits - 1 + * { + * q.s.low = n.s.low << (n_udword_bits - sr); + * q.s.high = (n.s.high << (n_udword_bits - sr)) | + * (n.s.low >> (sr - n_uword_bits)); + * r.s.high = 0; + * r.s.low = n.s.high >> (sr - n_uword_bits); + * } + */ + q.s.low = (n.s.low << (n_udword_bits - sr)) & + ((si_int)(n_uword_bits - sr) >> (n_uword_bits-1)); + q.s.high = ((n.s.low << ( n_uword_bits - sr)) & + ((si_int)(sr - n_uword_bits - 1) >> (n_uword_bits-1))) | + (((n.s.high << (n_udword_bits - sr)) | + (n.s.low >> (sr - n_uword_bits))) & + ((si_int)(n_uword_bits - sr) >> (n_uword_bits-1))); + r.s.high = (n.s.high >> sr) & + ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1)); + r.s.low = ((n.s.high >> (sr - n_uword_bits)) & + ((si_int)(n_uword_bits - sr - 1) >> (n_uword_bits-1))) | + (((n.s.high << (n_uword_bits - sr)) | + (n.s.low >> sr)) & + ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1))); + } + else + { + /* K X + * --- + * K K + */ + sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high); + /* 0 <= sr <= n_uword_bits - 1 or sr large */ + if (sr > n_uword_bits - 1) + { + if (rem) + *rem = n.all; + return 0; + } + ++sr; + /* 1 <= sr <= n_uword_bits */ + /* q.all = n.all << (n_udword_bits - sr); */ + q.s.low = 0; + q.s.high = n.s.low << (n_uword_bits - sr); + /* r.all = n.all >> sr; + * if (sr < n_uword_bits) + * { + * r.s.high = n.s.high >> sr; + * r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); + * } + * else + * { + * r.s.high = 0; + * r.s.low = n.s.high; + * } + */ + r.s.high = (n.s.high >> sr) & + ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1)); + r.s.low = (n.s.high << (n_uword_bits - sr)) | + ((n.s.low >> sr) & + ((si_int)(sr - n_uword_bits) >> (n_uword_bits-1))); + } + } + /* Not a special case + * q and r are initialized with: + * q.all = n.all << (n_udword_bits - sr); + * r.all = n.all >> sr; + * 1 <= sr <= n_udword_bits - 1 + */ + su_int carry = 0; + for (; sr > 0; --sr) + { + /* r:q = ((r:q) << 1) | carry */ + r.s.high = (r.s.high << 1) | (r.s.low >> (n_uword_bits - 1)); + r.s.low = (r.s.low << 1) | (q.s.high >> (n_uword_bits - 1)); + q.s.high = (q.s.high << 1) | (q.s.low >> (n_uword_bits - 1)); + q.s.low = (q.s.low << 1) | carry; + /* carry = 0; + * if (r.all >= d.all) + * { + * r.all -= d.all; + * carry = 1; + * } + */ + const di_int s = (di_int)(d.all - r.all - 1) >> (n_udword_bits - 1); + carry = s & 1; + r.all -= d.all & s; + } + q.all = (q.all << 1) | carry; + if (rem) + *rem = r.all; + return q.all; +} diff --git a/lib/builtins/udivmodsi4.c b/lib/builtins/udivmodsi4.c new file mode 100644 index 000000000..5b49089fc --- /dev/null +++ b/lib/builtins/udivmodsi4.c @@ -0,0 +1,30 @@ +/*===-- udivmodsi4.c - Implement __udivmodsi4 ------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __udivmodsi4 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +extern su_int COMPILER_RT_ABI __udivsi3(su_int n, su_int d); + + +/* Returns: a / b, *rem = a % b */ + +COMPILER_RT_ABI su_int +__udivmodsi4(su_int a, su_int b, su_int* rem) +{ + si_int d = __udivsi3(a,b); + *rem = a - (d*b); + return d; +} + + diff --git a/lib/builtins/udivmodti4.c b/lib/builtins/udivmodti4.c new file mode 100644 index 000000000..f619c7495 --- /dev/null +++ b/lib/builtins/udivmodti4.c @@ -0,0 +1,256 @@ +/* ===-- udivmodti4.c - Implement __udivmodti4 -----------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __udivmodti4 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +/* Effects: if rem != 0, *rem = a % b + * Returns: a / b + */ + +/* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */ + +tu_int +__udivmodti4(tu_int a, tu_int b, tu_int* rem) +{ + const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT; + const unsigned n_utword_bits = sizeof(tu_int) * CHAR_BIT; + utwords n; + n.all = a; + utwords d; + d.all = b; + utwords q; + utwords r; + unsigned sr; + /* special cases, X is unknown, K != 0 */ + if (n.s.high == 0) + { + if (d.s.high == 0) + { + /* 0 X + * --- + * 0 X + */ + if (rem) + *rem = n.s.low % d.s.low; + return n.s.low / d.s.low; + } + /* 0 X + * --- + * K X + */ + if (rem) + *rem = n.s.low; + return 0; + } + /* n.s.high != 0 */ + if (d.s.low == 0) + { + if (d.s.high == 0) + { + /* K X + * --- + * 0 0 + */ + if (rem) + *rem = n.s.high % d.s.low; + return n.s.high / d.s.low; + } + /* d.s.high != 0 */ + if (n.s.low == 0) + { + /* K 0 + * --- + * K 0 + */ + if (rem) + { + r.s.high = n.s.high % d.s.high; + r.s.low = 0; + *rem = r.all; + } + return n.s.high / d.s.high; + } + /* K K + * --- + * K 0 + */ + if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */ + { + if (rem) + { + r.s.low = n.s.low; + r.s.high = n.s.high & (d.s.high - 1); + *rem = r.all; + } + return n.s.high >> __builtin_ctzll(d.s.high); + } + /* K K + * --- + * K 0 + */ + sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high); + /* 0 <= sr <= n_udword_bits - 2 or sr large */ + if (sr > n_udword_bits - 2) + { + if (rem) + *rem = n.all; + return 0; + } + ++sr; + /* 1 <= sr <= n_udword_bits - 1 */ + /* q.all = n.all << (n_utword_bits - sr); */ + q.s.low = 0; + q.s.high = n.s.low << (n_udword_bits - sr); + /* r.all = n.all >> sr; */ + r.s.high = n.s.high >> sr; + r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr); + } + else /* d.s.low != 0 */ + { + if (d.s.high == 0) + { + /* K X + * --- + * 0 K + */ + if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */ + { + if (rem) + *rem = n.s.low & (d.s.low - 1); + if (d.s.low == 1) + return n.all; + sr = __builtin_ctzll(d.s.low); + q.s.high = n.s.high >> sr; + q.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr); + return q.all; + } + /* K X + * --- + * 0 K + */ + sr = 1 + n_udword_bits + __builtin_clzll(d.s.low) + - __builtin_clzll(n.s.high); + /* 2 <= sr <= n_utword_bits - 1 + * q.all = n.all << (n_utword_bits - sr); + * r.all = n.all >> sr; + * if (sr == n_udword_bits) + * { + * q.s.low = 0; + * q.s.high = n.s.low; + * r.s.high = 0; + * r.s.low = n.s.high; + * } + * else if (sr < n_udword_bits) // 2 <= sr <= n_udword_bits - 1 + * { + * q.s.low = 0; + * q.s.high = n.s.low << (n_udword_bits - sr); + * r.s.high = n.s.high >> sr; + * r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr); + * } + * else // n_udword_bits + 1 <= sr <= n_utword_bits - 1 + * { + * q.s.low = n.s.low << (n_utword_bits - sr); + * q.s.high = (n.s.high << (n_utword_bits - sr)) | + * (n.s.low >> (sr - n_udword_bits)); + * r.s.high = 0; + * r.s.low = n.s.high >> (sr - n_udword_bits); + * } + */ + q.s.low = (n.s.low << (n_utword_bits - sr)) & + ((di_int)(int)(n_udword_bits - sr) >> (n_udword_bits-1)); + q.s.high = ((n.s.low << ( n_udword_bits - sr)) & + ((di_int)(int)(sr - n_udword_bits - 1) >> (n_udword_bits-1))) | + (((n.s.high << (n_utword_bits - sr)) | + (n.s.low >> (sr - n_udword_bits))) & + ((di_int)(int)(n_udword_bits - sr) >> (n_udword_bits-1))); + r.s.high = (n.s.high >> sr) & + ((di_int)(int)(sr - n_udword_bits) >> (n_udword_bits-1)); + r.s.low = ((n.s.high >> (sr - n_udword_bits)) & + ((di_int)(int)(n_udword_bits - sr - 1) >> (n_udword_bits-1))) | + (((n.s.high << (n_udword_bits - sr)) | + (n.s.low >> sr)) & + ((di_int)(int)(sr - n_udword_bits) >> (n_udword_bits-1))); + } + else + { + /* K X + * --- + * K K + */ + sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high); + /*0 <= sr <= n_udword_bits - 1 or sr large */ + if (sr > n_udword_bits - 1) + { + if (rem) + *rem = n.all; + return 0; + } + ++sr; + /* 1 <= sr <= n_udword_bits */ + /* q.all = n.all << (n_utword_bits - sr); */ + q.s.low = 0; + q.s.high = n.s.low << (n_udword_bits - sr); + /* r.all = n.all >> sr; + * if (sr < n_udword_bits) + * { + * r.s.high = n.s.high >> sr; + * r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr); + * } + * else + * { + * r.s.high = 0; + * r.s.low = n.s.high; + * } + */ + r.s.high = (n.s.high >> sr) & + ((di_int)(int)(sr - n_udword_bits) >> (n_udword_bits-1)); + r.s.low = (n.s.high << (n_udword_bits - sr)) | + ((n.s.low >> sr) & + ((di_int)(int)(sr - n_udword_bits) >> (n_udword_bits-1))); + } + } + /* Not a special case + * q and r are initialized with: + * q.all = n.all << (n_utword_bits - sr); + * r.all = n.all >> sr; + * 1 <= sr <= n_utword_bits - 1 + */ + su_int carry = 0; + for (; sr > 0; --sr) + { + /* r:q = ((r:q) << 1) | carry */ + r.s.high = (r.s.high << 1) | (r.s.low >> (n_udword_bits - 1)); + r.s.low = (r.s.low << 1) | (q.s.high >> (n_udword_bits - 1)); + q.s.high = (q.s.high << 1) | (q.s.low >> (n_udword_bits - 1)); + q.s.low = (q.s.low << 1) | carry; + /* carry = 0; + * if (r.all >= d.all) + * { + * r.all -= d.all; + * carry = 1; + * } + */ + const ti_int s = (ti_int)(d.all - r.all - 1) >> (n_utword_bits - 1); + carry = s & 1; + r.all -= d.all & s; + } + q.all = (q.all << 1) | carry; + if (rem) + *rem = r.all; + return q.all; +} + +#endif /* __x86_64 */ diff --git a/lib/builtins/udivsi3.c b/lib/builtins/udivsi3.c new file mode 100644 index 000000000..5d0140cc3 --- /dev/null +++ b/lib/builtins/udivsi3.c @@ -0,0 +1,66 @@ +/* ===-- udivsi3.c - Implement __udivsi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __udivsi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: a / b */ + +/* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */ + +ARM_EABI_FNALIAS(uidiv, udivsi3) + +/* This function should not call __divsi3! */ +COMPILER_RT_ABI su_int +__udivsi3(su_int n, su_int d) +{ + const unsigned n_uword_bits = sizeof(su_int) * CHAR_BIT; + su_int q; + su_int r; + unsigned sr; + /* special cases */ + if (d == 0) + return 0; /* ?! */ + if (n == 0) + return 0; + sr = __builtin_clz(d) - __builtin_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 <= sr <= n_uword_bits - 1 */ + /* Not a special case */ + q = n << (n_uword_bits - sr); + r = n >> sr; + su_int carry = 0; + for (; sr > 0; --sr) + { + /* r:q = ((r:q) << 1) | carry */ + r = (r << 1) | (q >> (n_uword_bits - 1)); + q = (q << 1) | carry; + /* carry = 0; + * if (r.all >= d.all) + * { + * r.all -= d.all; + * carry = 1; + * } + */ + const si_int s = (si_int)(d - r - 1) >> (n_uword_bits - 1); + carry = s & 1; + r -= d & s; + } + q = (q << 1) | carry; + return q; +} diff --git a/lib/builtins/udivti3.c b/lib/builtins/udivti3.c new file mode 100644 index 000000000..d9e1bb46f --- /dev/null +++ b/lib/builtins/udivti3.c @@ -0,0 +1,29 @@ +/* ===-- udivti3.c - Implement __udivti3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __udivti3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem); + +/* Returns: a / b */ + +tu_int +__udivti3(tu_int a, tu_int b) +{ + return __udivmodti4(a, b, 0); +} + +#endif /* __x86_64 */ diff --git a/lib/builtins/umoddi3.c b/lib/builtins/umoddi3.c new file mode 100644 index 000000000..3541ab6e9 --- /dev/null +++ b/lib/builtins/umoddi3.c @@ -0,0 +1,27 @@ +/* ===-- umoddi3.c - Implement __umoddi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __umoddi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +du_int COMPILER_RT_ABI __udivmoddi4(du_int a, du_int b, du_int* rem); + +/* Returns: a % b */ + +COMPILER_RT_ABI du_int +__umoddi3(du_int a, du_int b) +{ + du_int r; + __udivmoddi4(a, b, &r); + return r; +} diff --git a/lib/builtins/umodsi3.c b/lib/builtins/umodsi3.c new file mode 100644 index 000000000..aae741d89 --- /dev/null +++ b/lib/builtins/umodsi3.c @@ -0,0 +1,25 @@ +/* ===-- umodsi3.c - Implement __umodsi3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __umodsi3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +/* Returns: a % b */ + +su_int COMPILER_RT_ABI __udivsi3(su_int a, su_int b); + +COMPILER_RT_ABI su_int +__umodsi3(su_int a, su_int b) +{ + return a - __udivsi3(a, b) * b; +} diff --git a/lib/builtins/umodti3.c b/lib/builtins/umodti3.c new file mode 100644 index 000000000..8ebe7f0dc --- /dev/null +++ b/lib/builtins/umodti3.c @@ -0,0 +1,31 @@ +/* ===-- umodti3.c - Implement __umodti3 -----------------------------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file implements __umodti3 for the compiler_rt library. + * + * ===----------------------------------------------------------------------=== + */ + +#include "int_lib.h" + +#if __x86_64 + +tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem); + +/* Returns: a % b */ + +tu_int +__umodti3(tu_int a, tu_int b) +{ + tu_int r; + __udivmodti4(a, b, &r); + return r; +} + +#endif diff --git a/lib/builtins/x86_64/Makefile.mk b/lib/builtins/x86_64/Makefile.mk new file mode 100644 index 000000000..83848dddd --- /dev/null +++ b/lib/builtins/x86_64/Makefile.mk @@ -0,0 +1,20 @@ +#===- lib/builtins/x86_64/Makefile.mk ----------------------*- Makefile -*--===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# + +ModuleName := builtins +SubDirs := +OnlyArchs := x86_64 x86_64h + +AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file))) +Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file))) +ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o) +Implementation := Optimized + +# FIXME: use automatic dependencies? +Dependencies := $(wildcard lib/*.h $(Dir)/*.h) diff --git a/lib/builtins/x86_64/floatdidf.c b/lib/builtins/x86_64/floatdidf.c new file mode 100644 index 000000000..388404e5e --- /dev/null +++ b/lib/builtins/x86_64/floatdidf.c @@ -0,0 +1,16 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +/* double __floatdidf(di_int a); */ + +#ifdef __x86_64__ + +#include "../int_lib.h" + +double __floatdidf(int64_t a) +{ + return (double)a; +} + +#endif /* __x86_64__ */ diff --git a/lib/builtins/x86_64/floatdisf.c b/lib/builtins/x86_64/floatdisf.c new file mode 100644 index 000000000..96c3728e9 --- /dev/null +++ b/lib/builtins/x86_64/floatdisf.c @@ -0,0 +1,14 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +#ifdef __x86_64__ + +#include "../int_lib.h" + +float __floatdisf(int64_t a) +{ + return (float)a; +} + +#endif /* __x86_64__ */ diff --git a/lib/builtins/x86_64/floatdixf.c b/lib/builtins/x86_64/floatdixf.c new file mode 100644 index 000000000..c01193a82 --- /dev/null +++ b/lib/builtins/x86_64/floatdixf.c @@ -0,0 +1,16 @@ +/* This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + */ + +/* long double __floatdixf(di_int a); */ + +#ifdef __x86_64__ + +#include "../int_lib.h" + +long double __floatdixf(int64_t a) +{ + return (long double)a; +} + +#endif /* __i386__ */ diff --git a/lib/builtins/x86_64/floatundidf.S b/lib/builtins/x86_64/floatundidf.S new file mode 100644 index 000000000..1df3d7479 --- /dev/null +++ b/lib/builtins/x86_64/floatundidf.S @@ -0,0 +1,44 @@ +//===-- floatundidf.S - Implement __floatundidf for x86_64 ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements __floatundidf for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + +// double __floatundidf(du_int a); + +#ifdef __x86_64__ + +#ifndef __ELF__ +.const +#endif +.align 4 +twop52: .quad 0x4330000000000000 +twop84_plus_twop52: + .quad 0x4530000000100000 +twop84: .quad 0x4530000000000000 + +#define REL_ADDR(_a) (_a)(%rip) + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__floatundidf) + movd %edi, %xmm0 // low 32 bits of a + shrq $32, %rdi // high 32 bits of a + orq REL_ADDR(twop84), %rdi // 0x1p84 + a_hi (no rounding occurs) + orpd REL_ADDR(twop52), %xmm0 // 0x1p52 + a_lo (no rounding occurs) + movd %rdi, %xmm1 + subsd REL_ADDR(twop84_plus_twop52), %xmm1 // a_hi - 0x1p52 (no rounding occurs) + addsd %xmm1, %xmm0 // a_hi + a_lo (round happens here) + ret +END_COMPILERRT_FUNCTION(__floatundidf) + +#endif // __x86_64__ diff --git a/lib/builtins/x86_64/floatundisf.S b/lib/builtins/x86_64/floatundisf.S new file mode 100644 index 000000000..7dd5c329b --- /dev/null +++ b/lib/builtins/x86_64/floatundisf.S @@ -0,0 +1,34 @@ +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. + +#include "../assembly.h" + +// float __floatundisf(du_int a); + +#ifdef __x86_64__ + +#ifndef __ELF__ +.literal4 +#endif +two: .single 2.0 + +#define REL_ADDR(_a) (_a)(%rip) + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__floatundisf) + movq $1, %rsi + testq %rdi, %rdi + js 1f + cvtsi2ssq %rdi, %xmm0 + ret + +1: andq %rdi, %rsi + shrq %rdi + orq %rsi, %rdi + cvtsi2ssq %rdi, %xmm0 + mulss REL_ADDR(two), %xmm0 + ret +END_COMPILERRT_FUNCTION(__floatundisf) + +#endif // __x86_64__ diff --git a/lib/builtins/x86_64/floatundixf.S b/lib/builtins/x86_64/floatundixf.S new file mode 100644 index 000000000..b05954a0b --- /dev/null +++ b/lib/builtins/x86_64/floatundixf.S @@ -0,0 +1,64 @@ +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. + +#include "../assembly.h" + +// long double __floatundixf(du_int a); + +#ifdef __x86_64__ + +#ifndef __ELF__ +.const +#endif +.align 4 +twop64: .quad 0x43f0000000000000 + +#define REL_ADDR(_a) (_a)(%rip) + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__floatundixf) + movq %rdi, -8(%rsp) + fildq -8(%rsp) + test %rdi, %rdi + js 1f + ret +1: faddl REL_ADDR(twop64) + ret +END_COMPILERRT_FUNCTION(__floatundixf) + +#endif // __x86_64__ + + +/* Branch-free implementation is ever so slightly slower, but more beautiful. + It is likely superior for inlining, so I kept it around for future reference. + +#ifdef __x86_64__ + +.const +.align 4 +twop52: .quad 0x4330000000000000 +twop84_plus_twop52_neg: + .quad 0xc530000000100000 +twop84: .quad 0x4530000000000000 + +#define REL_ADDR(_a) (_a)(%rip) + +.text +.align 4 +DEFINE_COMPILERRT_FUNCTION(__floatundixf) + movl %edi, %esi // low 32 bits of input + shrq $32, %rdi // hi 32 bits of input + orq REL_ADDR(twop84), %rdi // 2^84 + hi (as a double) + orq REL_ADDR(twop52), %rsi // 2^52 + lo (as a double) + movq %rdi, -8(%rsp) + movq %rsi, -16(%rsp) + fldl REL_ADDR(twop84_plus_twop52_neg) + faddl -8(%rsp) // hi - 2^52 (as double extended, no rounding occurs) + faddl -16(%rsp) // hi + lo (as double extended) + ret +END_COMPILERRT_FUNCTION(__floatundixf) + +#endif // __x86_64__ + +*/ |