forked from OSchip/llvm-project
compiler-rt: Add udivmodei5 to builtins and add bitint library
According to the RFC [0], this review contains the compiler-rt parts of large integer divison for _BitInt. It adds the functions ``` /// Computes the unsigned division of a / b for two large integers /// composed of n significant words. /// Writes the quotient to quo and the remainder to rem. /// /// \param quo The quotient represented by n words. Must be non-null. /// \param rem The remainder represented by n words. Must be non-null. /// \param a The dividend represented by n + 1 words. Must be non-null. /// \param b The divisor represented by n words. Must be non-null. /// \note The word order is in host endianness. /// \note Might modify a and b. /// \note The storage of 'a' needs to hold n + 1 elements because some /// implementations need extra scratch space in the most significant word. /// The value of that word is ignored. COMPILER_RT_ABI void __udivmodei5(su_int *quo, su_int *rem, su_int *a, su_int *b, unsigned int n); /// Computes the signed division of a / b. /// See __udivmodei5 for details. COMPILER_RT_ABI void __divmodei5(su_int *quo, su_int *rem, su_int *a, su_int *b, unsigned int words); ``` into builtins. In addition it introduces a new "bitint" library containing only those new functions, which is meant as a way to provide those when using libgcc as runtime. [0] https://discourse.llvm.org/t/rfc-add-support-for-division-of-large-bitint-builtins-selectiondag-globalisel-clang/60329 Differential Revision: https://reviews.llvm.org/D120327
This commit is contained in:
parent
36d3efea15
commit
bf2dc4b376
|
@ -34,6 +34,8 @@ include(CompilerRTUtils)
|
|||
|
||||
option(COMPILER_RT_BUILD_BUILTINS "Build builtins" ON)
|
||||
mark_as_advanced(COMPILER_RT_BUILD_BUILTINS)
|
||||
option(COMPILER_RT_BUILD_BITINT "Build bitint" ON)
|
||||
mark_as_advanced(COMPILER_RT_BUILD_BITINT)
|
||||
option(COMPILER_RT_BUILD_CRT "Build crtbegin.o/crtend.o" ON)
|
||||
mark_as_advanced(COMPILER_RT_BUILD_CRT)
|
||||
option(COMPILER_RT_CRT_USE_EH_FRAME_REGISTRY "Use eh_frame in crtbegin.o/crtend.o" ON)
|
||||
|
|
|
@ -65,6 +65,9 @@ set(ALL_BUILTIN_SUPPORTED_ARCH
|
|||
${RISCV32} ${RISCV64} ${SPARC} ${SPARCV9}
|
||||
${WASM32} ${WASM64} ${VE})
|
||||
|
||||
set(ALL_BITINT_SUPPORTED_ARCH
|
||||
${ALL_BUILTIN_SUPPORTED_ARCH})
|
||||
|
||||
include(CompilerRTUtils)
|
||||
include(CompilerRTDarwinUtils)
|
||||
|
||||
|
@ -195,6 +198,7 @@ if(APPLE)
|
|||
endforeach()
|
||||
|
||||
list_intersect(BUILTIN_SUPPORTED_ARCH ALL_BUILTIN_SUPPORTED_ARCH COMPILER_RT_SUPPORTED_ARCH)
|
||||
list_intersect(BITINT_SUPPORTED_ARCH ALL_BITINT_SUPPORTED_ARCH COMPILER_RT_SUPPORTED_ARCH)
|
||||
|
||||
else()
|
||||
# If we're not building the builtins standalone, just rely on the tests in
|
||||
|
@ -206,6 +210,8 @@ else()
|
|||
# Architectures supported by compiler-rt libraries.
|
||||
filter_available_targets(BUILTIN_SUPPORTED_ARCH
|
||||
${ALL_BUILTIN_SUPPORTED_ARCH})
|
||||
filter_available_targets(BITINT_SUPPORTED_ARCH
|
||||
${ALL_BITINT_SUPPORTED_ARCH})
|
||||
endif()
|
||||
|
||||
message(STATUS "Builtin supported architectures: ${BUILTIN_SUPPORTED_ARCH}")
|
||||
|
|
|
@ -17,6 +17,10 @@ if(COMPILER_RT_BUILD_BUILTINS)
|
|||
add_subdirectory(builtins)
|
||||
endif()
|
||||
|
||||
if(COMPILER_RT_BUILD_BITINT)
|
||||
add_subdirectory(bitint)
|
||||
endif()
|
||||
|
||||
if(COMPILER_RT_BUILD_CRT)
|
||||
add_subdirectory(crt)
|
||||
endif()
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
add_compiler_rt_component(bitint)
|
||||
|
||||
include(builtin-config-ix)
|
||||
|
||||
add_compiler_rt_runtime(clang_rt.bitint
|
||||
STATIC
|
||||
ARCHS ${BITINT_SUPPORTED_ARCH}
|
||||
SOURCES ../builtins/udivmodei5.c
|
||||
CFLAGS ${SANITIZER_COMMON_CFLAGS} -DIS_BITINT_LIBRARY
|
||||
PARENT_TARGET bitint)
|
||||
|
|
@ -174,6 +174,7 @@ set(GENERIC_SOURCES
|
|||
udivmoddi4.c
|
||||
udivmodsi4.c
|
||||
udivmodti4.c
|
||||
udivmodei5.c
|
||||
udivsi3.c
|
||||
udivti3.c
|
||||
umoddi3.c
|
||||
|
|
|
@ -110,6 +110,29 @@ COMPILER_RT_ABI su_int __udivsi3(su_int n, su_int d);
|
|||
|
||||
COMPILER_RT_ABI su_int __udivmodsi4(su_int a, su_int b, su_int *rem);
|
||||
COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int *rem);
|
||||
|
||||
/// Computes the unsigned division of a / b for two large integers
|
||||
/// composed of n significant words.
|
||||
/// Writes the quotient to quo and the remainder to rem.
|
||||
///
|
||||
/// \param quo The quotient represented by n words. Must be non-null.
|
||||
/// \param rem The remainder represented by n words. Must be non-null.
|
||||
/// \param a The dividend represented by n + 1 words. Must be non-null.
|
||||
/// \param b The divisor represented by n words. Must be non-null.
|
||||
|
||||
/// \note The word order is in host endianness.
|
||||
/// \note Might modify a and b.
|
||||
/// \note The storage of 'a' needs to hold n + 1 elements because some
|
||||
/// implementations need extra scratch space in the most significant word.
|
||||
/// The value of that word is ignored.
|
||||
COMPILER_RT_ABI void __udivmodei5(su_int *quo, su_int *rem, su_int *a,
|
||||
su_int *b, unsigned int n);
|
||||
|
||||
/// Computes the signed division of a / b.
|
||||
/// See __udivmodei5 for details.
|
||||
COMPILER_RT_ABI void __divmodei5(su_int *quo, su_int *rem, su_int *a, su_int *b,
|
||||
unsigned int words);
|
||||
|
||||
#ifdef CRT_HAS_128BIT
|
||||
COMPILER_RT_ABI int __clzti2(ti_int a);
|
||||
COMPILER_RT_ABI tu_int __udivmodti4(tu_int a, tu_int b, tu_int *rem);
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
//===-- udivmodei5.c - Implement _udivmodei5-------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements _udivmodei5 for the compiler_rt library.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "int_lib.h"
|
||||
|
||||
// When this is built into the bitint library, provide symbols with
|
||||
// weak linkage to allow gracefully upgrading once libgcc contains those
|
||||
// symbols.
|
||||
#ifdef IS_BITINT_LIBRARY
|
||||
#define WEAK_IF_BITINT_LIBRARY __attribute__((weak))
|
||||
#else
|
||||
#define WEAK_IF_BITINT_LIBRARY
|
||||
#endif
|
||||
|
||||
static const int WORD_SIZE_IN_BITS = sizeof(su_int) * CHAR_BIT;
|
||||
|
||||
/// A mask with the most significant bit set.
|
||||
static const su_int WORD_MSB = (su_int)1 << (WORD_SIZE_IN_BITS - 1);
|
||||
|
||||
// Define an index such that a[WORD_IDX(0)] is the least significant word
|
||||
// and a[WORD_IDX(words-1)] is the most significant word.
|
||||
#if _YUGA_LITTLE_ENDIAN
|
||||
#define WORD_IDX(X, words) (X)
|
||||
#else
|
||||
#define WORD_IDX(X) ((words) - (X))
|
||||
#endif
|
||||
|
||||
static bool has_msb_set(su_int a) { return (a & WORD_MSB) != 0; }
|
||||
|
||||
static bool is_neg(const uint32_t *V, unsigned words) {
|
||||
return has_msb_set(V[WORD_IDX(words - 1, words)]);
|
||||
}
|
||||
|
||||
/// dst = ~dst
|
||||
static void complement(su_int *dst, unsigned words) {
|
||||
for (unsigned i = 0; i < words; i++)
|
||||
dst[i] = ~dst[i];
|
||||
}
|
||||
|
||||
/// dst += src
|
||||
static void add_part(su_int *dst, su_int src, unsigned words) {
|
||||
for (unsigned i = 0; i < words; ++i) {
|
||||
dst[WORD_IDX(i, words)] += src;
|
||||
if (dst[WORD_IDX(i, words)] >= src)
|
||||
return; // No carry
|
||||
src = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// dst += 1
|
||||
static void increment(su_int *dst, unsigned words) { add_part(dst, 1u, words); }
|
||||
|
||||
/// dst = -dst
|
||||
static void negate(su_int *dst, unsigned words) {
|
||||
complement(dst, words);
|
||||
increment(dst, words);
|
||||
}
|
||||
|
||||
/// a -= b
|
||||
/// \pre a >= b
|
||||
static void subtract(su_int *a, const su_int *b, unsigned words) {
|
||||
su_int carry = 0;
|
||||
for (unsigned i = 0; i < words; ++i) {
|
||||
su_int dst = 0;
|
||||
carry = __builtin_sub_overflow(a[WORD_IDX(i, words)], carry, &dst);
|
||||
carry += __builtin_sub_overflow(dst, b[WORD_IDX(i, words)],
|
||||
&a[WORD_IDX(i, words)]);
|
||||
}
|
||||
}
|
||||
|
||||
/// a = 0
|
||||
static void set_zero(su_int *a, unsigned words) {
|
||||
for (unsigned i = 0; i < words; ++i)
|
||||
a[i] = 0;
|
||||
}
|
||||
|
||||
/// a > b: return +1
|
||||
/// a < b: return -1
|
||||
/// a == b: return 0
|
||||
static int ucompare(const su_int *a, const su_int *b, unsigned int words) {
|
||||
for (int i = words - 1; i >= 0; --i) {
|
||||
if (a[WORD_IDX(i, words)] != b[WORD_IDX(i, words)])
|
||||
return a[WORD_IDX(i, words)] > b[WORD_IDX(i, words)] ? 1 : -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Performs a logic left shift of one bit of 'a'.
|
||||
static void left_shift_1(su_int *a, unsigned words) {
|
||||
for (int i = words - 1; i >= 0; --i) {
|
||||
a[WORD_IDX(i, words)] <<= 1;
|
||||
if (i == 0)
|
||||
continue;
|
||||
if (has_msb_set(a[WORD_IDX(i - 1, words)]))
|
||||
a[WORD_IDX(i, words)] |= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the least signitificant bit of a to 'a'.
|
||||
/// \pre The least signitificant bit of 'a' is zero.
|
||||
static void set_bit_0(su_int *a, unsigned words, unsigned v) {
|
||||
a[WORD_IDX(0, words)] |= v;
|
||||
}
|
||||
|
||||
/// Sets the n-th bit of 'a' to 1.
|
||||
/// \pre The n-th bit of 'a' is zero.
|
||||
static void set_bit(su_int *a, unsigned words, unsigned n) {
|
||||
unsigned word = n / WORD_SIZE_IN_BITS;
|
||||
unsigned bit = n % WORD_SIZE_IN_BITS;
|
||||
a[WORD_IDX(word, words)] |= (su_int)1 << bit;
|
||||
}
|
||||
|
||||
/// Returns the n-th bit of 'a'.
|
||||
static unsigned get_bit(const su_int *a, unsigned words, unsigned n) {
|
||||
unsigned word = n / WORD_SIZE_IN_BITS;
|
||||
unsigned bit = n % WORD_SIZE_IN_BITS;
|
||||
su_int mask = (su_int)1 << bit;
|
||||
return !!(a[WORD_IDX(word, words)] & mask);
|
||||
}
|
||||
|
||||
/// Unsigned divison quo = a / b, rem = a % b
|
||||
WEAK_IF_BITINT_LIBRARY
|
||||
COMPILER_RT_ABI void __udivmodei5(su_int *quo, su_int *rem, su_int *a,
|
||||
su_int *b, unsigned int words) {
|
||||
|
||||
set_zero(quo, words);
|
||||
set_zero(rem, words);
|
||||
|
||||
unsigned bits = words * WORD_SIZE_IN_BITS;
|
||||
for (int i = bits - 1; i >= 0; --i) {
|
||||
left_shift_1(rem, words); // rem <<= 1;
|
||||
set_bit_0(rem, words, get_bit(a, words, i)); // rem(bit 0) = a(bit i);
|
||||
if (ucompare(rem, b, words) >= 0) { // if (rem >= b)
|
||||
subtract(rem, b, words); // rem -= b;
|
||||
set_bit(quo, words, i); // quo(bit i) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Signed divison quo = a / b, rem = a % b
|
||||
WEAK_IF_BITINT_LIBRARY
|
||||
COMPILER_RT_ABI void __divmodei5(su_int *quo, su_int *rem, su_int *a, su_int *b,
|
||||
unsigned int words) {
|
||||
int asign = is_neg(a, words);
|
||||
int bsign = is_neg(b, words);
|
||||
if (asign) {
|
||||
if (bsign) {
|
||||
negate(a, words);
|
||||
negate(b, words);
|
||||
__udivmodei5(quo, rem, a, b, words);
|
||||
} else {
|
||||
negate(a, words);
|
||||
__udivmodei5(quo, rem, a, b, words);
|
||||
negate(quo, words);
|
||||
}
|
||||
negate(rem, words);
|
||||
} else if (bsign) {
|
||||
negate(b, words);
|
||||
__udivmodei5(quo, rem, a, b, words);
|
||||
negate(quo, words);
|
||||
} else {
|
||||
__udivmodei5(quo, rem, a, b, words);
|
||||
}
|
||||
}
|
|
@ -60,6 +60,9 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS)
|
|||
if(COMPILER_RT_BUILD_BUILTINS)
|
||||
add_subdirectory(builtins)
|
||||
endif()
|
||||
if(COMPILER_RT_BUILD_BITINT)
|
||||
add_subdirectory(bitint)
|
||||
endif()
|
||||
if(COMPILER_RT_BUILD_SANITIZERS)
|
||||
compiler_rt_test_runtime(interception)
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
set(BITINT_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
set(BITINT_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS} bitint)
|
||||
set(BITINT_TESTSUITES)
|
||||
|
||||
include(builtin-config-ix)
|
||||
|
||||
foreach(arch ${BITINT_SUPPORTED_ARCH})
|
||||
set(BITINT_TEST_TARGET_ARCH ${arch})
|
||||
string(TOLOWER "-${arch}" BITINT_TEST_CONFIG_SUFFIX)
|
||||
get_test_cc_for_arch(${arch} BITINT_TEST_TARGET_CC BITINT_TEST_TARGET_CFLAGS)
|
||||
configure_lit_site_cfg(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Unit/${arch}/lit.site.cfg.py
|
||||
)
|
||||
list(APPEND BITINT_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit/${arch})
|
||||
endforeach()
|
||||
|
||||
add_lit_testsuite(check-bitint "Running the Bitint tests"
|
||||
${BITINT_TESTSUITES}
|
||||
DEPENDS ${BITINT_TEST_DEPS})
|
||||
set_target_properties(check-bitint PROPERTIES FOLDER "Compiler-RT Misc")
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
// RUN: %clang_bitint %s %libbitint -o %t && %run %t
|
||||
|
||||
// Ensure that libclang_rt.bitint exports the right symbols
|
||||
|
||||
#include "int_lib.h"
|
||||
|
||||
#define WORDS 4
|
||||
int main(int argc, char *argv[]) {
|
||||
unsigned int quo[WORDS], rem[WORDS];
|
||||
// 'a' needs to have an extra word, see documentation of __udivmodei5.
|
||||
unsigned int a[WORDS+1] = {0, 0, 0, 1, 0};
|
||||
unsigned int b[WORDS] = {0, 0, 0, 1};
|
||||
|
||||
__udivmodei5(quo, rem, a, b, WORDS);
|
||||
__divmodei5(quo, rem, a, b, WORDS);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
# -*- Python -*-
|
||||
|
||||
import os
|
||||
|
||||
# Setup config name.
|
||||
config.name = 'bitint' + config.name_suffix
|
||||
|
||||
config.test_source_root = os.path.dirname(__file__)
|
||||
|
||||
# Test suffixes.
|
||||
config.suffixes = ['.c', '.cc', '.cpp', '.m', '.mm']
|
||||
|
||||
base_lib = os.path.join(config.compiler_rt_libdir, "libclang_rt.bitint%s.a"
|
||||
% config.target_suffix)
|
||||
|
||||
config.substitutions.append( ("%libbitint ", base_lib + ' -lc ') )
|
||||
|
||||
def build_invocation(compile_flags):
|
||||
return " ".join([config.clang] + compile_flags) + " "
|
||||
|
||||
def get_required_attr(config, attr_name):
|
||||
attr_value = getattr(config, attr_name, None)
|
||||
if attr_value == None:
|
||||
lit_config.fatal(
|
||||
"No attribute %r in test configuration! You may need to run "
|
||||
"tests from your build directory or add this attribute "
|
||||
"to lit.site.cfg.py " % attr_name)
|
||||
return attr_value
|
||||
|
||||
builtins_source_dir = os.path.join(
|
||||
get_required_attr(config, "compiler_rt_src_root"), "lib", "builtins")
|
||||
if sys.platform in ['win32'] and execute_external:
|
||||
# Don't pass dosish path separator to msys bash.exe.
|
||||
builtins_source_dir = builtins_source_dir.replace('\\', '/')
|
||||
|
||||
clang_bitint_static_cflags = (['-g',
|
||||
'-fno-builtin',
|
||||
'-nodefaultlibs',
|
||||
'-I', builtins_source_dir,
|
||||
config.target_cflags])
|
||||
|
||||
config.substitutions.append( ("%clang_bitint ", \
|
||||
build_invocation(clang_bitint_static_cflags)))
|
|
@ -0,0 +1,14 @@
|
|||
@LIT_SITE_CFG_IN_HEADER@
|
||||
|
||||
config.name_suffix = "@BITINT_TEST_CONFIG_SUFFIX@"
|
||||
|
||||
config.target_cflags = "@BITINT_TEST_TARGET_CFLAGS@"
|
||||
|
||||
config.target_arch = "@BITINT_TEST_TARGET_ARCH@"
|
||||
|
||||
# Load common config for all compiler-rt lit tests.
|
||||
lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
|
||||
|
||||
# Load tool-specific config that would do the real work.
|
||||
lit_config.load_config(config, "@BITINT_LIT_SOURCE_DIR@/Unit/lit.cfg.py")
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
// RUN: %clang_builtins %s %librt -o %t && %run %t
|
||||
|
||||
#include "int_lib.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
// bigx = sext x
|
||||
static void sext(int x, unsigned int* bigx, unsigned words) {
|
||||
char sign = (x < 0) ? 0xFF : 0;
|
||||
memset(bigx, sign, words*sizeof(su_int));
|
||||
#ifdef _YUGA_LITTLE_ENDIAN
|
||||
(void)words;
|
||||
memcpy(bigx, &x, sizeof(x));
|
||||
#else
|
||||
memcpy(bigx + (sizeof(su_int)*words - sizeof(x)), &x, sizeof(x));
|
||||
#endif
|
||||
}
|
||||
|
||||
// x = trunc bigx
|
||||
static void trunc(unsigned int* bigx, int *x, unsigned words) {
|
||||
#ifdef _YUGA_LITTLE_ENDIAN
|
||||
(void)words;
|
||||
memcpy(x, bigx, sizeof(*x));
|
||||
#else
|
||||
memcpy(x, bigx + (sizeof(su_int)*words - sizeof(x)), sizeof(x));
|
||||
#endif
|
||||
}
|
||||
|
||||
int test__divmodei5(int a, int b, int expected_quo, int expected_rem,
|
||||
unsigned words, unsigned int *a_scratch,
|
||||
unsigned int *b_scratch, unsigned int *quo_scratch,
|
||||
unsigned int *rem_scratch) {
|
||||
// sign-extend a and b
|
||||
// 'a' needs to have an extra word, see documentation of __udivmodei5.
|
||||
sext(a, a_scratch, words+1);
|
||||
sext(b, b_scratch, words);
|
||||
|
||||
memset(quo_scratch, 0, words * sizeof(su_int));
|
||||
memset(rem_scratch, 0, words * sizeof(su_int));
|
||||
|
||||
__divmodei5(quo_scratch, rem_scratch, a_scratch, b_scratch, words);
|
||||
|
||||
su_int sign_q = (expected_quo < 0) ? (su_int)-1 : 0;
|
||||
su_int sign_r = (expected_rem < 0) ? (su_int)-1 : 0;
|
||||
|
||||
int q, r;
|
||||
trunc(quo_scratch, &q, words);
|
||||
trunc(rem_scratch, &r, words);
|
||||
|
||||
if (q != expected_quo) {
|
||||
printf("error in __divmodei5: %d / %d = %d, expected %d\n", a, b, q,
|
||||
expected_quo);
|
||||
return 1;
|
||||
}
|
||||
if (r != expected_rem) {
|
||||
printf("error in __divmodei5: %d mod %d = %d, expected %d\n", a, b, r,
|
||||
expected_rem);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// Expect upper bits of result to be sign-extended
|
||||
#ifdef _YUGA_LITTLE_ENDIAN
|
||||
for(unsigned i= sizeof(q); i < words; ++i) {
|
||||
#else
|
||||
for(unsigned i= words - 1; i >= sizeof(q); --i) {
|
||||
#endif
|
||||
if (quo_scratch[i] != sign_q) {
|
||||
printf("error in __divmodei5: %d / %d = %d, R = %d, words=%d expected "
|
||||
"quo_scratch[%d] == %d but got %d\n",
|
||||
a, b, q, r, words, i, sign_q, quo_scratch[i]);
|
||||
return 1;
|
||||
}
|
||||
if (rem_scratch[i] != sign_r) {
|
||||
printf("error in __divmodei5: %d / %d = %d, R = %d, words=%d expected "
|
||||
"rem_scratch[%d] == %d but got %d\n",
|
||||
a, b, q, r, words, i, sign_r, rem_scratch[i]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Multiples of sizeof(int) are allowed for _divmodei5.
|
||||
int words[] = {1, 2, 4, 5, 6, 8};
|
||||
|
||||
int main() {
|
||||
for (unsigned iwords = 0; iwords < sizeof(words) / sizeof(words[0]); ++iwords) {
|
||||
int nwords = words[iwords];
|
||||
// 'a' needs to have an extra word, see documentation of __udivmodei5.
|
||||
unsigned int *a_scratch = malloc((nwords + 1) * sizeof(su_int));
|
||||
unsigned int *b_scratch = malloc(nwords * sizeof(su_int));
|
||||
unsigned int *quo_scratch = malloc(nwords * sizeof(su_int));
|
||||
unsigned int *rem_scratch = malloc(nwords * sizeof(su_int));
|
||||
|
||||
if (test__divmodei5(0, 1, 0, 0, nwords, a_scratch, b_scratch, quo_scratch,
|
||||
rem_scratch))
|
||||
return 1;
|
||||
if (test__divmodei5(0, -1, 0, 0, nwords, a_scratch, b_scratch, quo_scratch,
|
||||
rem_scratch))
|
||||
return 1;
|
||||
if (test__divmodei5(1, 1, 1, 0, nwords, a_scratch, b_scratch, quo_scratch,
|
||||
rem_scratch))
|
||||
return 1;
|
||||
|
||||
if (test__divmodei5(2, 1, 2, 0, nwords, a_scratch, b_scratch, quo_scratch,
|
||||
rem_scratch))
|
||||
return 1;
|
||||
if (test__divmodei5(2, -1, -2, 0, nwords, a_scratch, b_scratch, quo_scratch,
|
||||
rem_scratch))
|
||||
return 1;
|
||||
if (test__divmodei5(-2, 1, -2, 0, nwords, a_scratch, b_scratch, quo_scratch,
|
||||
rem_scratch))
|
||||
return 1;
|
||||
if (test__divmodei5(-2, -1, 2, 0, nwords, a_scratch, b_scratch, quo_scratch,
|
||||
rem_scratch))
|
||||
return 1;
|
||||
|
||||
if (test__divmodei5(7, 5, 1, 2, nwords, a_scratch, b_scratch, quo_scratch,
|
||||
rem_scratch))
|
||||
return 1;
|
||||
if (test__divmodei5(-7, 5, -1, -2, nwords, a_scratch, b_scratch, quo_scratch,
|
||||
rem_scratch))
|
||||
return 1;
|
||||
if (test__divmodei5(19, 5, 3, 4, nwords, a_scratch, b_scratch, quo_scratch,
|
||||
rem_scratch))
|
||||
return 1;
|
||||
if (test__divmodei5(19, -5, -3, 4, nwords, a_scratch, b_scratch, quo_scratch,
|
||||
rem_scratch))
|
||||
return 1;
|
||||
|
||||
if (test__divmodei5(0x80000000, 8, 0xf0000000, 0, nwords, a_scratch,
|
||||
b_scratch, quo_scratch, rem_scratch))
|
||||
return 1;
|
||||
if (test__divmodei5(0x80000007, 8, 0xf0000001, -1, nwords, a_scratch,
|
||||
b_scratch, quo_scratch, rem_scratch))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue