diff --git a/.gitignore b/.gitignore index a17cbe67..091e7388 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,8 @@ build *.app *.dylib *.a +*.o +*.d Debug/* diff --git a/samples/breakout/build.bat b/samples/breakout/build.bat index 74e181d5..f61c42b6 100644 --- a/samples/breakout/build.bat +++ b/samples/breakout/build.bat @@ -12,27 +12,22 @@ if exist "..\..\scripts\sample_build_check.py" ( echo If you have copied this script to your own project, you can delete this code. ) -set ORCA_DIR=..\.. -set STDLIB_DIR=%ORCA_DIR%\src\libc-shim +set ORCA_DIR=../.. +set STDLIB_DIR=%ORCA_DIR%/build/orca-libc :: common flags to build wasm modules set wasmFlags=--target=wasm32^ - --no-standard-libraries ^ -mbulk-memory ^ -g -O2 ^ -D__ORCA__ ^ -Wl,--no-entry ^ -Wl,--export-dynamic ^ - -isystem %STDLIB_DIR%\include ^ - -I%ORCA_DIR%\src ^ - -I%ORCA_DIR%\src\ext - -:: build orca core as wasm module -clang %wasmFlags% -Wl,--relocatable -o .\liborca.a %ORCA_DIR%\src\orca.c %ORCA_DIR%\src\libc-shim\src\*.c -IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL% + --sysroot %ORCA_DIR%/build/orca-libc ^ + -I%ORCA_DIR%/src ^ + -I%ORCA_DIR%/src/ext :: build sample as wasm module and link it with the orca module -clang %wasmFlags% -L . -lorca -o module.wasm src/main.c +clang %wasmFlags% -L %ORCA_DIR%/build/bin -lorca_wasm -o module.wasm src/main.c IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL% :: create app directory and copy files into it diff --git a/samples/breakout/build.sh b/samples/breakout/build.sh index 807888c3..50048bd0 100755 --- a/samples/breakout/build.sh +++ b/samples/breakout/build.sh @@ -13,25 +13,20 @@ else fi ORCA_DIR=../.. -STDLIB_DIR=$ORCA_DIR/src/libc-shim # common flags to build wasm modules wasmFlags="--target=wasm32 \ - --no-standard-libraries \ -mbulk-memory \ -g -O2 \ -D__ORCA__ \ -Wl,--no-entry \ -Wl,--export-dynamic \ - -isystem $STDLIB_DIR/include \ + --sysroot $ORCA_DIR/build/orca-libc \ -I $ORCA_DIR/src \ -I $ORCA_DIR/src/ext" -# build orca core as wasm module -clang $wasmFlags -Wl,--relocatable -o ./liborca.a $ORCA_DIR/src/orca.c $STDLIB_DIR/src/*.c - # build sample as wasm module and link it with the orca module -clang $wasmFlags -L . -lorca -o module.wasm src/main.c +clang $wasmFlags -L $ORCA_DIR/build/bin -lorca_wasm -o module.wasm src/main.c # create app directory and copy files into it orca bundle --orca-dir $ORCA_DIR --name Breakout --icon icon.png --resource-dir data module.wasm diff --git a/samples/clock/build.bat b/samples/clock/build.bat index 9eedbf06..ce9df197 100644 --- a/samples/clock/build.bat +++ b/samples/clock/build.bat @@ -12,27 +12,22 @@ if exist "..\..\scripts\sample_build_check.py" ( echo If you have copied this script to your own project, you can delete this code. ) -set ORCA_DIR=..\.. -set STDLIB_DIR=%ORCA_DIR%\src\libc-shim +set ORCA_DIR=../.. +set STDLIB_DIR=%ORCA_DIR%/build/orca-libc :: common flags to build wasm modules set wasmFlags=--target=wasm32^ - --no-standard-libraries ^ -mbulk-memory ^ -g -O2 ^ -D__ORCA__ ^ -Wl,--no-entry ^ -Wl,--export-dynamic ^ - -isystem %STDLIB_DIR%\include ^ - -I%ORCA_DIR%\src ^ - -I%ORCA_DIR%\src\ext - -:: build orca core as wasm module -clang %wasmFlags% -Wl,--relocatable -o .\liborca.a %ORCA_DIR%\src\orca.c %ORCA_DIR%\src\libc-shim\src\*.c -IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL% + --sysroot %ORCA_DIR%/build/orca-libc ^ + -I%ORCA_DIR%/src ^ + -I%ORCA_DIR%/src/ext :: build sample as wasm module and link it with the orca module -clang %wasmFlags% -L . -lorca -o module.wasm src/main.c +clang %wasmFlags% -L %ORCA_DIR%/build/bin -lorca_wasm -o module.wasm src/main.c IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL% :: create app directory and copy files into it diff --git a/samples/fluid/build.bat b/samples/fluid/build.bat index 1c22a58a..a6ef7f2e 100644 --- a/samples/fluid/build.bat +++ b/samples/fluid/build.bat @@ -12,24 +12,23 @@ if exist "..\..\scripts\sample_build_check.py" ( echo If you have copied this script to your own project, you can delete this code. ) -set ORCA_DIR=..\.. -set STDLIB_DIR=%ORCA_DIR%\src\libc-shim +set ORCA_DIR=../.. +set STDLIB_DIR=%ORCA_DIR%/build/orca-libc :: common flags to build wasm modules set wasmFlags=--target=wasm32^ - --no-standard-libraries ^ -mbulk-memory ^ -g -O2 ^ -D__ORCA__ ^ -Wl,--no-entry ^ -Wl,--export-dynamic ^ - -isystem %STDLIB_DIR%\include ^ - -I%ORCA_DIR%\src ^ - -I%ORCA_DIR%\src\ext + --sysroot %ORCA_DIR%/build/orca-libc ^ + -I%ORCA_DIR%/src ^ + -I%ORCA_DIR%/src/ext :: build orca core as wasm module -clang %wasmFlags% -Wl,--relocatable -o .\liborca.a %ORCA_DIR%\src\orca.c %ORCA_DIR%\src\libc-shim\src\*.c -IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL% +rem clang %wasmFlags% -Wl,--relocatable -o .\liborca.a %ORCA_DIR%\src\orca.c %ORCA_DIR%\src\libc-shim\src\*.c +rem IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL% set shaders=src/shaders/advect.glsl^ src/shaders/blit_div_fragment.glsl^ @@ -50,8 +49,9 @@ call python ../../scripts/embed_text_files.py --prefix=glsl_ --output src/glsl_s if !ERRORLEVEL! neq 0 exit /b !ERRORLEVEL! :: build sample as wasm module and link it with the orca module -clang %wasmFlags% -L . -lorca -o .\module.wasm src\main.c +clang %wasmFlags% -L %ORCA_DIR%/build/bin -lorca_wasm -o module.wasm src/main.c IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL% :: create app directory and copy files into it orca bundle --orca-dir %ORCA_DIR% --name Fluid --icon icon.png module.wasm + diff --git a/samples/fluid/build.sh b/samples/fluid/build.sh index e13eb11c..be6529f6 100755 --- a/samples/fluid/build.sh +++ b/samples/fluid/build.sh @@ -13,27 +13,22 @@ else fi ORCA_DIR=../.. -STDLIB_DIR=$ORCA_DIR/src/libc-shim python3 ../../scripts/embed_text_files.py --prefix=glsl_ --output src/glsl_shaders.h src/shaders/*.glsl # common flags to build wasm modules wasmFlags="--target=wasm32 \ - --no-standard-libraries \ -mbulk-memory \ -g -O2 \ -D__ORCA__ \ -Wl,--no-entry \ -Wl,--export-dynamic \ - -isystem $STDLIB_DIR/include \ + --sysroot $ORCA_DIR/build/orca-libc \ -I $ORCA_DIR/src \ -I $ORCA_DIR/src/ext" -# build orca core as wasm module -clang $wasmFlags -Wl,--relocatable -o ./liborca.a $ORCA_DIR/src/orca.c $STDLIB_DIR/src/*.c - # build sample as wasm module and link it with the orca module -clang $wasmFlags -L . -lorca -o module.wasm src/main.c +clang $wasmFlags -L $ORCA_DIR/build/bin -lorca_wasm -o module.wasm src/main.c # create app directory and copy files into it orca bundle --orca-dir $ORCA_DIR --name Fluid --icon icon.png module.wasm diff --git a/samples/triangle/build.bat b/samples/triangle/build.bat index d5c07a94..c72547bd 100644 --- a/samples/triangle/build.bat +++ b/samples/triangle/build.bat @@ -12,27 +12,23 @@ if exist "..\..\scripts\sample_build_check.py" ( echo If you have copied this script to your own project, you can delete this code. ) -set ORCA_DIR=..\.. -set STDLIB_DIR=%ORCA_DIR%\src\libc-shim + +set ORCA_DIR=../.. +set STDLIB_DIR=%ORCA_DIR%/build/orca-libc :: common flags to build wasm modules set wasmFlags=--target=wasm32^ - --no-standard-libraries ^ -mbulk-memory ^ -g -O2 ^ -D__ORCA__ ^ -Wl,--no-entry ^ -Wl,--export-dynamic ^ - -isystem %STDLIB_DIR%\include ^ - -I%ORCA_DIR%\src ^ - -I%ORCA_DIR%\src\ext - -:: build orca core as wasm module -clang %wasmFlags% -Wl,--relocatable -o .\liborca.a %ORCA_DIR%\src\orca.c %ORCA_DIR%\src\libc-shim\src\*.c -IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL% + --sysroot %ORCA_DIR%/build/orca-libc ^ + -I%ORCA_DIR%/src ^ + -I%ORCA_DIR%/src/ext :: build sample as wasm module and link it with the orca module -clang %wasmFlags% -L . -lorca -o module.wasm src/main.c +clang %wasmFlags% -L %ORCA_DIR%/build/bin -lorca_wasm -o module.wasm src/main.c IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL% :: create app directory and copy files into it diff --git a/samples/triangle/build.sh b/samples/triangle/build.sh index ba68ae4b..4e09520f 100755 --- a/samples/triangle/build.sh +++ b/samples/triangle/build.sh @@ -13,25 +13,20 @@ else fi ORCA_DIR=../.. -STDLIB_DIR=$ORCA_DIR/src/libc-shim # common flags to build wasm modules wasmFlags="--target=wasm32 \ - --no-standard-libraries \ -mbulk-memory \ -g -O2 \ -D__ORCA__ \ -Wl,--no-entry \ -Wl,--export-dynamic \ - -isystem $STDLIB_DIR/include \ + --sysroot $ORCA_DIR/build/orca-libc \ -I $ORCA_DIR/src \ -I $ORCA_DIR/src/ext" -# build orca core as wasm module -clang $wasmFlags -Wl,--relocatable -o ./liborca.a $ORCA_DIR/src/orca.c $STDLIB_DIR/src/*.c - # build sample as wasm module and link it with the orca module -clang $wasmFlags -L . -lorca -o module.wasm src/main.c +clang $wasmFlags -L $ORCA_DIR/build/bin -lorca_wasm -o module.wasm src/main.c # create app directory and copy files into it orca bundle --orca-dir $ORCA_DIR --name Triangle module.wasm diff --git a/samples/ui/build.bat b/samples/ui/build.bat index cf64748f..a76924d7 100644 --- a/samples/ui/build.bat +++ b/samples/ui/build.bat @@ -12,27 +12,22 @@ if exist "..\..\scripts\sample_build_check.py" ( echo If you have copied this script to your own project, you can delete this code. ) -set ORCA_DIR=..\.. -set STDLIB_DIR=%ORCA_DIR%\src\libc-shim +set ORCA_DIR=../.. +set STDLIB_DIR=%ORCA_DIR%/build/orca-libc :: common flags to build wasm modules set wasmFlags=--target=wasm32^ - --no-standard-libraries ^ -mbulk-memory ^ -g -O2 ^ -D__ORCA__ ^ -Wl,--no-entry ^ -Wl,--export-dynamic ^ - -isystem %STDLIB_DIR%\include ^ - -I%ORCA_DIR%\src ^ - -I%ORCA_DIR%\src\ext - -:: build orca core as wasm module -clang %wasmFlags% -Wl,--relocatable -o .\liborca.a %ORCA_DIR%\src\orca.c %ORCA_DIR%\src\libc-shim\src\*.c -IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL% + --sysroot %ORCA_DIR%/build/orca-libc ^ + -I%ORCA_DIR%/src ^ + -I%ORCA_DIR%/src/ext :: build sample as wasm module and link it with the orca module -clang %wasmFlags% -L . -lorca -o .\module.wasm src\main.c +clang %wasmFlags% -L %ORCA_DIR%/build/bin -lorca_wasm -o module.wasm src/main.c IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL% :: create app directory and copy files into it diff --git a/samples/ui/build.sh b/samples/ui/build.sh index 98c1e871..05fbbe91 100755 --- a/samples/ui/build.sh +++ b/samples/ui/build.sh @@ -13,25 +13,20 @@ else fi ORCA_DIR=../.. -STDLIB_DIR=$ORCA_DIR/src/libc-shim # common flags to build wasm modules wasmFlags="--target=wasm32 \ - --no-standard-libraries \ -mbulk-memory \ -g -O2 \ -D__ORCA__ \ -Wl,--no-entry \ -Wl,--export-dynamic \ - -isystem $STDLIB_DIR/include \ + --sysroot $ORCA_DIR/build/orca-libc \ -I $ORCA_DIR/src \ -I $ORCA_DIR/src/ext" -# build orca core as wasm module -clang $wasmFlags -Wl,--relocatable -o ./liborca.a $ORCA_DIR/src/orca.c $STDLIB_DIR/src/*.c - # build sample as wasm module and link it with the orca module -clang $wasmFlags -L . -lorca -o module.wasm src/main.c +clang $wasmFlags -L $ORCA_DIR/build/bin -lorca_wasm -o module.wasm src/main.c # create app directory and copy files into it orca bundle --orca-dir $ORCA_DIR --name UI --resource-dir data module.wasm diff --git a/samples/ui/src/main.c b/samples/ui/src/main.c index 45203d73..23d9d48a 100644 --- a/samples/ui/src/main.c +++ b/samples/ui/src/main.c @@ -7,6 +7,7 @@ **************************************************************************/ #include "orca.h" #include +#include oc_vec2 frameSize = { 1200, 838 }; diff --git a/scripts/dev.py b/scripts/dev.py index 1497d826..6247574b 100644 --- a/scripts/dev.py +++ b/scripts/dev.py @@ -66,6 +66,8 @@ def build_runtime(args): build_platform_layer("lib", args.release) build_wasm3(args.release) build_orca(args.release) + build_libc(args.release) + build_sdk(args.release) with open("build/orcaruntime.sum", "w") as f: f.write(runtime_checksum()) @@ -403,6 +405,96 @@ def gen_all_bindings(): wasm3_bindings="src/wasmbind/io_api_bind_gen.c", ) +def build_libc(release): + print("Building orca-libc...") + + # create directory and copy header files + os.makedirs("build/orca-libc", exist_ok=True) + os.makedirs("build/orca-libc/lib", exist_ok=True) + os.makedirs("build/orca-libc/include", exist_ok=True) + + shutil.copytree(f"src/orca-libc/include", "build/orca-libc/include", dirs_exist_ok=True) + + # compile flags, include, etc + cfiles = [] + dirs = os.listdir("src/orca-libc/src") + for directory in dirs: + cfiles.extend(glob.glob('src/orca-libc/src/' + directory + '/*.c')) + + includes = [ + "-Isrc", + "-isystem", "src/orca-libc/include", + "-isystem", "src/orca-libc/include/private", + "-Isrc/orca-libc/src/arch", + "-Isrc/orca-libc/src/internal" + ] + + warning_flags = [ + "-Wall", "-Wextra", "-Werror", "-Wno-null-pointer-arithmetic", "-Wno-unused-parameter", "-Wno-sign-compare", "-Wno-unused-variable", "-Wno-unused-function", "-Wno-ignored-attributes", "-Wno-missing-braces", "-Wno-ignored-pragmas", "-Wno-unused-but-set-variable", "-Wno-unknown-warning-option", "-Wno-parentheses", "-Wno-shift-op-parentheses", "-Wno-bitwise-op-parentheses", "-Wno-logical-op-parentheses", "-Wno-string-plus-int", "-Wno-dangling-else", "-Wno-unknown-pragmas" + ] + + debug_flags = ["-O2", "-DNDEBUG"] if release else ["-g"] + + flags = [ + *debug_flags, + *warning_flags, + "--target=wasm32", + "--std=c11", + "-D__ORCA__", + "--no-standard-libraries", + "-fno-trapping-math", + "-mbulk-memory", + "-DBULK_MEMORY_THRESHOLD=32", + "-mthread-model", "single", + "-Wl,--relocatable" + ] + + # compile dummy CRT + subprocess.run([ + "clang", *flags, *includes, + "-o", "build/orca-libc/lib/crt1.o", + "src/orca-libc/src/crt/crt1.c" + ], check=True) + + # compile standard lib + subprocess.run([ + "clang", *flags, *includes, + "-o", "build/orca-libc/lib/libc.o", + *cfiles + ], check=True) + + subprocess.run([ + "llvm-ar", "crs", + "build/orca-libc/lib/libc.a", + "build/orca-libc/lib/libc.o" + ], check=True) + +def build_sdk(release): + print("Building orca wasm sdk...") + + includes = [ + "-I", "src", + "-I", "src/ext", + "-I", "build/orca-libc/include", + ] + + debug_flags = ["-O2", "-DNDEBUG"] if release else ["-g"] + + flags = [ + *debug_flags, + "--target=wasm32", + "--std=c11", + "-D__ORCA__", + "--no-standard-libraries", + "-mbulk-memory", + "-Wl,--relocatable" + ] + + subprocess.run([ + "clang", *flags, *includes, + "-o", "build/bin/liborca_wasm.a", + "src/orca.c" + ], check=True) def ensure_programs(): if platform.system() == "Windows": diff --git a/src/libc-shim/include/bits/errno.h b/src/libc-shim/include/bits/errno.h deleted file mode 100644 index b9ebc31b..00000000 --- a/src/libc-shim/include/bits/errno.h +++ /dev/null @@ -1,134 +0,0 @@ -#define EPERM 1 -#define ENOENT 2 -#define ESRCH 3 -#define EINTR 4 -#define EIO 5 -#define ENXIO 6 -#define E2BIG 7 -#define ENOEXEC 8 -#define EBADF 9 -#define ECHILD 10 -#define EAGAIN 11 -#define ENOMEM 12 -#define EACCES 13 -#define EFAULT 14 -#define ENOTBLK 15 -#define EBUSY 16 -#define EEXIST 17 -#define EXDEV 18 -#define ENODEV 19 -#define ENOTDIR 20 -#define EISDIR 21 -#define EINVAL 22 -#define ENFILE 23 -#define EMFILE 24 -#define ENOTTY 25 -#define ETXTBSY 26 -#define EFBIG 27 -#define ENOSPC 28 -#define ESPIPE 29 -#define EROFS 30 -#define EMLINK 31 -#define EPIPE 32 -#define EDOM 33 -#define ERANGE 34 -#define EDEADLK 35 -#define ENAMETOOLONG 36 -#define ENOLCK 37 -#define ENOSYS 38 -#define ENOTEMPTY 39 -#define ELOOP 40 -#define EWOULDBLOCK EAGAIN -#define ENOMSG 42 -#define EIDRM 43 -#define ECHRNG 44 -#define EL2NSYNC 45 -#define EL3HLT 46 -#define EL3RST 47 -#define ELNRNG 48 -#define EUNATCH 49 -#define ENOCSI 50 -#define EL2HLT 51 -#define EBADE 52 -#define EBADR 53 -#define EXFULL 54 -#define ENOANO 55 -#define EBADRQC 56 -#define EBADSLT 57 -#define EDEADLOCK EDEADLK -#define EBFONT 59 -#define ENOSTR 60 -#define ENODATA 61 -#define ETIME 62 -#define ENOSR 63 -#define ENONET 64 -#define ENOPKG 65 -#define EREMOTE 66 -#define ENOLINK 67 -#define EADV 68 -#define ESRMNT 69 -#define ECOMM 70 -#define EPROTO 71 -#define EMULTIHOP 72 -#define EDOTDOT 73 -#define EBADMSG 74 -#define EOVERFLOW 75 -#define ENOTUNIQ 76 -#define EBADFD 77 -#define EREMCHG 78 -#define ELIBACC 79 -#define ELIBBAD 80 -#define ELIBSCN 81 -#define ELIBMAX 82 -#define ELIBEXEC 83 -#define EILSEQ 84 -#define ERESTART 85 -#define ESTRPIPE 86 -#define EUSERS 87 -#define ENOTSOCK 88 -#define EDESTADDRREQ 89 -#define EMSGSIZE 90 -#define EPROTOTYPE 91 -#define ENOPROTOOPT 92 -#define EPROTONOSUPPORT 93 -#define ESOCKTNOSUPPORT 94 -#define EOPNOTSUPP 95 -#define ENOTSUP EOPNOTSUPP -#define EPFNOSUPPORT 96 -#define EAFNOSUPPORT 97 -#define EADDRINUSE 98 -#define EADDRNOTAVAIL 99 -#define ENETDOWN 100 -#define ENETUNREACH 101 -#define ENETRESET 102 -#define ECONNABORTED 103 -#define ECONNRESET 104 -#define ENOBUFS 105 -#define EISCONN 106 -#define ENOTCONN 107 -#define ESHUTDOWN 108 -#define ETOOMANYREFS 109 -#define ETIMEDOUT 110 -#define ECONNREFUSED 111 -#define EHOSTDOWN 112 -#define EHOSTUNREACH 113 -#define EALREADY 114 -#define EINPROGRESS 115 -#define ESTALE 116 -#define EUCLEAN 117 -#define ENOTNAM 118 -#define ENAVAIL 119 -#define EISNAM 120 -#define EREMOTEIO 121 -#define EDQUOT 122 -#define ENOMEDIUM 123 -#define EMEDIUMTYPE 124 -#define ECANCELED 125 -#define ENOKEY 126 -#define EKEYEXPIRED 127 -#define EKEYREVOKED 128 -#define EKEYREJECTED 129 -#define EOWNERDEAD 130 -#define ENOTRECOVERABLE 131 -#define ERFKILL 132 -#define EHWPOISON 133 diff --git a/src/libc-shim/include/bits/float.h b/src/libc-shim/include/bits/float.h deleted file mode 100644 index c4a655e7..00000000 --- a/src/libc-shim/include/bits/float.h +++ /dev/null @@ -1,16 +0,0 @@ -#define FLT_EVAL_METHOD 0 - -#define LDBL_TRUE_MIN 4.94065645841246544177e-324L -#define LDBL_MIN 2.22507385850720138309e-308L -#define LDBL_MAX 1.79769313486231570815e+308L -#define LDBL_EPSILON 2.22044604925031308085e-16L - -#define LDBL_MANT_DIG 53 -#define LDBL_MIN_EXP (-1021) -#define LDBL_MAX_EXP 1024 - -#define LDBL_DIG 15 -#define LDBL_MIN_10_EXP (-307) -#define LDBL_MAX_10_EXP 308 - -#define DECIMAL_DIG 17 diff --git a/src/libc-shim/include/errno.h b/src/libc-shim/include/errno.h deleted file mode 100644 index 20e06bc6..00000000 --- a/src/libc-shim/include/errno.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _ERRNO_H -#define _ERRNO_H - -#ifdef __cplusplus -extern "C" -{ -#endif - -#include - -#include - -#ifdef __GNUC__ - __attribute__((const)) -#endif - int* - __errno_location(void); -#define errno (*__errno_location()) - -#ifdef _GNU_SOURCE - extern char *program_invocation_short_name, *program_invocation_name; -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/libc-shim/include/features.h b/src/libc-shim/include/features.h deleted file mode 100644 index e69de29b..00000000 diff --git a/src/libc-shim/include/math.h b/src/libc-shim/include/math.h deleted file mode 100644 index 737b6297..00000000 --- a/src/libc-shim/include/math.h +++ /dev/null @@ -1,132 +0,0 @@ -#ifndef _MATH_H -#define _MATH_H - -#ifdef __cplusplus -extern "C" { -#endif - -// NOTE(orca): not doing anything fancy for float_t and double_t -typedef float float_t; -typedef double double_t; - -#define NAN __builtin_nanf("") -#define INFINITY __builtin_inff() - -#define FP_NAN 0 -#define FP_INFINITE 1 -#define FP_ZERO 2 -#define FP_SUBNORMAL 3 -#define FP_NORMAL 4 - -int __fpclassify(double); -int __fpclassifyf(float); -int __fpclassifyl(long double); - -static __inline unsigned __FLOAT_BITS(float __f) -{ - union - { - float __f; - unsigned __i; - } __u; - - __u.__f = __f; - return __u.__i; -} - -static __inline unsigned long long __DOUBLE_BITS(double __f) -{ - union - { - double __f; - unsigned long long __i; - } __u; - - __u.__f = __f; - return __u.__i; -} - -#define fpclassify(x) ( \ - sizeof(x) == sizeof(float) ? __fpclassifyf(x) : sizeof(x) == sizeof(double) ? __fpclassify(x) \ - : __fpclassifyl(x)) - -#define isinf(x) ( \ - sizeof(x) == sizeof(float) ? (__FLOAT_BITS(x) & 0x7fffffff) == 0x7f800000 : sizeof(x) == sizeof(double) ? (__DOUBLE_BITS(x) & -1ULL >> 1) == 0x7ffULL << 52 \ - : __fpclassifyl(x) == FP_INFINITE) - -#define isnan(x) ( \ - sizeof(x) == sizeof(float) ? (__FLOAT_BITS(x) & 0x7fffffff) > 0x7f800000 : sizeof(x) == sizeof(double) ? (__DOUBLE_BITS(x) & -1ULL >> 1) > 0x7ffULL << 52 \ - : __fpclassifyl(x) == FP_NAN) - -double fabs(double); -float fabsf(float); - -double acos(double); -float acosf(float); - -double cbrt(double); -float cbrtf(float); - -double ceil(double); - -double cos(double); -float cosf(float); - -double floor(double); - -double fmod(double, double); - -double log(double); -float logf(float); -double log2(double); -float log2f(float); - -double pow(double, double); -float powf(float, float); - -double exp(double); -float expf(float); - -double scalbn(double, int); - -double sin(double); -float sinf(float); - -double asin(double); -float asinf(float); - -double tan(double); -float tanf(float); - -double atan(double); -float atanf(float); -double atan2(double, double); -float atan2f(float, float); - -double sqrt(double); -float sqrtf(float); - -#define M_E 2.7182818284590452354 /* e */ -#define M_LOG2E 1.4426950408889634074 /* log_2 e */ -#define M_LOG10E 0.43429448190325182765 /* log_10 e */ -#define M_LN2 0.69314718055994530942 /* log_e 2 */ -#define M_LN10 2.30258509299404568402 /* log_e 10 */ -#define M_PI 3.14159265358979323846 /* pi */ -#define M_PI_2 1.57079632679489661923 /* pi/2 */ -#define M_PI_4 0.78539816339744830962 /* pi/4 */ -#define M_1_PI 0.31830988618379067154 /* 1/pi */ -#define M_2_PI 0.63661977236758134308 /* 2/pi */ -#define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */ -#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ -#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ - -//NOTE(orca) - implementation details -typedef unsigned uint32_t; -double __math_divzero(uint32_t sign); -float __math_divzerof(uint32_t sign); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/libc-shim/include/stdlib.h b/src/libc-shim/include/stdlib.h deleted file mode 100644 index 8c564589..00000000 --- a/src/libc-shim/include/stdlib.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _STDLIB_H -#define _STDLIB_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define abort(...) OC_ABORT(__VA_ARGS__) - -int abs(int); - -void* malloc(size_t); -void* realloc(void*, size_t); -void* calloc(size_t count, size_t size); -void free(void*); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/libc-shim/include/string.h b/src/libc-shim/include/string.h deleted file mode 100644 index 20868298..00000000 --- a/src/libc-shim/include/string.h +++ /dev/null @@ -1,22 +0,0 @@ -#include "stb/stb_sprintf.h" - -#ifdef __cplusplus -extern "C" { -#endif - -void* memset(void* b, int c, size_t n); -void* memcpy(void* __restrict dst, const void* __restrict src, size_t n); -void* memmove(void* dst, const void* src, size_t n); -int memcmp(const void* s1, const void* s2, size_t n); - -size_t strlen(const char* s); -int strcmp(const char* s1, const char* s2); -int strncmp(const char* s1, const char* s2, size_t n); -char* strcpy(char* __restrict s1, const char* __restrict s2); - -#define snprintf stbsp_snprintf -#define vsnprintf stbsp_vsnprintf - -#ifdef __cplusplus -} // extern "C" -#endif diff --git a/src/libc-shim/src/__errno_location.c b/src/libc-shim/src/__errno_location.c deleted file mode 100644 index 43f203f8..00000000 --- a/src/libc-shim/src/__errno_location.c +++ /dev/null @@ -1,9 +0,0 @@ -#include - -int errno; - -int* __errno_location(void) -{ - // NOTE(orca): We might need a better solution if we eventually support wasm threads. - return &errno; -} diff --git a/src/libc-shim/src/__math_divzero.c b/src/libc-shim/src/__math_divzero.c deleted file mode 100644 index 8f3d84cc..00000000 --- a/src/libc-shim/src/__math_divzero.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "libm.h" - -double __math_divzero(uint32_t sign) -{ - // NOTE(orca): no fp barriers - return (sign ? -1.0 : 1.0) / 0.0; -} diff --git a/src/libc-shim/src/__math_divzerof.c b/src/libc-shim/src/__math_divzerof.c deleted file mode 100644 index 52b2d343..00000000 --- a/src/libc-shim/src/__math_divzerof.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "libm.h" - -float __math_divzerof(uint32_t sign) -{ - // NOTE(orca): no fp barriers - return (sign ? -1.0f : 1.0f) / 0.0f; -} diff --git a/src/libc-shim/src/__math_xflow.c b/src/libc-shim/src/__math_xflow.c deleted file mode 100644 index 9118f29f..00000000 --- a/src/libc-shim/src/__math_xflow.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "libm.h" - -double __math_xflow(uint32_t sign, double y) -{ - // NOTE(orca): no fp barriers - // return eval_as_double(fp_barrier(sign ? -y : y) * y); - return eval_as_double((sign ? -y : y) * y); -} diff --git a/src/libc-shim/src/__math_xflowf.c b/src/libc-shim/src/__math_xflowf.c deleted file mode 100644 index 000d3113..00000000 --- a/src/libc-shim/src/__math_xflowf.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "libm.h" - -float __math_xflowf(uint32_t sign, float y) -{ - // NOTE(orca): no fp barriers - // return eval_as_double(fp_barrier(sign ? -y : y) * y); - return eval_as_float((sign ? -y : y) * y); -} diff --git a/src/libc-shim/src/__rem_pio2.c b/src/libc-shim/src/__rem_pio2.c deleted file mode 100644 index 7e33167a..00000000 --- a/src/libc-shim/src/__rem_pio2.c +++ /dev/null @@ -1,224 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - * - * Optimized by Bruce D. Evans. - */ -/* __rem_pio2(x,y) - * - * return the remainder of x rem pi/2 in y[0]+y[1] - * use __rem_pio2_large() for large x - */ - -#include "libm.h" - -#if FLT_EVAL_METHOD == 0 || FLT_EVAL_METHOD == 1 - #define EPS DBL_EPSILON -#elif FLT_EVAL_METHOD == 2 - #define EPS LDBL_EPSILON -#endif - -/* - * invpio2: 53 bits of 2/pi - * pio2_1: first 33 bit of pi/2 - * pio2_1t: pi/2 - pio2_1 - * pio2_2: second 33 bit of pi/2 - * pio2_2t: pi/2 - (pio2_1+pio2_2) - * pio2_3: third 33 bit of pi/2 - * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3) - */ -static const double - toint = 1.5 / EPS, - pio4 = 0x1.921fb54442d18p-1, - invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ - pio2_1 = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */ - pio2_1t = 6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */ - pio2_2 = 6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */ - pio2_2t = 2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */ - pio2_3 = 2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */ - pio2_3t = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ - -/* caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ -int __rem_pio2(double x, double* y) -{ - union - { - double f; - uint64_t i; - } u = { x }; - - double_t z, w, t, r, fn; - double tx[3], ty[2]; - uint32_t ix; - int sign, n, ex, ey, i; - - sign = u.i >> 63; - ix = u.i >> 32 & 0x7fffffff; - if(ix <= 0x400f6a7a) - { /* |x| ~<= 5pi/4 */ - if((ix & 0xfffff) == 0x921fb) /* |x| ~= pi/2 or 2pi/2 */ - goto medium; /* cancellation -- use medium case */ - if(ix <= 0x4002d97c) - { /* |x| ~<= 3pi/4 */ - if(!sign) - { - z = x - pio2_1; /* one round good to 85 bits */ - y[0] = z - pio2_1t; - y[1] = (z - y[0]) - pio2_1t; - return 1; - } - else - { - z = x + pio2_1; - y[0] = z + pio2_1t; - y[1] = (z - y[0]) + pio2_1t; - return -1; - } - } - else - { - if(!sign) - { - z = x - 2 * pio2_1; - y[0] = z - 2 * pio2_1t; - y[1] = (z - y[0]) - 2 * pio2_1t; - return 2; - } - else - { - z = x + 2 * pio2_1; - y[0] = z + 2 * pio2_1t; - y[1] = (z - y[0]) + 2 * pio2_1t; - return -2; - } - } - } - if(ix <= 0x401c463b) - { /* |x| ~<= 9pi/4 */ - if(ix <= 0x4015fdbc) - { /* |x| ~<= 7pi/4 */ - if(ix == 0x4012d97c) /* |x| ~= 3pi/2 */ - goto medium; - if(!sign) - { - z = x - 3 * pio2_1; - y[0] = z - 3 * pio2_1t; - y[1] = (z - y[0]) - 3 * pio2_1t; - return 3; - } - else - { - z = x + 3 * pio2_1; - y[0] = z + 3 * pio2_1t; - y[1] = (z - y[0]) + 3 * pio2_1t; - return -3; - } - } - else - { - if(ix == 0x401921fb) /* |x| ~= 4pi/2 */ - goto medium; - if(!sign) - { - z = x - 4 * pio2_1; - y[0] = z - 4 * pio2_1t; - y[1] = (z - y[0]) - 4 * pio2_1t; - return 4; - } - else - { - z = x + 4 * pio2_1; - y[0] = z + 4 * pio2_1t; - y[1] = (z - y[0]) + 4 * pio2_1t; - return -4; - } - } - } - if(ix < 0x413921fb) - { /* |x| ~< 2^20*(pi/2), medium size */ - medium: - /* rint(x/(pi/2)) */ - fn = (double_t)x * invpio2 + toint - toint; - n = (int32_t)fn; - r = x - fn * pio2_1; - w = fn * pio2_1t; /* 1st round, good to 85 bits */ - /* Matters with directed rounding. */ - if(predict_false(r - w < -pio4)) - { - n--; - fn--; - r = x - fn * pio2_1; - w = fn * pio2_1t; - } - else if(predict_false(r - w > pio4)) - { - n++; - fn++; - r = x - fn * pio2_1; - w = fn * pio2_1t; - } - y[0] = r - w; - u.f = y[0]; - ey = u.i >> 52 & 0x7ff; - ex = ix >> 20; - if(ex - ey > 16) - { /* 2nd round, good to 118 bits */ - t = r; - w = fn * pio2_2; - r = t - w; - w = fn * pio2_2t - ((t - r) - w); - y[0] = r - w; - u.f = y[0]; - ey = u.i >> 52 & 0x7ff; - if(ex - ey > 49) - { /* 3rd round, good to 151 bits, covers all cases */ - t = r; - w = fn * pio2_3; - r = t - w; - w = fn * pio2_3t - ((t - r) - w); - y[0] = r - w; - } - } - y[1] = (r - y[0]) - w; - return n; - } - /* - * all other (large) arguments - */ - if(ix >= 0x7ff00000) - { /* x is inf or NaN */ - y[0] = y[1] = x - x; - return 0; - } - /* set z = scalbn(|x|,-ilogb(x)+23) */ - u.f = x; - u.i &= (uint64_t)-1 >> 12; - u.i |= (uint64_t)(0x3ff + 23) << 52; - z = u.f; - for(i = 0; i < 2; i++) - { - tx[i] = (double)(int32_t)z; - z = (z - tx[i]) * 0x1p24; - } - tx[i] = z; - /* skip zero terms, first term is non-zero */ - while(tx[i] == 0.0) - i--; - n = __rem_pio2_large(tx, ty, (int)(ix >> 20) - (0x3ff + 23), i + 1, 1); - if(sign) - { - y[0] = -ty[0]; - y[1] = -ty[1]; - return -n; - } - y[0] = ty[0]; - y[1] = ty[1]; - return n; -} diff --git a/src/libc-shim/src/__rem_pio2_large.c b/src/libc-shim/src/__rem_pio2_large.c deleted file mode 100644 index bfdfad3d..00000000 --- a/src/libc-shim/src/__rem_pio2_large.c +++ /dev/null @@ -1,1060 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/k_rem_pio2.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* - * __rem_pio2_large(x,y,e0,nx,prec) - * double x[],y[]; int e0,nx,prec; - * - * __rem_pio2_large return the last three digits of N with - * y = x - N*pi/2 - * so that |y| < pi/2. - * - * The method is to compute the integer (mod 8) and fraction parts of - * (2/pi)*x without doing the full multiplication. In general we - * skip the part of the product that are known to be a huge integer ( - * more accurately, = 0 mod 8 ). Thus the number of operations are - * independent of the exponent of the input. - * - * (2/pi) is represented by an array of 24-bit integers in ipio2[]. - * - * Input parameters: - * x[] The input value (must be positive) is broken into nx - * pieces of 24-bit integers in double precision format. - * x[i] will be the i-th 24 bit of x. The scaled exponent - * of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 - * match x's up to 24 bits. - * - * Example of breaking a double positive z into x[0]+x[1]+x[2]: - * e0 = ilogb(z)-23 - * z = scalbn(z,-e0) - * for i = 0,1,2 - * x[i] = floor(z) - * z = (z-x[i])*2**24 - * - * - * y[] ouput result in an array of double precision numbers. - * The dimension of y[] is: - * 24-bit precision 1 - * 53-bit precision 2 - * 64-bit precision 2 - * 113-bit precision 3 - * The actual value is the sum of them. Thus for 113-bit - * precison, one may have to do something like: - * - * long double t,w,r_head, r_tail; - * t = (long double)y[2] + (long double)y[1]; - * w = (long double)y[0]; - * r_head = t+w; - * r_tail = w - (r_head - t); - * - * e0 The exponent of x[0]. Must be <= 16360 or you need to - * expand the ipio2 table. - * - * nx dimension of x[] - * - * prec an integer indicating the precision: - * 0 24 bits (single) - * 1 53 bits (double) - * 2 64 bits (extended) - * 3 113 bits (quad) - * - * External function: - * double scalbn(), floor(); - * - * - * Here is the description of some local variables: - * - * jk jk+1 is the initial number of terms of ipio2[] needed - * in the computation. The minimum and recommended value - * for jk is 3,4,4,6 for single, double, extended, and quad. - * jk+1 must be 2 larger than you might expect so that our - * recomputation test works. (Up to 24 bits in the integer - * part (the 24 bits of it that we compute) and 23 bits in - * the fraction part may be lost to cancelation before we - * recompute.) - * - * jz local integer variable indicating the number of - * terms of ipio2[] used. - * - * jx nx - 1 - * - * jv index for pointing to the suitable ipio2[] for the - * computation. In general, we want - * ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 - * is an integer. Thus - * e0-3-24*jv >= 0 or (e0-3)/24 >= jv - * Hence jv = max(0,(e0-3)/24). - * - * jp jp+1 is the number of terms in PIo2[] needed, jp = jk. - * - * q[] double array with integral value, representing the - * 24-bits chunk of the product of x and 2/pi. - * - * q0 the corresponding exponent of q[0]. Note that the - * exponent for q[i] would be q0-24*i. - * - * PIo2[] double precision array, obtained by cutting pi/2 - * into 24 bits chunks. - * - * f[] ipio2[] in floating point - * - * iq[] integer array by breaking up q[] in 24-bits chunk. - * - * fq[] final product of x*(2/pi) in fq[0],..,fq[jk] - * - * ih integer. If >0 it indicates q[] is >= 0.5, hence - * it also indicates the *sign* of the result. - * - */ -/* - * Constants: - * The hexadecimal values are the intended ones for the following - * constants. The decimal values may be used, provided that the - * compiler will convert from decimal to binary accurately enough - * to produce the hexadecimal values shown. - */ - -#include "libm.h" - -static const int init_jk[] = { 3, 4, 4, 6 }; /* initial value for jk */ - -/* - * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi - * - * integer array, contains the (24*i)-th to (24*i+23)-th - * bit of 2/pi after binary point. The corresponding - * floating value is - * - * ipio2[i] * 2^(-24(i+1)). - * - * NB: This table must have at least (e0-3)/24 + jk terms. - * For quad precision (e0 <= 16360, jk = 6), this is 686. - */ -static const int32_t ipio2[] = { - 0xA2F983, - 0x6E4E44, - 0x1529FC, - 0x2757D1, - 0xF534DD, - 0xC0DB62, - 0x95993C, - 0x439041, - 0xFE5163, - 0xABDEBB, - 0xC561B7, - 0x246E3A, - 0x424DD2, - 0xE00649, - 0x2EEA09, - 0xD1921C, - 0xFE1DEB, - 0x1CB129, - 0xA73EE8, - 0x8235F5, - 0x2EBB44, - 0x84E99C, - 0x7026B4, - 0x5F7E41, - 0x3991D6, - 0x398353, - 0x39F49C, - 0x845F8B, - 0xBDF928, - 0x3B1FF8, - 0x97FFDE, - 0x05980F, - 0xEF2F11, - 0x8B5A0A, - 0x6D1F6D, - 0x367ECF, - 0x27CB09, - 0xB74F46, - 0x3F669E, - 0x5FEA2D, - 0x7527BA, - 0xC7EBE5, - 0xF17B3D, - 0x0739F7, - 0x8A5292, - 0xEA6BFB, - 0x5FB11F, - 0x8D5D08, - 0x560330, - 0x46FC7B, - 0x6BABF0, - 0xCFBC20, - 0x9AF436, - 0x1DA9E3, - 0x91615E, - 0xE61B08, - 0x659985, - 0x5F14A0, - 0x68408D, - 0xFFD880, - 0x4D7327, - 0x310606, - 0x1556CA, - 0x73A8C9, - 0x60E27B, - 0xC08C6B, - -#if LDBL_MAX_EXP > 1024 - 0x47C419, - 0xC367CD, - 0xDCE809, - 0x2A8359, - 0xC4768B, - 0x961CA6, - 0xDDAF44, - 0xD15719, - 0x053EA5, - 0xFF0705, - 0x3F7E33, - 0xE832C2, - 0xDE4F98, - 0x327DBB, - 0xC33D26, - 0xEF6B1E, - 0x5EF89F, - 0x3A1F35, - 0xCAF27F, - 0x1D87F1, - 0x21907C, - 0x7C246A, - 0xFA6ED5, - 0x772D30, - 0x433B15, - 0xC614B5, - 0x9D19C3, - 0xC2C4AD, - 0x414D2C, - 0x5D000C, - 0x467D86, - 0x2D71E3, - 0x9AC69B, - 0x006233, - 0x7CD2B4, - 0x97A7B4, - 0xD55537, - 0xF63ED7, - 0x1810A3, - 0xFC764D, - 0x2A9D64, - 0xABD770, - 0xF87C63, - 0x57B07A, - 0xE71517, - 0x5649C0, - 0xD9D63B, - 0x3884A7, - 0xCB2324, - 0x778AD6, - 0x23545A, - 0xB91F00, - 0x1B0AF1, - 0xDFCE19, - 0xFF319F, - 0x6A1E66, - 0x615799, - 0x47FBAC, - 0xD87F7E, - 0xB76522, - 0x89E832, - 0x60BFE6, - 0xCDC4EF, - 0x09366C, - 0xD43F5D, - 0xD7DE16, - 0xDE3B58, - 0x929BDE, - 0x2822D2, - 0xE88628, - 0x4D58E2, - 0x32CAC6, - 0x16E308, - 0xCB7DE0, - 0x50C017, - 0xA71DF3, - 0x5BE018, - 0x34132E, - 0x621283, - 0x014883, - 0x5B8EF5, - 0x7FB0AD, - 0xF2E91E, - 0x434A48, - 0xD36710, - 0xD8DDAA, - 0x425FAE, - 0xCE616A, - 0xA4280A, - 0xB499D3, - 0xF2A606, - 0x7F775C, - 0x83C2A3, - 0x883C61, - 0x78738A, - 0x5A8CAF, - 0xBDD76F, - 0x63A62D, - 0xCBBFF4, - 0xEF818D, - 0x67C126, - 0x45CA55, - 0x36D9CA, - 0xD2A828, - 0x8D61C2, - 0x77C912, - 0x142604, - 0x9B4612, - 0xC459C4, - 0x44C5C8, - 0x91B24D, - 0xF31700, - 0xAD43D4, - 0xE54929, - 0x10D5FD, - 0xFCBE00, - 0xCC941E, - 0xEECE70, - 0xF53E13, - 0x80F1EC, - 0xC3E7B3, - 0x28F8C7, - 0x940593, - 0x3E71C1, - 0xB3092E, - 0xF3450B, - 0x9C1288, - 0x7B20AB, - 0x9FB52E, - 0xC29247, - 0x2F327B, - 0x6D550C, - 0x90A772, - 0x1FE76B, - 0x96CB31, - 0x4A1679, - 0xE27941, - 0x89DFF4, - 0x9794E8, - 0x84E6E2, - 0x973199, - 0x6BED88, - 0x365F5F, - 0x0EFDBB, - 0xB49A48, - 0x6CA467, - 0x427271, - 0x325D8D, - 0xB8159F, - 0x09E5BC, - 0x25318D, - 0x3974F7, - 0x1C0530, - 0x010C0D, - 0x68084B, - 0x58EE2C, - 0x90AA47, - 0x02E774, - 0x24D6BD, - 0xA67DF7, - 0x72486E, - 0xEF169F, - 0xA6948E, - 0xF691B4, - 0x5153D1, - 0xF20ACF, - 0x339820, - 0x7E4BF5, - 0x6863B2, - 0x5F3EDD, - 0x035D40, - 0x7F8985, - 0x295255, - 0xC06437, - 0x10D86D, - 0x324832, - 0x754C5B, - 0xD4714E, - 0x6E5445, - 0xC1090B, - 0x69F52A, - 0xD56614, - 0x9D0727, - 0x50045D, - 0xDB3BB4, - 0xC576EA, - 0x17F987, - 0x7D6B49, - 0xBA271D, - 0x296996, - 0xACCCC6, - 0x5414AD, - 0x6AE290, - 0x89D988, - 0x50722C, - 0xBEA404, - 0x940777, - 0x7030F3, - 0x27FC00, - 0xA871EA, - 0x49C266, - 0x3DE064, - 0x83DD97, - 0x973FA3, - 0xFD9443, - 0x8C860D, - 0xDE4131, - 0x9D3992, - 0x8C70DD, - 0xE7B717, - 0x3BDF08, - 0x2B3715, - 0xA0805C, - 0x93805A, - 0x921110, - 0xD8E80F, - 0xAF806C, - 0x4BFFDB, - 0x0F9038, - 0x761859, - 0x15A562, - 0xBBCB61, - 0xB989C7, - 0xBD4010, - 0x04F2D2, - 0x277549, - 0xF6B6EB, - 0xBB22DB, - 0xAA140A, - 0x2F2689, - 0x768364, - 0x333B09, - 0x1A940E, - 0xAA3A51, - 0xC2A31D, - 0xAEEDAF, - 0x12265C, - 0x4DC26D, - 0x9C7A2D, - 0x9756C0, - 0x833F03, - 0xF6F009, - 0x8C402B, - 0x99316D, - 0x07B439, - 0x15200C, - 0x5BC3D8, - 0xC492F5, - 0x4BADC6, - 0xA5CA4E, - 0xCD37A7, - 0x36A9E6, - 0x9492AB, - 0x6842DD, - 0xDE6319, - 0xEF8C76, - 0x528B68, - 0x37DBFC, - 0xABA1AE, - 0x3115DF, - 0xA1AE00, - 0xDAFB0C, - 0x664D64, - 0xB705ED, - 0x306529, - 0xBF5657, - 0x3AFF47, - 0xB9F96A, - 0xF3BE75, - 0xDF9328, - 0x3080AB, - 0xF68C66, - 0x15CB04, - 0x0622FA, - 0x1DE4D9, - 0xA4B33D, - 0x8F1B57, - 0x09CD36, - 0xE9424E, - 0xA4BE13, - 0xB52333, - 0x1AAAF0, - 0xA8654F, - 0xA5C1D2, - 0x0F3F0B, - 0xCD785B, - 0x76F923, - 0x048B7B, - 0x721789, - 0x53A6C6, - 0xE26E6F, - 0x00EBEF, - 0x584A9B, - 0xB7DAC4, - 0xBA66AA, - 0xCFCF76, - 0x1D02D1, - 0x2DF1B1, - 0xC1998C, - 0x77ADC3, - 0xDA4886, - 0xA05DF7, - 0xF480C6, - 0x2FF0AC, - 0x9AECDD, - 0xBC5C3F, - 0x6DDED0, - 0x1FC790, - 0xB6DB2A, - 0x3A25A3, - 0x9AAF00, - 0x9353AD, - 0x0457B6, - 0xB42D29, - 0x7E804B, - 0xA707DA, - 0x0EAA76, - 0xA1597B, - 0x2A1216, - 0x2DB7DC, - 0xFDE5FA, - 0xFEDB89, - 0xFDBE89, - 0x6C76E4, - 0xFCA906, - 0x70803E, - 0x156E85, - 0xFF87FD, - 0x073E28, - 0x336761, - 0x86182A, - 0xEABD4D, - 0xAFE7B3, - 0x6E6D8F, - 0x396795, - 0x5BBF31, - 0x48D784, - 0x16DF30, - 0x432DC7, - 0x356125, - 0xCE70C9, - 0xB8CB30, - 0xFD6CBF, - 0xA200A4, - 0xE46C05, - 0xA0DD5A, - 0x476F21, - 0xD21262, - 0x845CB9, - 0x496170, - 0xE0566B, - 0x015299, - 0x375550, - 0xB7D51E, - 0xC4F133, - 0x5F6E13, - 0xE4305D, - 0xA92E85, - 0xC3B21D, - 0x3632A1, - 0xA4B708, - 0xD4B1EA, - 0x21F716, - 0xE4698F, - 0x77FF27, - 0x80030C, - 0x2D408D, - 0xA0CD4F, - 0x99A520, - 0xD3A2B3, - 0x0A5D2F, - 0x42F9B4, - 0xCBDA11, - 0xD0BE7D, - 0xC1DB9B, - 0xBD17AB, - 0x81A2CA, - 0x5C6A08, - 0x17552E, - 0x550027, - 0xF0147F, - 0x8607E1, - 0x640B14, - 0x8D4196, - 0xDEBE87, - 0x2AFDDA, - 0xB6256B, - 0x34897B, - 0xFEF305, - 0x9EBFB9, - 0x4F6A68, - 0xA82A4A, - 0x5AC44F, - 0xBCF82D, - 0x985AD7, - 0x95C7F4, - 0x8D4D0D, - 0xA63A20, - 0x5F57A4, - 0xB13F14, - 0x953880, - 0x0120CC, - 0x86DD71, - 0xB6DEC9, - 0xF560BF, - 0x11654D, - 0x6B0701, - 0xACB08C, - 0xD0C0B2, - 0x485551, - 0x0EFB1E, - 0xC37295, - 0x3B06A3, - 0x3540C0, - 0x7BDC06, - 0xCC45E0, - 0xFA294E, - 0xC8CAD6, - 0x41F3E8, - 0xDE647C, - 0xD8649B, - 0x31BED9, - 0xC397A4, - 0xD45877, - 0xC5E369, - 0x13DAF0, - 0x3C3ABA, - 0x461846, - 0x5F7555, - 0xF5BDD2, - 0xC6926E, - 0x5D2EAC, - 0xED440E, - 0x423E1C, - 0x87C461, - 0xE9FD29, - 0xF3D6E7, - 0xCA7C22, - 0x35916F, - 0xC5E008, - 0x8DD7FF, - 0xE26A6E, - 0xC6FDB0, - 0xC10893, - 0x745D7C, - 0xB2AD6B, - 0x9D6ECD, - 0x7B723E, - 0x6A11C6, - 0xA9CFF7, - 0xDF7329, - 0xBAC9B5, - 0x5100B7, - 0x0DB2E2, - 0x24BA74, - 0x607DE5, - 0x8AD874, - 0x2C150D, - 0x0C1881, - 0x94667E, - 0x162901, - 0x767A9F, - 0xBEFDFD, - 0xEF4556, - 0x367ED9, - 0x13D9EC, - 0xB9BA8B, - 0xFC97C4, - 0x27A831, - 0xC36EF1, - 0x36C594, - 0x56A8D8, - 0xB5A8B4, - 0x0ECCCF, - 0x2D8912, - 0x34576F, - 0x89562C, - 0xE3CE99, - 0xB920D6, - 0xAA5E6B, - 0x9C2A3E, - 0xCC5F11, - 0x4A0BFD, - 0xFBF4E1, - 0x6D3B8E, - 0x2C86E2, - 0x84D4E9, - 0xA9B4FC, - 0xD1EEEF, - 0xC9352E, - 0x61392F, - 0x442138, - 0xC8D91B, - 0x0AFC81, - 0x6A4AFB, - 0xD81C2F, - 0x84B453, - 0x8C994E, - 0xCC2254, - 0xDC552A, - 0xD6C6C0, - 0x96190B, - 0xB8701A, - 0x649569, - 0x605A26, - 0xEE523F, - 0x0F117F, - 0x11B5F4, - 0xF5CBFC, - 0x2DBC34, - 0xEEBC34, - 0xCC5DE8, - 0x605EDD, - 0x9B8E67, - 0xEF3392, - 0xB817C9, - 0x9B5861, - 0xBC57E1, - 0xC68351, - 0x103ED8, - 0x4871DD, - 0xDD1C2D, - 0xA118AF, - 0x462C21, - 0xD7F359, - 0x987AD9, - 0xC0549E, - 0xFA864F, - 0xFC0656, - 0xAE79E5, - 0x362289, - 0x22AD38, - 0xDC9367, - 0xAAE855, - 0x382682, - 0x9BE7CA, - 0xA40D51, - 0xB13399, - 0x0ED7A9, - 0x480569, - 0xF0B265, - 0xA7887F, - 0x974C88, - 0x36D1F9, - 0xB39221, - 0x4A827B, - 0x21CF98, - 0xDC9F40, - 0x5547DC, - 0x3A74E1, - 0x42EB67, - 0xDF9DFE, - 0x5FD45E, - 0xA4677B, - 0x7AACBA, - 0xA2F655, - 0x23882B, - 0x55BA41, - 0x086E59, - 0x862A21, - 0x834739, - 0xE6E389, - 0xD49EE5, - 0x40FB49, - 0xE956FF, - 0xCA0F1C, - 0x8A59C5, - 0x2BFA94, - 0xC5C1D3, - 0xCFC50F, - 0xAE5ADB, - 0x86C547, - 0x624385, - 0x3B8621, - 0x94792C, - 0x876110, - 0x7B4C2A, - 0x1A2C80, - 0x12BF43, - 0x902688, - 0x893C78, - 0xE4C4A8, - 0x7BDBE5, - 0xC23AC4, - 0xEAF426, - 0x8A67F7, - 0xBF920D, - 0x2BA365, - 0xB1933D, - 0x0B7CBD, - 0xDC51A4, - 0x63DD27, - 0xDDE169, - 0x19949A, - 0x9529A8, - 0x28CE68, - 0xB4ED09, - 0x209F44, - 0xCA984E, - 0x638270, - 0x237C7E, - 0x32B90F, - 0x8EF5A7, - 0xE75614, - 0x08F121, - 0x2A9DB5, - 0x4D7E6F, - 0x5119A5, - 0xABF9B5, - 0xD6DF82, - 0x61DD96, - 0x023616, - 0x9F3AC4, - 0xA1A283, - 0x6DED72, - 0x7A8D39, - 0xA9B882, - 0x5C326B, - 0x5B2746, - 0xED3400, - 0x7700D2, - 0x55F4FC, - 0x4D5901, - 0x8071E0, -#endif -}; - -static const double PIo2[] = { - 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ - 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ - 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ - 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ - 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ - 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ - 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ - 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ -}; - -int __rem_pio2_large(double* x, double* y, int e0, int nx, int prec) -{ - int32_t jz, jx, jv, jp, jk, carry, n, iq[20], i, j, k, m, q0, ih; - double z, fw, f[20], fq[20], q[20]; - - /* initialize jk*/ - jk = init_jk[prec]; - jp = jk; - - /* determine jx,jv,q0, note that 3>q0 */ - jx = nx - 1; - jv = (e0 - 3) / 24; - if(jv < 0) - jv = 0; - q0 = e0 - 24 * (jv + 1); - - /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ - j = jv - jx; - m = jx + jk; - for(i = 0; i <= m; i++, j++) - f[i] = j < 0 ? 0.0 : (double)ipio2[j]; - - /* compute q[0],q[1],...q[jk] */ - for(i = 0; i <= jk; i++) - { - for(j = 0, fw = 0.0; j <= jx; j++) - fw += x[j] * f[jx + i - j]; - q[i] = fw; - } - - jz = jk; -recompute: - /* distill q[] into iq[] reversingly */ - for(i = 0, j = jz, z = q[jz]; j > 0; i++, j--) - { - fw = (double)(int32_t)(0x1p-24 * z); - iq[i] = (int32_t)(z - 0x1p24 * fw); - z = q[j - 1] + fw; - } - - /* compute n */ - z = scalbn(z, q0); /* actual value of z */ - z -= 8.0 * floor(z * 0.125); /* trim off integer >= 8 */ - n = (int32_t)z; - z -= (double)n; - ih = 0; - if(q0 > 0) - { /* need iq[jz-1] to determine n */ - i = iq[jz - 1] >> (24 - q0); - n += i; - iq[jz - 1] -= i << (24 - q0); - ih = iq[jz - 1] >> (23 - q0); - } - else if(q0 == 0) - ih = iq[jz - 1] >> 23; - else if(z >= 0.5) - ih = 2; - - if(ih > 0) - { /* q > 0.5 */ - n += 1; - carry = 0; - for(i = 0; i < jz; i++) - { /* compute 1-q */ - j = iq[i]; - if(carry == 0) - { - if(j != 0) - { - carry = 1; - iq[i] = 0x1000000 - j; - } - } - else - iq[i] = 0xffffff - j; - } - if(q0 > 0) - { /* rare case: chance is 1 in 12 */ - switch(q0) - { - case 1: - iq[jz - 1] &= 0x7fffff; - break; - case 2: - iq[jz - 1] &= 0x3fffff; - break; - } - } - if(ih == 2) - { - z = 1.0 - z; - if(carry != 0) - z -= scalbn(1.0, q0); - } - } - - /* check if recomputation is needed */ - if(z == 0.0) - { - j = 0; - for(i = jz - 1; i >= jk; i--) - j |= iq[i]; - if(j == 0) - { /* need recomputation */ - for(k = 1; iq[jk - k] == 0; k++) - ; /* k = no. of terms needed */ - - for(i = jz + 1; i <= jz + k; i++) - { /* add q[jz+1] to q[jz+k] */ - f[jx + i] = (double)ipio2[jv + i]; - for(j = 0, fw = 0.0; j <= jx; j++) - fw += x[j] * f[jx + i - j]; - q[i] = fw; - } - jz += k; - goto recompute; - } - } - - /* chop off zero terms */ - if(z == 0.0) - { - jz -= 1; - q0 -= 24; - while(iq[jz] == 0) - { - jz--; - q0 -= 24; - } - } - else - { /* break z into 24-bit if necessary */ - z = scalbn(z, -q0); - if(z >= 0x1p24) - { - fw = (double)(int32_t)(0x1p-24 * z); - iq[jz] = (int32_t)(z - 0x1p24 * fw); - jz += 1; - q0 += 24; - iq[jz] = (int32_t)fw; - } - else - iq[jz] = (int32_t)z; - } - - /* convert integer "bit" chunk to floating-point value */ - fw = scalbn(1.0, q0); - for(i = jz; i >= 0; i--) - { - q[i] = fw * (double)iq[i]; - fw *= 0x1p-24; - } - - /* compute PIo2[0,...,jp]*q[jz,...,0] */ - for(i = jz; i >= 0; i--) - { - for(fw = 0.0, k = 0; k <= jp && k <= jz - i; k++) - fw += PIo2[k] * q[i + k]; - fq[jz - i] = fw; - } - - /* compress fq[] into y[] */ - switch(prec) - { - case 0: - fw = 0.0; - for(i = jz; i >= 0; i--) - fw += fq[i]; - y[0] = ih == 0 ? fw : -fw; - break; - case 1: - case 2: - fw = 0.0; - for(i = jz; i >= 0; i--) - fw += fq[i]; - // TODO: drop excess precision here once double_t is used - fw = (double)fw; - y[0] = ih == 0 ? fw : -fw; - fw = fq[0] - fw; - for(i = 1; i <= jz; i++) - fw += fq[i]; - y[1] = ih == 0 ? fw : -fw; - break; - case 3: /* painful */ - for(i = jz; i > 0; i--) - { - fw = fq[i - 1] + fq[i]; - fq[i] += fq[i - 1] - fw; - fq[i - 1] = fw; - } - for(i = jz; i > 1; i--) - { - fw = fq[i - 1] + fq[i]; - fq[i] += fq[i - 1] - fw; - fq[i - 1] = fw; - } - for(fw = 0.0, i = jz; i >= 2; i--) - fw += fq[i]; - if(ih == 0) - { - y[0] = fq[0]; - y[1] = fq[1]; - y[2] = fw; - } - else - { - y[0] = -fq[0]; - y[1] = -fq[1]; - y[2] = -fw; - } - } - return n & 7; -} diff --git a/src/libc-shim/src/__rem_pio2f.c b/src/libc-shim/src/__rem_pio2f.c deleted file mode 100644 index 6917f1db..00000000 --- a/src/libc-shim/src/__rem_pio2f.c +++ /dev/null @@ -1,97 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2f.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Debugged and optimized by Bruce D. Evans. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* __rem_pio2f(x,y) - * - * return the remainder of x rem pi/2 in *y - * use double precision for everything except passing x - * use __rem_pio2_large() for large x - */ - -#include "libm.h" - -#if FLT_EVAL_METHOD == 0 || FLT_EVAL_METHOD == 1 - #define EPS DBL_EPSILON -#elif FLT_EVAL_METHOD == 2 - #define EPS LDBL_EPSILON -#endif - -/* - * invpio2: 53 bits of 2/pi - * pio2_1: first 25 bits of pi/2 - * pio2_1t: pi/2 - pio2_1 - */ -static const double - toint = 1.5 / EPS, - pio4 = 0x1.921fb6p-1, - invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ - pio2_1 = 1.57079631090164184570e+00, /* 0x3FF921FB, 0x50000000 */ - pio2_1t = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ - -int __rem_pio2f(float x, double* y) -{ - union - { - float f; - uint32_t i; - } u = { x }; - - double tx[1], ty[1]; - double_t fn; - uint32_t ix; - int n, sign, e0; - - ix = u.i & 0x7fffffff; - /* 25+53 bit pi is good enough for medium size */ - if(ix < 0x4dc90fdb) - { /* |x| ~< 2^28*(pi/2), medium size */ - /* Use a specialized rint() to get fn. */ - fn = (double_t)x * invpio2 + toint - toint; - n = (int32_t)fn; - *y = x - fn * pio2_1 - fn * pio2_1t; - /* Matters with directed rounding. */ - if(predict_false(*y < -pio4)) - { - n--; - fn--; - *y = x - fn * pio2_1 - fn * pio2_1t; - } - else if(predict_false(*y > pio4)) - { - n++; - fn++; - *y = x - fn * pio2_1 - fn * pio2_1t; - } - return n; - } - if(ix >= 0x7f800000) - { /* x is inf or NaN */ - *y = x - x; - return 0; - } - /* scale x into [2^23, 2^24-1] */ - sign = u.i >> 31; - e0 = (ix >> 23) - (0x7f + 23); /* e0 = ilogb(|x|)-23, positive */ - u.i = ix - (e0 << 23); - tx[0] = u.f; - n = __rem_pio2_large(tx, ty, e0, 1, 0); - if(sign) - { - *y = -ty[0]; - return -n; - } - *y = ty[0]; - return n; -} diff --git a/src/libc-shim/src/acos.c b/src/libc-shim/src/acos.c deleted file mode 100644 index 9d248992..00000000 --- a/src/libc-shim/src/acos.c +++ /dev/null @@ -1,105 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/e_acos.c */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunSoft, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ -/* acos(x) - * Method : - * acos(x) = pi/2 - asin(x) - * acos(-x) = pi/2 + asin(x) - * For |x|<=0.5 - * acos(x) = pi/2 - (x + x*x^2*R(x^2)) (see asin.c) - * For x>0.5 - * acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2))) - * = 2asin(sqrt((1-x)/2)) - * = 2s + 2s*z*R(z) ...z=(1-x)/2, s=sqrt(z) - * = 2f + (2c + 2s*z*R(z)) - * where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term - * for f so that f+c ~ sqrt(z). - * For x<-0.5 - * acos(x) = pi - 2asin(sqrt((1-|x|)/2)) - * = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z) - * - * Special cases: - * if x is NaN, return x itself; - * if |x|>1, return NaN with invalid signal. - * - * Function needed: sqrt - */ - -#include "libm.h" - -static const double - pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */ - pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */ - pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */ - pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */ - pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */ - pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */ - pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */ - pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */ - qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */ - qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */ - qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */ - qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ - -static double R(double z) -{ - double_t p, q; - p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5))))); - q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4))); - return p / q; -} - -double acos(double x) -{ - double z, w, s, c, df; - uint32_t hx, ix; - - GET_HIGH_WORD(hx, x); - ix = hx & 0x7fffffff; - /* |x| >= 1 or nan */ - if(ix >= 0x3ff00000) - { - uint32_t lx; - - GET_LOW_WORD(lx, x); - if((ix - 0x3ff00000 | lx) == 0) - { - /* acos(1)=0, acos(-1)=pi */ - if(hx >> 31) - return 2 * pio2_hi + 0x1p-120f; - return 0; - } - return 0 / (x - x); - } - /* |x| < 0.5 */ - if(ix < 0x3fe00000) - { - if(ix <= 0x3c600000) /* |x| < 2**-57 */ - return pio2_hi + 0x1p-120f; - return pio2_hi - (x - (pio2_lo - x * R(x * x))); - } - /* x < -0.5 */ - if(hx >> 31) - { - z = (1.0 + x) * 0.5; - s = sqrt(z); - w = R(z) * s - pio2_lo; - return 2 * (pio2_hi - (s + w)); - } - /* x > 0.5 */ - z = (1.0 - x) * 0.5; - s = sqrt(z); - df = s; - SET_LOW_WORD(df, 0); - c = (z - df * df) / (s + df); - w = R(z) * s + c; - return 2 * (df + w); -} diff --git a/src/libc-shim/src/ceil.c b/src/libc-shim/src/ceil.c deleted file mode 100644 index b33d1966..00000000 --- a/src/libc-shim/src/ceil.c +++ /dev/null @@ -1,37 +0,0 @@ -#include "libm.h" - -#if FLT_EVAL_METHOD == 0 || FLT_EVAL_METHOD == 1 - #define EPS DBL_EPSILON -#elif FLT_EVAL_METHOD == 2 - #define EPS LDBL_EPSILON -#endif -static const double_t toint = 1 / EPS; - -double ceil(double x) -{ - union - { - double f; - uint64_t i; - } u = { x }; - - int e = u.i >> 52 & 0x7ff; - double_t y; - - if(e >= 0x3ff + 52 || x == 0) - return x; - /* y = int(x) - x, where int(x) is an integer neighbor of x */ - if(u.i >> 63) - y = x - toint + toint - x; - else - y = x + toint - toint - x; - /* special case because of non-nearest rounding modes */ - if(e <= 0x3ff - 1) - { - FORCE_EVAL(y); - return u.i >> 63 ? -0.0 : 1; - } - if(y < 0) - return x + y + 1; - return x + y; -} diff --git a/src/libc-shim/src/cosf.c b/src/libc-shim/src/cosf.c deleted file mode 100644 index e2a07933..00000000 --- a/src/libc-shim/src/cosf.c +++ /dev/null @@ -1,88 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_cosf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Optimized by Bruce D. Evans. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -#include "libm.h" - -/* Small multiples of pi/2 rounded to double precision. */ -static const double - c1pio2 = 1 * M_PI_2, /* 0x3FF921FB, 0x54442D18 */ - c2pio2 = 2 * M_PI_2, /* 0x400921FB, 0x54442D18 */ - c3pio2 = 3 * M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ - c4pio2 = 4 * M_PI_2; /* 0x401921FB, 0x54442D18 */ - -float cosf(float x) -{ - double y; - uint32_t ix; - unsigned n, sign; - - GET_FLOAT_WORD(ix, x); - sign = ix >> 31; - ix &= 0x7fffffff; - - if(ix <= 0x3f490fda) - { /* |x| ~<= pi/4 */ - if(ix < 0x39800000) - { /* |x| < 2**-12 */ - /* raise inexact if x != 0 */ - FORCE_EVAL(x + 0x1p120f); - return 1.0f; - } - return __cosdf(x); - } - if(ix <= 0x407b53d1) - { /* |x| ~<= 5*pi/4 */ - if(ix > 0x4016cbe3) /* |x| ~> 3*pi/4 */ - return -__cosdf(sign ? x + c2pio2 : x - c2pio2); - else - { - if(sign) - return __sindf(x + c1pio2); - else - return __sindf(c1pio2 - x); - } - } - if(ix <= 0x40e231d5) - { /* |x| ~<= 9*pi/4 */ - if(ix > 0x40afeddf) /* |x| ~> 7*pi/4 */ - return __cosdf(sign ? x + c4pio2 : x - c4pio2); - else - { - if(sign) - return __sindf(-x - c3pio2); - else - return __sindf(x - c3pio2); - } - } - - /* cos(Inf or NaN) is NaN */ - if(ix >= 0x7f800000) - return x - x; - - /* general argument reduction needed */ - n = __rem_pio2f(x, &y); - switch(n & 3) - { - case 0: - return __cosdf(y); - case 1: - return __sindf(-y); - case 2: - return -__cosdf(y); - default: - return __sindf(y); - } -} diff --git a/src/libc-shim/src/fabs.c b/src/libc-shim/src/fabs.c deleted file mode 100644 index a051b0a1..00000000 --- a/src/libc-shim/src/fabs.c +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include - -double fabs(double x) -{ - union - { - double f; - uint64_t i; - } u = { x }; - - u.i &= -1ULL / 2; - return u.f; -} diff --git a/src/libc-shim/src/fabsf.c b/src/libc-shim/src/fabsf.c deleted file mode 100644 index b9f0d4fd..00000000 --- a/src/libc-shim/src/fabsf.c +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include - -float fabsf(float x) -{ - union - { - float f; - uint32_t i; - } u = { x }; - - u.i &= -1U / 2; - return u.f; -} diff --git a/src/libc-shim/src/floor.c b/src/libc-shim/src/floor.c deleted file mode 100644 index 8a5f7273..00000000 --- a/src/libc-shim/src/floor.c +++ /dev/null @@ -1,37 +0,0 @@ -#include "libm.h" - -#if FLT_EVAL_METHOD == 0 || FLT_EVAL_METHOD == 1 - #define EPS DBL_EPSILON -#elif FLT_EVAL_METHOD == 2 - #define EPS LDBL_EPSILON -#endif -static const double_t toint = 1 / EPS; - -double floor(double x) -{ - union - { - double f; - uint64_t i; - } u = { x }; - - int e = u.i >> 52 & 0x7ff; - double_t y; - - if(e >= 0x3ff + 52 || x == 0) - return x; - /* y = int(x) - x, where int(x) is an integer neighbor of x */ - if(u.i >> 63) - y = x - toint + toint - x; - else - y = x + toint - toint - x; - /* special case because of non-nearest rounding modes */ - if(e <= 0x3ff - 1) - { - FORCE_EVAL(y); - return u.i >> 63 ? -1 : 0; - } - if(y > 0) - return x + y - 1; - return x + y; -} diff --git a/src/libc-shim/src/fmod.c b/src/libc-shim/src/fmod.c deleted file mode 100644 index 90204064..00000000 --- a/src/libc-shim/src/fmod.c +++ /dev/null @@ -1,89 +0,0 @@ -#include -#include - -double fmod(double x, double y) -{ - union - { - double f; - uint64_t i; - } ux = { x }, uy = { y }; - - int ex = ux.i >> 52 & 0x7ff; - int ey = uy.i >> 52 & 0x7ff; - int sx = ux.i >> 63; - uint64_t i; - - /* in the followings uxi should be ux.i, but then gcc wrongly adds */ - /* float load/store to inner loops ruining performance and code size */ - uint64_t uxi = ux.i; - - if(uy.i << 1 == 0 || isnan(y) || ex == 0x7ff) - return (x * y) / (x * y); - if(uxi << 1 <= uy.i << 1) - { - if(uxi << 1 == uy.i << 1) - return 0 * x; - return x; - } - - /* normalize x and y */ - if(!ex) - { - for(i = uxi << 12; i >> 63 == 0; ex--, i <<= 1) - ; - uxi <<= -ex + 1; - } - else - { - uxi &= -1ULL >> 12; - uxi |= 1ULL << 52; - } - if(!ey) - { - for(i = uy.i << 12; i >> 63 == 0; ey--, i <<= 1) - ; - uy.i <<= -ey + 1; - } - else - { - uy.i &= -1ULL >> 12; - uy.i |= 1ULL << 52; - } - - /* x mod y */ - for(; ex > ey; ex--) - { - i = uxi - uy.i; - if(i >> 63 == 0) - { - if(i == 0) - return 0 * x; - uxi = i; - } - uxi <<= 1; - } - i = uxi - uy.i; - if(i >> 63 == 0) - { - if(i == 0) - return 0 * x; - uxi = i; - } - for(; uxi >> 52 == 0; uxi <<= 1, ex--) - ; - - /* scale result */ - if(ex > 0) - { - uxi -= 1ULL << 52; - uxi |= (uint64_t)ex << 52; - } - else - { - uxi >>= -ex + 1; - } - uxi |= (uint64_t)sx << 63; - ux.i = uxi; - return ux.f; -} diff --git a/src/libc-shim/src/libm.h b/src/libc-shim/src/libm.h deleted file mode 100644 index 9edc4382..00000000 --- a/src/libc-shim/src/libm.h +++ /dev/null @@ -1,159 +0,0 @@ -#ifndef _LIBM_H -#define _LIBM_H - -#include -#include -#include - -#define WANT_ROUNDING 1 - -#if WANT_SNAN - #error SNaN is unsupported -#else - #define issignalingf_inline(x) 0 - #define issignaling_inline(x) 0 -#endif - -/* Helps static branch prediction so hot path can be better optimized. */ -#ifdef __GNUC__ - #define predict_true(x) __builtin_expect(!!(x), 1) - #define predict_false(x) __builtin_expect(x, 0) -#else - #define predict_true(x) (x) - #define predict_false(x) (x) -#endif - -static inline float eval_as_float(float x) -{ - float y = x; - return y; -} - -static inline double eval_as_double(double x) -{ - double y = x; - return y; -} - -/* fp_force_eval ensures that the input value is computed when that's - otherwise unused. To prevent the constant folding of the input - expression, an additional fp_barrier may be needed or a compilation - mode that does so (e.g. -frounding-math in gcc). Then it can be - used to evaluate an expression for its fenv side-effects only. */ - -#ifndef fp_force_evalf - #define fp_force_evalf fp_force_evalf - -static inline void fp_force_evalf(float x) -{ - volatile float y; - y = x; -} -#endif - -#ifndef fp_force_eval - #define fp_force_eval fp_force_eval - -static inline void fp_force_eval(double x) -{ - volatile double y; - y = x; -} -#endif - -#ifndef fp_force_evall - #define fp_force_evall fp_force_evall - -static inline void fp_force_evall(long double x) -{ - volatile long double y; - y = x; -} -#endif - -#define FORCE_EVAL(x) \ - do \ - { \ - if(sizeof(x) == sizeof(float)) \ - { \ - fp_force_evalf(x); \ - } \ - else if(sizeof(x) == sizeof(double)) \ - { \ - fp_force_eval(x); \ - } \ - else \ - { \ - fp_force_evall(x); \ - } \ - } while(0) - -#define asuint(f) ((union {float _f; uint32_t _i; }){ f })._i -#define asfloat(i) ((union {uint32_t _i; float _f; }){ i })._f -#define asuint64(f) ((union {double _f; uint64_t _i; }){ f })._i -#define asdouble(i) ((union {uint64_t _i; double _f; }){ i })._f - -#define EXTRACT_WORDS(hi, lo, d) \ - do \ - { \ - uint64_t __u = asuint64(d); \ - (hi) = __u >> 32; \ - (lo) = (uint32_t)__u; \ - } while(0) - -#define GET_HIGH_WORD(hi, d) \ - do \ - { \ - (hi) = asuint64(d) >> 32; \ - } while(0) - -#define GET_LOW_WORD(lo, d) \ - do \ - { \ - (lo) = (uint32_t)asuint64(d); \ - } while(0) - -#define INSERT_WORDS(d, hi, lo) \ - do \ - { \ - (d) = asdouble(((uint64_t)(hi) << 32) | (uint32_t)(lo)); \ - } while(0) - -#define SET_HIGH_WORD(d, hi) \ - INSERT_WORDS(d, hi, (uint32_t)asuint64(d)) - -#define SET_LOW_WORD(d, lo) \ - INSERT_WORDS(d, asuint64(d) >> 32, lo) - -#define GET_FLOAT_WORD(w, d) \ - do \ - { \ - (w) = asuint(d); \ - } while(0) - -#define SET_FLOAT_WORD(d, w) \ - do \ - { \ - (d) = asfloat(w); \ - } while(0) - -int __rem_pio2_large(double*, double*, int, int, int); - -int __rem_pio2(double, double*); -double __sin(double, double, int); -double __cos(double, double); - -int __rem_pio2f(float, double*); -float __sindf(double); -float __cosdf(double); - -float __math_xflowf(uint32_t, float); -float __math_uflowf(uint32_t); -float __math_oflowf(uint32_t); -float __math_invalidf(float); -double __math_xflow(uint32_t, double); -double __math_uflow(uint32_t); -double __math_oflow(uint32_t); -double __math_invalid(double); - -#endif // _LIBM_H diff --git a/src/libc-shim/src/pow.c b/src/libc-shim/src/pow.c deleted file mode 100644 index 4e682fcf..00000000 --- a/src/libc-shim/src/pow.c +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Double-precision x^y function. - * - * Copyright (c) 2018, Arm Limited. - * SPDX-License-Identifier: MIT - */ - -#include "exp_data.h" -#include "libm.h" -#include "pow_data.h" -#include -#include - -/* -Worst-case error: 0.54 ULP (~= ulperr_exp + 1024*Ln2*relerr_log*2^53) -relerr_log: 1.3 * 2^-68 (Relative error of log, 1.5 * 2^-68 without fma) -ulperr_exp: 0.509 ULP (ULP error of exp, 0.511 ULP without fma) -*/ - -#define T __pow_log_data.tab -#define A __pow_log_data.poly -#define Ln2hi __pow_log_data.ln2hi -#define Ln2lo __pow_log_data.ln2lo -#define N (1 << POW_LOG_TABLE_BITS) -#define OFF 0x3fe6955500000000 - -/* Top 12 bits of a double (sign and exponent bits). */ -static inline uint32_t top12(double x) -{ - return asuint64(x) >> 52; -} - -/* Compute y+TAIL = log(x) where the rounded result is y and TAIL has about - additional 15 bits precision. IX is the bit representation of x, but - normalized in the subnormal range using the sign bit for the exponent. */ -static inline double_t log_inline(uint64_t ix, double_t* tail) -{ - /* double_t for better performance on targets with FLT_EVAL_METHOD==2. */ - double_t z, r, y, invc, logc, logctail, kd, hi, t1, t2, lo, lo1, lo2, p; - uint64_t iz, tmp; - int k, i; - - /* x = 2^k z; where z is in range [OFF,2*OFF) and exact. - The range is split into N subintervals. - The ith subinterval contains z and c is near its center. */ - tmp = ix - OFF; - i = (tmp >> (52 - POW_LOG_TABLE_BITS)) % N; - k = (int64_t)tmp >> 52; /* arithmetic shift */ - iz = ix - (tmp & 0xfffULL << 52); - z = asdouble(iz); - kd = (double_t)k; - - /* log(x) = k*Ln2 + log(c) + log1p(z/c-1). */ - invc = T[i].invc; - logc = T[i].logc; - logctail = T[i].logctail; - - /* Note: 1/c is j/N or j/N/2 where j is an integer in [N,2N) and - |z/c - 1| < 1/N, so r = z/c - 1 is exactly representible. */ -#if __FP_FAST_FMA - r = __builtin_fma(z, invc, -1.0); -#else - /* Split z such that rhi, rlo and rhi*rhi are exact and |rlo| <= |r|. */ - double_t zhi = asdouble((iz + (1ULL << 31)) & (-1ULL << 32)); - double_t zlo = z - zhi; - double_t rhi = zhi * invc - 1.0; - double_t rlo = zlo * invc; - r = rhi + rlo; -#endif - - /* k*Ln2 + log(c) + r. */ - t1 = kd * Ln2hi + logc; - t2 = t1 + r; - lo1 = kd * Ln2lo + logctail; - lo2 = t1 - t2 + r; - - /* Evaluation is optimized assuming superscalar pipelined execution. */ - double_t ar, ar2, ar3, lo3, lo4; - ar = A[0] * r; /* A[0] = -0.5. */ - ar2 = r * ar; - ar3 = r * ar2; - /* k*Ln2 + log(c) + r + A[0]*r*r. */ -#if __FP_FAST_FMA - hi = t2 + ar2; - lo3 = __builtin_fma(ar, r, -ar2); - lo4 = t2 - hi + ar2; -#else - double_t arhi = A[0] * rhi; - double_t arhi2 = rhi * arhi; - hi = t2 + arhi2; - lo3 = rlo * (ar + arhi); - lo4 = t2 - hi + arhi2; -#endif - /* p = log1p(r) - r - A[0]*r*r. */ - p = (ar3 * (A[1] + r * A[2] + ar2 * (A[3] + r * A[4] + ar2 * (A[5] + r * A[6])))); - lo = lo1 + lo2 + lo3 + lo4 + p; - y = hi + lo; - *tail = hi - y + lo; - return y; -} - -#undef N -#undef T -#define N (1 << EXP_TABLE_BITS) -#define InvLn2N __exp_data.invln2N -#define NegLn2hiN __exp_data.negln2hiN -#define NegLn2loN __exp_data.negln2loN -#define Shift __exp_data.shift -#define T __exp_data.tab -#define C2 __exp_data.poly[5 - EXP_POLY_ORDER] -#define C3 __exp_data.poly[6 - EXP_POLY_ORDER] -#define C4 __exp_data.poly[7 - EXP_POLY_ORDER] -#define C5 __exp_data.poly[8 - EXP_POLY_ORDER] -#define C6 __exp_data.poly[9 - EXP_POLY_ORDER] - -/* Handle cases that may overflow or underflow when computing the result that - is scale*(1+TMP) without intermediate rounding. The bit representation of - scale is in SBITS, however it has a computed exponent that may have - overflown into the sign bit so that needs to be adjusted before using it as - a double. (int32_t)KI is the k used in the argument reduction and exponent - adjustment of scale, positive k here means the result may overflow and - negative k means the result may underflow. */ -static inline double specialcase(double_t tmp, uint64_t sbits, uint64_t ki) -{ - double_t scale, y; - - if((ki & 0x80000000) == 0) - { - /* k > 0, the exponent of scale might have overflowed by <= 460. */ - sbits -= 1009ull << 52; - scale = asdouble(sbits); - y = 0x1p1009 * (scale + scale * tmp); - return eval_as_double(y); - } - /* k < 0, need special care in the subnormal range. */ - sbits += 1022ull << 52; - /* Note: sbits is signed scale. */ - scale = asdouble(sbits); - y = scale + scale * tmp; - if(fabs(y) < 1.0) - { - /* Round y to the right precision before scaling it into the subnormal - range to avoid double rounding that can cause 0.5+E/2 ulp error where - E is the worst-case ulp error outside the subnormal range. So this - is only useful if the goal is better than 1 ulp worst-case error. */ - double_t hi, lo, one = 1.0; - if(y < 0.0) - one = -1.0; - lo = scale - y + scale * tmp; - hi = one + y; - lo = one - hi + y + lo; - y = eval_as_double(hi + lo) - one; - /* Fix the sign of 0. */ - if(y == 0.0) - y = asdouble(sbits & 0x8000000000000000); - /* The underflow exception needs to be signaled explicitly. */ - // NOTE(orca): removing special fp functions - // fp_force_eval(fp_barrier(0x1p-1022) * 0x1p-1022); - } - y = 0x1p-1022 * y; - return eval_as_double(y); -} - -#define SIGN_BIAS (0x800 << EXP_TABLE_BITS) - -/* Computes sign*exp(x+xtail) where |xtail| < 2^-8/N and |xtail| <= |x|. - The sign_bias argument is SIGN_BIAS or 0 and sets the sign to -1 or 1. */ -static inline double exp_inline(double_t x, double_t xtail, uint32_t sign_bias) -{ - uint32_t abstop; - uint64_t ki, idx, top, sbits; - /* double_t for better performance on targets with FLT_EVAL_METHOD==2. */ - double_t kd, z, r, r2, scale, tail, tmp; - - abstop = top12(x) & 0x7ff; - if(predict_false(abstop - top12(0x1p-54) >= top12(512.0) - top12(0x1p-54))) - { - if(abstop - top12(0x1p-54) >= 0x80000000) - { - /* Avoid spurious underflow for tiny x. */ - /* Note: 0 is common input. */ - double_t one = WANT_ROUNDING ? 1.0 + x : 1.0; - return sign_bias ? -one : one; - } - if(abstop >= top12(1024.0)) - { - /* Note: inf and nan are already handled. */ - if(asuint64(x) >> 63) - return __math_uflow(sign_bias); - else - return __math_oflow(sign_bias); - } - /* Large x is special cased below. */ - abstop = 0; - } - - /* exp(x) = 2^(k/N) * exp(r), with exp(r) in [2^(-1/2N),2^(1/2N)]. */ - /* x = ln2/N*k + r, with int k and r in [-ln2/2N, ln2/2N]. */ - z = InvLn2N * x; -#if TOINT_INTRINSICS - kd = roundtoint(z); - ki = converttoint(z); -#elif EXP_USE_TOINT_NARROW - /* z - kd is in [-0.5-2^-16, 0.5] in all rounding modes. */ - kd = eval_as_double(z + Shift); - ki = asuint64(kd) >> 16; - kd = (double_t)(int32_t)ki; -#else - /* z - kd is in [-1, 1] in non-nearest rounding modes. */ - kd = eval_as_double(z + Shift); - ki = asuint64(kd); - kd -= Shift; -#endif - r = x + kd * NegLn2hiN + kd * NegLn2loN; - /* The code assumes 2^-200 < |xtail| < 2^-8/N. */ - r += xtail; - /* 2^(k/N) ~= scale * (1 + tail). */ - idx = 2 * (ki % N); - top = (ki + sign_bias) << (52 - EXP_TABLE_BITS); - tail = asdouble(T[idx]); - /* This is only a valid scale when -1023*N < k < 1024*N. */ - sbits = T[idx + 1] + top; - /* exp(x) = 2^(k/N) * exp(r) ~= scale + scale * (tail + exp(r) - 1). */ - /* Evaluation is optimized assuming superscalar pipelined execution. */ - r2 = r * r; - /* Without fma the worst case error is 0.25/N ulp larger. */ - /* Worst case error is less than 0.5+1.11/N+(abs poly error * 2^53) ulp. */ - tmp = tail + r + r2 * (C2 + r * C3) + r2 * r2 * (C4 + r * C5); - if(predict_false(abstop == 0)) - return specialcase(tmp, sbits, ki); - scale = asdouble(sbits); - /* Note: tmp == 0 or |tmp| > 2^-200 and scale > 2^-739, so there - is no spurious underflow here even without fma. */ - return eval_as_double(scale + scale * tmp); -} - -/* Returns 0 if not int, 1 if odd int, 2 if even int. The argument is - the bit representation of a non-zero finite floating-point value. */ -static inline int checkint(uint64_t iy) -{ - int e = iy >> 52 & 0x7ff; - if(e < 0x3ff) - return 0; - if(e > 0x3ff + 52) - return 2; - if(iy & ((1ULL << (0x3ff + 52 - e)) - 1)) - return 0; - if(iy & (1ULL << (0x3ff + 52 - e))) - return 1; - return 2; -} - -/* Returns 1 if input is the bit representation of 0, infinity or nan. */ -static inline int zeroinfnan(uint64_t i) -{ - return 2 * i - 1 >= 2 * asuint64(INFINITY) - 1; -} - -double pow(double x, double y) -{ - uint32_t sign_bias = 0; - uint64_t ix, iy; - uint32_t topx, topy; - - ix = asuint64(x); - iy = asuint64(y); - topx = top12(x); - topy = top12(y); - if(predict_false(topx - 0x001 >= 0x7ff - 0x001 || (topy & 0x7ff) - 0x3be >= 0x43e - 0x3be)) - { - /* Note: if |y| > 1075 * ln2 * 2^53 ~= 0x1.749p62 then pow(x,y) = inf/0 - and if |y| < 2^-54 / 1075 ~= 0x1.e7b6p-65 then pow(x,y) = +-1. */ - /* Special cases: (x < 0x1p-126 or inf or nan) or - (|y| < 0x1p-65 or |y| >= 0x1p63 or nan). */ - if(predict_false(zeroinfnan(iy))) - { - if(2 * iy == 0) - return issignaling_inline(x) ? x + y : 1.0; - if(ix == asuint64(1.0)) - return issignaling_inline(y) ? x + y : 1.0; - if(2 * ix > 2 * asuint64(INFINITY) || 2 * iy > 2 * asuint64(INFINITY)) - return x + y; - if(2 * ix == 2 * asuint64(1.0)) - return 1.0; - if((2 * ix < 2 * asuint64(1.0)) == !(iy >> 63)) - return 0.0; /* |x|<1 && y==inf or |x|>1 && y==-inf. */ - return y * y; - } - if(predict_false(zeroinfnan(ix))) - { - double_t x2 = x * x; - if(ix >> 63 && checkint(iy) == 1) - x2 = -x2; - /* Without the barrier some versions of clang hoist the 1/x2 and - thus division by zero exception can be signaled spuriously. */ - // NOTE(orca): I hope my version of clang is not affected lol - // return iy >> 63 ? fp_barrier(1 / x2) : x2; - return iy >> 63 ? (1 / x2) : x2; - } - /* Here x and y are non-zero finite. */ - if(ix >> 63) - { - /* Finite x < 0. */ - int yint = checkint(iy); - if(yint == 0) - return __math_invalid(x); - if(yint == 1) - sign_bias = SIGN_BIAS; - ix &= 0x7fffffffffffffff; - topx &= 0x7ff; - } - if((topy & 0x7ff) - 0x3be >= 0x43e - 0x3be) - { - /* Note: sign_bias == 0 here because y is not odd. */ - if(ix == asuint64(1.0)) - return 1.0; - if((topy & 0x7ff) < 0x3be) - { - /* |y| < 2^-65, x^y ~= 1 + y*log(x). */ - if(WANT_ROUNDING) - return ix > asuint64(1.0) ? 1.0 + y : 1.0 - y; - else - return 1.0; - } - return (ix > asuint64(1.0)) == (topy < 0x800) ? __math_oflow(0) : __math_uflow(0); - } - if(topx == 0) - { - /* Normalize subnormal x so exponent becomes negative. */ - ix = asuint64(x * 0x1p52); - ix &= 0x7fffffffffffffff; - ix -= 52ULL << 52; - } - } - - double_t lo; - double_t hi = log_inline(ix, &lo); - double_t ehi, elo; -#if __FP_FAST_FMA - ehi = y * hi; - elo = y * lo + __builtin_fma(y, hi, -ehi); -#else - double_t yhi = asdouble(iy & -1ULL << 27); - double_t ylo = y - yhi; - double_t lhi = asdouble(asuint64(hi) & -1ULL << 27); - double_t llo = hi - lhi + lo; - ehi = yhi * lhi; - elo = ylo * lhi + y * llo; /* |elo| < |ehi| * 2^-25. */ -#endif - return exp_inline(ehi, elo, sign_bias); -} diff --git a/src/libc-shim/src/pow_data.h b/src/libc-shim/src/pow_data.h deleted file mode 100644 index 3c138945..00000000 --- a/src/libc-shim/src/pow_data.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2018, Arm Limited. - * SPDX-License-Identifier: MIT - */ -#ifndef _POW_DATA_H -#define _POW_DATA_H - -#include - -#define POW_LOG_TABLE_BITS 7 -#define POW_LOG_POLY_ORDER 8 - -extern const struct pow_log_data -{ - double ln2hi; - double ln2lo; - double poly[POW_LOG_POLY_ORDER - 1]; /* First coefficient is 1. */ - - /* Note: the pad field is unused, but allows slightly faster indexing. */ - struct - { - double invc, pad, logc, logctail; - } tab[1 << POW_LOG_TABLE_BITS]; -} __pow_log_data; - -#endif diff --git a/src/libc-shim/src/scalbn.c b/src/libc-shim/src/scalbn.c deleted file mode 100644 index 5b7d4d9d..00000000 --- a/src/libc-shim/src/scalbn.c +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include - -double scalbn(double x, int n) -{ - union - { - double f; - uint64_t i; - } u; - - double_t y = x; - - if(n > 1023) - { - y *= 0x1p1023; - n -= 1023; - if(n > 1023) - { - y *= 0x1p1023; - n -= 1023; - if(n > 1023) - n = 1023; - } - } - else if(n < -1022) - { - /* make sure final n < -53 to avoid double - rounding in the subnormal range */ - y *= 0x1p-1022 * 0x1p53; - n += 1022 - 53; - if(n < -1022) - { - y *= 0x1p-1022 * 0x1p53; - n += 1022 - 53; - if(n < -1022) - n = -1022; - } - } - u.i = (uint64_t)(0x3ff + n) << 52; - x = y * u.f; - return x; -} diff --git a/src/libc-shim/src/sinf.c b/src/libc-shim/src/sinf.c deleted file mode 100644 index 83d21cb3..00000000 --- a/src/libc-shim/src/sinf.c +++ /dev/null @@ -1,86 +0,0 @@ -/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ -/* - * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. - * Optimized by Bruce D. Evans. - */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -#include "libm.h" - -/* Small multiples of pi/2 rounded to double precision. */ -static const double - s1pio2 = 1 * M_PI_2, /* 0x3FF921FB, 0x54442D18 */ - s2pio2 = 2 * M_PI_2, /* 0x400921FB, 0x54442D18 */ - s3pio2 = 3 * M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ - s4pio2 = 4 * M_PI_2; /* 0x401921FB, 0x54442D18 */ - -float sinf(float x) -{ - double y; - uint32_t ix; - int n, sign; - - GET_FLOAT_WORD(ix, x); - sign = ix >> 31; - ix &= 0x7fffffff; - - if(ix <= 0x3f490fda) - { /* |x| ~<= pi/4 */ - if(ix < 0x39800000) - { /* |x| < 2**-12 */ - /* raise inexact if x!=0 and underflow if subnormal */ - FORCE_EVAL(ix < 0x00800000 ? x / 0x1p120f : x + 0x1p120f); - return x; - } - return __sindf(x); - } - if(ix <= 0x407b53d1) - { /* |x| ~<= 5*pi/4 */ - if(ix <= 0x4016cbe3) - { /* |x| ~<= 3pi/4 */ - if(sign) - return -__cosdf(x + s1pio2); - else - return __cosdf(x - s1pio2); - } - return __sindf(sign ? -(x + s2pio2) : -(x - s2pio2)); - } - if(ix <= 0x40e231d5) - { /* |x| ~<= 9*pi/4 */ - if(ix <= 0x40afeddf) - { /* |x| ~<= 7*pi/4 */ - if(sign) - return __cosdf(x + s3pio2); - else - return -__cosdf(x - s3pio2); - } - return __sindf(sign ? x + s4pio2 : x - s4pio2); - } - - /* sin(Inf or NaN) is NaN */ - if(ix >= 0x7f800000) - return x - x; - - /* general argument reduction needed */ - n = __rem_pio2f(x, &y); - switch(n & 3) - { - case 0: - return __sindf(y); - case 1: - return __cosdf(y); - case 2: - return __sindf(-y); - default: - return -__cosdf(y); - } -} diff --git a/src/libc-shim/src/sqrt_data.c b/src/libc-shim/src/sqrt_data.c deleted file mode 100644 index df0a86dc..00000000 --- a/src/libc-shim/src/sqrt_data.c +++ /dev/null @@ -1,131 +0,0 @@ -#include "sqrt_data.h" -const uint16_t __rsqrt_tab[128] = { - 0xb451, - 0xb2f0, - 0xb196, - 0xb044, - 0xaef9, - 0xadb6, - 0xac79, - 0xab43, - 0xaa14, - 0xa8eb, - 0xa7c8, - 0xa6aa, - 0xa592, - 0xa480, - 0xa373, - 0xa26b, - 0xa168, - 0xa06a, - 0x9f70, - 0x9e7b, - 0x9d8a, - 0x9c9d, - 0x9bb5, - 0x9ad1, - 0x99f0, - 0x9913, - 0x983a, - 0x9765, - 0x9693, - 0x95c4, - 0x94f8, - 0x9430, - 0x936b, - 0x92a9, - 0x91ea, - 0x912e, - 0x9075, - 0x8fbe, - 0x8f0a, - 0x8e59, - 0x8daa, - 0x8cfe, - 0x8c54, - 0x8bac, - 0x8b07, - 0x8a64, - 0x89c4, - 0x8925, - 0x8889, - 0x87ee, - 0x8756, - 0x86c0, - 0x862b, - 0x8599, - 0x8508, - 0x8479, - 0x83ec, - 0x8361, - 0x82d8, - 0x8250, - 0x81c9, - 0x8145, - 0x80c2, - 0x8040, - 0xff02, - 0xfd0e, - 0xfb25, - 0xf947, - 0xf773, - 0xf5aa, - 0xf3ea, - 0xf234, - 0xf087, - 0xeee3, - 0xed47, - 0xebb3, - 0xea27, - 0xe8a3, - 0xe727, - 0xe5b2, - 0xe443, - 0xe2dc, - 0xe17a, - 0xe020, - 0xdecb, - 0xdd7d, - 0xdc34, - 0xdaf1, - 0xd9b3, - 0xd87b, - 0xd748, - 0xd61a, - 0xd4f1, - 0xd3cd, - 0xd2ad, - 0xd192, - 0xd07b, - 0xcf69, - 0xce5b, - 0xcd51, - 0xcc4a, - 0xcb48, - 0xca4a, - 0xc94f, - 0xc858, - 0xc764, - 0xc674, - 0xc587, - 0xc49d, - 0xc3b7, - 0xc2d4, - 0xc1f4, - 0xc116, - 0xc03c, - 0xbf65, - 0xbe90, - 0xbdbe, - 0xbcef, - 0xbc23, - 0xbb59, - 0xba91, - 0xb9cc, - 0xb90a, - 0xb84a, - 0xb78c, - 0xb6d0, - 0xb617, - 0xb560, -}; diff --git a/src/libc-shim/src/sqrtf.c b/src/libc-shim/src/sqrtf.c deleted file mode 100644 index efa80120..00000000 --- a/src/libc-shim/src/sqrtf.c +++ /dev/null @@ -1,85 +0,0 @@ -#include "libm.h" -#include "sqrt_data.h" -#include -#include - -#define FENV_SUPPORT 1 - -static inline uint32_t mul32(uint32_t a, uint32_t b) -{ - return (uint64_t)a * b >> 32; -} - -/* see sqrt.c for more detailed comments. */ - -float sqrtf(float x) -{ - uint32_t ix, m, m1, m0, even, ey; - - ix = asuint(x); - if(predict_false(ix - 0x00800000 >= 0x7f800000 - 0x00800000)) - { - /* x < 0x1p-126 or inf or nan. */ - if(ix * 2 == 0) - return x; - if(ix == 0x7f800000) - return x; - if(ix > 0x7f800000) - return __math_invalidf(x); - /* x is subnormal, normalize it. */ - ix = asuint(x * 0x1p23f); - ix -= 23 << 23; - } - - /* x = 4^e m; with int e and m in [1, 4). */ - even = ix & 0x00800000; - m1 = (ix << 8) | 0x80000000; - m0 = (ix << 7) & 0x7fffffff; - m = even ? m0 : m1; - - /* 2^e is the exponent part of the return value. */ - ey = ix >> 1; - ey += 0x3f800000 >> 1; - ey &= 0x7f800000; - - /* compute r ~ 1/sqrt(m), s ~ sqrt(m) with 2 goldschmidt iterations. */ - static const uint32_t three = 0xc0000000; - uint32_t r, s, d, u, i; - i = (ix >> 17) % 128; - r = (uint32_t)__rsqrt_tab[i] << 16; - /* |r*sqrt(m) - 1| < 0x1p-8 */ - s = mul32(m, r); - /* |s/sqrt(m) - 1| < 0x1p-8 */ - d = mul32(s, r); - u = three - d; - r = mul32(r, u) << 1; - /* |r*sqrt(m) - 1| < 0x1.7bp-16 */ - s = mul32(s, u) << 1; - /* |s/sqrt(m) - 1| < 0x1.7bp-16 */ - d = mul32(s, r); - u = three - d; - s = mul32(s, u); - /* -0x1.03p-28 < s/sqrt(m) - 1 < 0x1.fp-31 */ - s = (s - 1) >> 6; - /* s < sqrt(m) < s + 0x1.08p-23 */ - - /* compute nearest rounded result. */ - uint32_t d0, d1, d2; - float y, t; - d0 = (m << 16) - s * s; - d1 = s - d0; - d2 = d1 + s + 1; - s += d1 >> 31; - s &= 0x007fffff; - s |= ey; - y = asfloat(s); - if(FENV_SUPPORT) - { - /* handle rounding and inexact exception. */ - uint32_t tiny = predict_false(d2 == 0) ? 0 : 0x01000000; - tiny |= (d1 ^ d2) & 0x80000000; - t = asfloat(tiny); - y = eval_as_float(y + t); - } - return y; -} diff --git a/src/libc-shim/src/.clang-format b/src/orca-libc/.clang-format similarity index 100% rename from src/libc-shim/src/.clang-format rename to src/orca-libc/.clang-format diff --git a/src/orca-libc/alltypes.h.in b/src/orca-libc/alltypes.h.in new file mode 100644 index 00000000..966e34ba --- /dev/null +++ b/src/orca-libc/alltypes.h.in @@ -0,0 +1,105 @@ +#define _Addr long +#define _Int64 long long +#define _Reg long long + +#define __BYTE_ORDER __BYTE_ORDER__ + +#define __LONG_MAX __LONG_MAX__ + +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#define __USE_TIME_BITS64 1 + +TYPEDEF unsigned _Addr size_t; +TYPEDEF unsigned _Addr uintptr_t; +TYPEDEF _Addr ptrdiff_t; +TYPEDEF _Addr ssize_t; +TYPEDEF _Addr intptr_t; +TYPEDEF _Addr regoff_t; +TYPEDEF _Reg register_t; + +TYPEDEF _Int64 time_t; +TYPEDEF _Int64 suseconds_t; + +TYPEDEF signed char int8_t; +TYPEDEF signed short int16_t; +TYPEDEF signed int int32_t; +TYPEDEF signed _Int64 int64_t; +TYPEDEF signed _Int64 intmax_t; +TYPEDEF unsigned char uint8_t; +TYPEDEF unsigned short uint16_t; +TYPEDEF unsigned int uint32_t; +TYPEDEF unsigned _Int64 uint64_t; +TYPEDEF unsigned _Int64 u_int64_t; +TYPEDEF unsigned _Int64 uintmax_t; + +TYPEDEF float float_t; +TYPEDEF double double_t; + +TYPEDEF int wchar_t; + +TYPEDEF unsigned mode_t; +TYPEDEF unsigned _Reg nlink_t; +TYPEDEF _Int64 off_t; +TYPEDEF unsigned _Int64 ino_t; +TYPEDEF unsigned _Int64 dev_t; +TYPEDEF long blksize_t; +TYPEDEF _Int64 blkcnt_t; +TYPEDEF unsigned _Int64 fsblkcnt_t; +TYPEDEF unsigned _Int64 fsfilcnt_t; + +TYPEDEF unsigned wint_t; +TYPEDEF unsigned long wctype_t; + +TYPEDEF void * timer_t; +TYPEDEF int clockid_t; +TYPEDEF long clock_t; + +STRUCT timeval { time_t tv_sec; suseconds_t tv_usec; }; +STRUCT timespec { time_t tv_sec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER==4321); long tv_nsec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER!=4321); }; + +TYPEDEF int pid_t; +TYPEDEF unsigned id_t; +TYPEDEF unsigned uid_t; +TYPEDEF unsigned gid_t; +TYPEDEF int key_t; +TYPEDEF unsigned useconds_t; + +#ifdef __cplusplus +TYPEDEF unsigned long pthread_t; +#else +TYPEDEF struct __pthread * pthread_t; +#endif +TYPEDEF int pthread_once_t; +TYPEDEF unsigned pthread_key_t; +TYPEDEF int pthread_spinlock_t; +TYPEDEF struct { unsigned __attr; } pthread_mutexattr_t; +TYPEDEF struct { unsigned __attr; } pthread_condattr_t; +TYPEDEF struct { unsigned __attr; } pthread_barrierattr_t; +TYPEDEF struct { unsigned __attr[2]; } pthread_rwlockattr_t; + +TYPEDEF __builtin_va_list va_list; +TYPEDEF __builtin_va_list __isoc_va_list; + +TYPEDEF struct __mbstate_t { unsigned __opaque1, __opaque2; } mbstate_t; + +TYPEDEF struct __locale_struct * locale_t; + +TYPEDEF struct __sigset_t { unsigned long __bits[128/sizeof(long)]; } sigset_t; + +STRUCT winsize { unsigned short ws_row, ws_col, ws_xpixel, ws_ypixel; }; + +TYPEDEF unsigned socklen_t; +TYPEDEF unsigned short sa_family_t; + +TYPEDEF struct { union { int __i[sizeof(long)==8?14:9]; volatile int __vi[sizeof(long)==8?14:9]; unsigned long __s[sizeof(long)==8?7:9]; } __u; } pthread_attr_t; +TYPEDEF struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } pthread_mutex_t; +TYPEDEF struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } mtx_t; +TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } pthread_cond_t; +TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } cnd_t; +TYPEDEF struct { union { int __i[sizeof(long)==8?14:8]; volatile int __vi[sizeof(long)==8?14:8]; void *__p[sizeof(long)==8?7:8]; } __u; } pthread_rwlock_t; +TYPEDEF struct { union { int __i[sizeof(long)==8?8:5]; volatile int __vi[sizeof(long)==8?8:5]; void *__p[sizeof(long)==8?4:5]; } __u; } pthread_barrier_t; + +#undef _Addr +#undef _Int64 +#undef _Reg diff --git a/src/orca-libc/alltypes_all.h b/src/orca-libc/alltypes_all.h new file mode 100644 index 00000000..e670f5a1 --- /dev/null +++ b/src/orca-libc/alltypes_all.h @@ -0,0 +1,381 @@ +#define _Addr long +#define _Int64 long long +#define _Reg long long + +#define __BYTE_ORDER __BYTE_ORDER__ + +#define __LONG_MAX __LONG_MAX__ + +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#define __USE_TIME_BITS64 1 + +#if defined(__NEED_size_t) && !defined(__DEFINED_size_t) +typedef unsigned _Addr size_t; +#define __DEFINED_size_t +#endif + +#if defined(__NEED_uintptr_t) && !defined(__DEFINED_uintptr_t) +typedef unsigned _Addr uintptr_t; +#define __DEFINED_uintptr_t +#endif + +#if defined(__NEED_ptrdiff_t) && !defined(__DEFINED_ptrdiff_t) +typedef _Addr ptrdiff_t; +#define __DEFINED_ptrdiff_t +#endif + +#if defined(__NEED_ssize_t) && !defined(__DEFINED_ssize_t) +typedef _Addr ssize_t; +#define __DEFINED_ssize_t +#endif + +#if defined(__NEED_intptr_t) && !defined(__DEFINED_intptr_t) +typedef _Addr intptr_t; +#define __DEFINED_intptr_t +#endif + +#if defined(__NEED_regoff_t) && !defined(__DEFINED_regoff_t) +typedef _Addr regoff_t; +#define __DEFINED_regoff_t +#endif + +#if defined(__NEED_register_t) && !defined(__DEFINED_register_t) +typedef _Reg register_t; +#define __DEFINED_register_t +#endif + + +#if defined(__NEED_time_t) && !defined(__DEFINED_time_t) +typedef _Int64 time_t; +#define __DEFINED_time_t +#endif + +#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t) +typedef _Int64 suseconds_t; +#define __DEFINED_suseconds_t +#endif + + +#if defined(__NEED_int8_t) && !defined(__DEFINED_int8_t) +typedef signed char int8_t; +#define __DEFINED_int8_t +#endif + +#if defined(__NEED_int16_t) && !defined(__DEFINED_int16_t) +typedef signed short int16_t; +#define __DEFINED_int16_t +#endif + +#if defined(__NEED_int32_t) && !defined(__DEFINED_int32_t) +typedef signed int int32_t; +#define __DEFINED_int32_t +#endif + +#if defined(__NEED_int64_t) && !defined(__DEFINED_int64_t) +typedef signed _Int64 int64_t; +#define __DEFINED_int64_t +#endif + +#if defined(__NEED_intmax_t) && !defined(__DEFINED_intmax_t) +typedef signed _Int64 intmax_t; +#define __DEFINED_intmax_t +#endif + +#if defined(__NEED_uint8_t) && !defined(__DEFINED_uint8_t) +typedef unsigned char uint8_t; +#define __DEFINED_uint8_t +#endif + +#if defined(__NEED_uint16_t) && !defined(__DEFINED_uint16_t) +typedef unsigned short uint16_t; +#define __DEFINED_uint16_t +#endif + +#if defined(__NEED_uint32_t) && !defined(__DEFINED_uint32_t) +typedef unsigned int uint32_t; +#define __DEFINED_uint32_t +#endif + +#if defined(__NEED_uint64_t) && !defined(__DEFINED_uint64_t) +typedef unsigned _Int64 uint64_t; +#define __DEFINED_uint64_t +#endif + +#if defined(__NEED_u_int64_t) && !defined(__DEFINED_u_int64_t) +typedef unsigned _Int64 u_int64_t; +#define __DEFINED_u_int64_t +#endif + +#if defined(__NEED_uintmax_t) && !defined(__DEFINED_uintmax_t) +typedef unsigned _Int64 uintmax_t; +#define __DEFINED_uintmax_t +#endif + + +#if defined(__NEED_float_t) && !defined(__DEFINED_float_t) +typedef float float_t; +#define __DEFINED_float_t +#endif + +#if defined(__NEED_double_t) && !defined(__DEFINED_double_t) +typedef double double_t; +#define __DEFINED_double_t +#endif + + +#if defined(__NEED_wchar_t) && !defined(__DEFINED_wchar_t) +typedef int wchar_t; +#define __DEFINED_wchar_t +#endif + + +#if defined(__NEED_mode_t) && !defined(__DEFINED_mode_t) +typedef unsigned mode_t; +#define __DEFINED_mode_t +#endif + +#if defined(__NEED_nlink_t) && !defined(__DEFINED_nlink_t) +typedef unsigned _Reg nlink_t; +#define __DEFINED_nlink_t +#endif + +#if defined(__NEED_off_t) && !defined(__DEFINED_off_t) +typedef _Int64 off_t; +#define __DEFINED_off_t +#endif + +#if defined(__NEED_ino_t) && !defined(__DEFINED_ino_t) +typedef unsigned _Int64 ino_t; +#define __DEFINED_ino_t +#endif + +#if defined(__NEED_dev_t) && !defined(__DEFINED_dev_t) +typedef unsigned _Int64 dev_t; +#define __DEFINED_dev_t +#endif + +#if defined(__NEED_blksize_t) && !defined(__DEFINED_blksize_t) +typedef long blksize_t; +#define __DEFINED_blksize_t +#endif + +#if defined(__NEED_blkcnt_t) && !defined(__DEFINED_blkcnt_t) +typedef _Int64 blkcnt_t; +#define __DEFINED_blkcnt_t +#endif + +#if defined(__NEED_fsblkcnt_t) && !defined(__DEFINED_fsblkcnt_t) +typedef unsigned _Int64 fsblkcnt_t; +#define __DEFINED_fsblkcnt_t +#endif + +#if defined(__NEED_fsfilcnt_t) && !defined(__DEFINED_fsfilcnt_t) +typedef unsigned _Int64 fsfilcnt_t; +#define __DEFINED_fsfilcnt_t +#endif + + +#if defined(__NEED_wint_t) && !defined(__DEFINED_wint_t) +typedef unsigned wint_t; +#define __DEFINED_wint_t +#endif + +#if defined(__NEED_wctype_t) && !defined(__DEFINED_wctype_t) +typedef unsigned long wctype_t; +#define __DEFINED_wctype_t +#endif + + +#if defined(__NEED_timer_t) && !defined(__DEFINED_timer_t) +typedef void * timer_t; +#define __DEFINED_timer_t +#endif + +#if defined(__NEED_clockid_t) && !defined(__DEFINED_clockid_t) +typedef int clockid_t; +#define __DEFINED_clockid_t +#endif + +#if defined(__NEED_clock_t) && !defined(__DEFINED_clock_t) +typedef long clock_t; +#define __DEFINED_clock_t +#endif + + +#if defined(__NEED_struct_timeval) && !defined(__DEFINED_struct_timeval) +struct timeval { time_t tv_sec; suseconds_t tv_usec; }; +#define __DEFINED_struct_timeval +#endif + +#if defined(__NEED_struct_timespec) && !defined(__DEFINED_struct_timespec) +struct timespec { time_t tv_sec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER==4321); long tv_nsec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER!=4321); }; +#define __DEFINED_struct_timespec +#endif + + +#if defined(__NEED_pid_t) && !defined(__DEFINED_pid_t) +typedef int pid_t; +#define __DEFINED_pid_t +#endif + +#if defined(__NEED_id_t) && !defined(__DEFINED_id_t) +typedef unsigned id_t; +#define __DEFINED_id_t +#endif + +#if defined(__NEED_uid_t) && !defined(__DEFINED_uid_t) +typedef unsigned uid_t; +#define __DEFINED_uid_t +#endif + +#if defined(__NEED_gid_t) && !defined(__DEFINED_gid_t) +typedef unsigned gid_t; +#define __DEFINED_gid_t +#endif + +#if defined(__NEED_key_t) && !defined(__DEFINED_key_t) +typedef int key_t; +#define __DEFINED_key_t +#endif + +#if defined(__NEED_useconds_t) && !defined(__DEFINED_useconds_t) +typedef unsigned useconds_t; +#define __DEFINED_useconds_t +#endif + + +#ifdef __cplusplus +#if defined(__NEED_pthread_t) && !defined(__DEFINED_pthread_t) +typedef unsigned long pthread_t; +#define __DEFINED_pthread_t +#endif + +#else +#if defined(__NEED_pthread_t) && !defined(__DEFINED_pthread_t) +typedef struct __pthread * pthread_t; +#define __DEFINED_pthread_t +#endif + +#endif +#if defined(__NEED_pthread_once_t) && !defined(__DEFINED_pthread_once_t) +typedef int pthread_once_t; +#define __DEFINED_pthread_once_t +#endif + +#if defined(__NEED_pthread_key_t) && !defined(__DEFINED_pthread_key_t) +typedef unsigned pthread_key_t; +#define __DEFINED_pthread_key_t +#endif + +#if defined(__NEED_pthread_spinlock_t) && !defined(__DEFINED_pthread_spinlock_t) +typedef int pthread_spinlock_t; +#define __DEFINED_pthread_spinlock_t +#endif + +#if defined(__NEED_pthread_mutexattr_t) && !defined(__DEFINED_pthread_mutexattr_t) +typedef struct { unsigned __attr; } pthread_mutexattr_t; +#define __DEFINED_pthread_mutexattr_t +#endif + +#if defined(__NEED_pthread_condattr_t) && !defined(__DEFINED_pthread_condattr_t) +typedef struct { unsigned __attr; } pthread_condattr_t; +#define __DEFINED_pthread_condattr_t +#endif + +#if defined(__NEED_pthread_barrierattr_t) && !defined(__DEFINED_pthread_barrierattr_t) +typedef struct { unsigned __attr; } pthread_barrierattr_t; +#define __DEFINED_pthread_barrierattr_t +#endif + +#if defined(__NEED_pthread_rwlockattr_t) && !defined(__DEFINED_pthread_rwlockattr_t) +typedef struct { unsigned __attr[2]; } pthread_rwlockattr_t; +#define __DEFINED_pthread_rwlockattr_t +#endif + + +#if defined(__NEED_va_list) && !defined(__DEFINED_va_list) +typedef __builtin_va_list va_list; +#define __DEFINED_va_list +#endif + +#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list) +typedef __builtin_va_list __isoc_va_list; +#define __DEFINED___isoc_va_list +#endif + + +#if defined(__NEED_mbstate_t) && !defined(__DEFINED_mbstate_t) +typedef struct __mbstate_t { unsigned __opaque1, __opaque2; } mbstate_t; +#define __DEFINED_mbstate_t +#endif + + +#if defined(__NEED_locale_t) && !defined(__DEFINED_locale_t) +typedef struct __locale_struct * locale_t; +#define __DEFINED_locale_t +#endif + + +#if defined(__NEED_sigset_t) && !defined(__DEFINED_sigset_t) +typedef struct __sigset_t { unsigned long __bits[128/sizeof(long)]; } sigset_t; +#define __DEFINED_sigset_t +#endif + + +#if defined(__NEED_struct_winsize) && !defined(__DEFINED_struct_winsize) +struct winsize { unsigned short ws_row, ws_col, ws_xpixel, ws_ypixel; }; +#define __DEFINED_struct_winsize +#endif + + +#if defined(__NEED_socklen_t) && !defined(__DEFINED_socklen_t) +typedef unsigned socklen_t; +#define __DEFINED_socklen_t +#endif + +#if defined(__NEED_sa_family_t) && !defined(__DEFINED_sa_family_t) +typedef unsigned short sa_family_t; +#define __DEFINED_sa_family_t +#endif + + +#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t) +typedef struct { union { int __i[sizeof(long)==8?14:9]; volatile int __vi[sizeof(long)==8?14:9]; unsigned long __s[sizeof(long)==8?7:9]; } __u; } pthread_attr_t; +#define __DEFINED_pthread_attr_t +#endif + +#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t) +typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } pthread_mutex_t; +#define __DEFINED_pthread_mutex_t +#endif + +#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t) +typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } mtx_t; +#define __DEFINED_mtx_t +#endif + +#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t) +typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } pthread_cond_t; +#define __DEFINED_pthread_cond_t +#endif + +#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t) +typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } cnd_t; +#define __DEFINED_cnd_t +#endif + +#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t) +typedef struct { union { int __i[sizeof(long)==8?14:8]; volatile int __vi[sizeof(long)==8?14:8]; void *__p[sizeof(long)==8?7:8]; } __u; } pthread_rwlock_t; +#define __DEFINED_pthread_rwlock_t +#endif + +#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t) +typedef struct { union { int __i[sizeof(long)==8?8:5]; volatile int __vi[sizeof(long)==8?8:5]; void *__p[sizeof(long)==8?4:5]; } __u; } pthread_barrier_t; +#define __DEFINED_pthread_barrier_t +#endif + + +#undef _Addr +#undef _Int64 +#undef _Reg diff --git a/src/orca-libc/build.sh b/src/orca-libc/build.sh new file mode 100755 index 00000000..8c9cbe88 --- /dev/null +++ b/src/orca-libc/build.sh @@ -0,0 +1,20 @@ +#!/bin/zsh + +#cfiles=(src/{complex,ctype,errno,fenv,math,prng,search,stdio,stdlib,string}/*.c) + +cfiles=(src/{complex,ctype,errno,fenv,math,prng,string,stdlib,stdio,internal,malloc,multibyte,exit}/*.c) + +warnings=(-Wall -Wextra -Werror -Wno-null-pointer-arithmetic -Wno-unused-parameter -Wno-sign-compare -Wno-unused-variable -Wno-unused-function -Wno-ignored-attributes -Wno-missing-braces -Wno-ignored-pragmas -Wno-unused-but-set-variable -Wno-unknown-warning-option -Wno-parentheses -Wno-shift-op-parentheses -Wno-bitwise-op-parentheses -Wno-logical-op-parentheses -Wno-string-plus-int -Wno-dangling-else -Wno-unknown-pragmas) + +includes=(-isystem ./include -Iarch -Isrc/internal -I..) + +# compile dummy CRT +/usr/local/opt/llvm/bin/clang -O2 -DNDEBUG --target=wasm32 --no-standard-libraries -fno-trapping-math -mbulk-memory -DBULK_MEMORY_THRESHOLD=32 -mthread-model single -MD -MP -Wl,--relocatable $warnings $includes -o lib/crt1.o src/crt/crt1.c + +# compile standard lib +/usr/local/opt/llvm/bin/clang -O2 -DNDEBUG --target=wasm32 -D__ORCA__ --std=c11 --no-standard-libraries -fno-trapping-math -mbulk-memory -DBULK_MEMORY_THRESHOLD=32 -mthread-model single -MD -MP -Wl,--relocatable $warnings $includes -o lib/libc.o $cfiles + +/usr/local/opt/llvm/bin/llvm-ar crs lib/libc.a lib/libc.o + +# compile test +/usr/local/opt/llvm/bin/clang -O2 --target=wasm32 --sysroot=. -Wl,--no-entry -o test test.c diff --git a/src/orca-libc/include/__header_fcntl.h b/src/orca-libc/include/__header_fcntl.h new file mode 100644 index 00000000..84098fb9 --- /dev/null +++ b/src/orca-libc/include/__header_fcntl.h @@ -0,0 +1,60 @@ +#ifndef __HEADER_FCNTL_H +#define __HEADER_FCNTL_H + +#include <__seek.h> +#include <__mode_t.h> + +#define O_APPEND (1 << 0) +#define O_DSYNC (1 << 1) +#define O_NONBLOCK (1 << 2) +#define O_RSYNC (1 << 3) +#define O_SYNC (1 << 4) +#define O_CREAT ((1 << 0) << 12) +#define O_DIRECTORY ((1 << 1) << 12) +#define O_EXCL ((1 << 2) << 12) +#define O_TRUNC ((1 << 3) << 12) + +#define O_NOFOLLOW (0x01000000) +#define O_EXEC (0x02000000) +#define O_RDONLY (0x04000000) +#define O_SEARCH (0x08000000) +#define O_WRONLY (0x10000000) + +/* + * O_CLOEXEC is defined to be zero, as WASI has no exec-style functions. + */ +#define O_CLOEXEC (0) + +/* + * O_TTY_INIT is defined to be zero, meaning that WASI implementations are + * expected to always initialize a terminal the first time it's opened. + */ +#define O_TTY_INIT (0) + +#define O_NOCTTY (0) + +#define O_RDWR (O_RDONLY | O_WRONLY) +#define O_ACCMODE (O_EXEC | O_RDWR | O_SEARCH) + +#define POSIX_FADV_DONTNEED __WASI_ADVICE_DONTNEED +#define POSIX_FADV_NOREUSE __WASI_ADVICE_NOREUSE +#define POSIX_FADV_NORMAL __WASI_ADVICE_NORMAL +#define POSIX_FADV_RANDOM __WASI_ADVICE_RANDOM +#define POSIX_FADV_SEQUENTIAL __WASI_ADVICE_SEQUENTIAL +#define POSIX_FADV_WILLNEED __WASI_ADVICE_WILLNEED + +#define F_GETFD (1) +#define F_SETFD (2) +#define F_GETFL (3) +#define F_SETFL (4) + +#define FD_CLOEXEC (1) + +#define AT_EACCESS (0x0) +#define AT_SYMLINK_NOFOLLOW (0x1) +#define AT_SYMLINK_FOLLOW (0x2) +#define AT_REMOVEDIR (0x4) + +#define AT_FDCWD (-2) + +#endif diff --git a/src/orca-libc/include/__macro_PAGESIZE.h b/src/orca-libc/include/__macro_PAGESIZE.h new file mode 100644 index 00000000..d8922205 --- /dev/null +++ b/src/orca-libc/include/__macro_PAGESIZE.h @@ -0,0 +1,16 @@ +#ifndef __wasilibc___macro_PAGESIZE_h +#define __wasilibc___macro_PAGESIZE_h + +/* + * The page size in WebAssembly is fixed at 64 KiB. If this ever changes, + * it's expected that applications will need to opt in, so we can change + * this. + * + * If this ever needs to be a value outside the range of an `int`, the + * `getpagesize` function which returns this value will need special + * consideration. POSIX has deprecated `getpagesize` in favor of + * `sysconf(_SC_PAGESIZE)` which does not have this problem. + */ +#define PAGESIZE (0x10000) + +#endif diff --git a/src/orca-libc/include/__mode_t.h b/src/orca-libc/include/__mode_t.h new file mode 100644 index 00000000..d8dcaf96 --- /dev/null +++ b/src/orca-libc/include/__mode_t.h @@ -0,0 +1,38 @@ +#ifndef __MODE_T_H +#define __MODE_T_H + +#define S_IFMT \ + (S_IFBLK | S_IFCHR | S_IFDIR | S_IFIFO | S_IFLNK | S_IFREG | S_IFSOCK) +#define S_IFBLK (0x6000) +#define S_IFCHR (0x2000) +#define S_IFDIR (0x4000) +#define S_IFLNK (0xa000) +#define S_IFREG (0x8000) +#define S_IFSOCK (0xc000) +#define S_IFIFO (0xc000) + +#define S_ISBLK(m) (((m)&S_IFMT) == S_IFBLK) +#define S_ISCHR(m) (((m)&S_IFMT) == S_IFCHR) +#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) +#define S_ISFIFO(m) (((m)&S_IFMT) == S_IFIFO) +#define S_ISLNK(m) (((m)&S_IFMT) == S_IFLNK) +#define S_ISREG(m) (((m)&S_IFMT) == S_IFREG) +#define S_ISSOCK(m) (((m)&S_IFMT) == S_IFSOCK) + +#define S_IXOTH (0x1) +#define S_IWOTH (0x2) +#define S_IROTH (0x4) +#define S_IRWXO (S_IXOTH | S_IWOTH | S_IROTH) +#define S_IXGRP (0x8) +#define S_IWGRP (0x10) +#define S_IRGRP (0x20) +#define S_IRWXG (S_IXGRP | S_IWGRP | S_IRGRP) +#define S_IXUSR (0x40) +#define S_IWUSR (0x80) +#define S_IRUSR (0x100) +#define S_IRWXU (S_IXUSR | S_IWUSR | S_IRUSR) +#define S_ISVTX (0x200) +#define S_ISGID (0x400) +#define S_ISUID (0x800) + +#endif diff --git a/src/orca-libc/include/__seek.h b/src/orca-libc/include/__seek.h new file mode 100644 index 00000000..f36192d8 --- /dev/null +++ b/src/orca-libc/include/__seek.h @@ -0,0 +1,8 @@ +#ifndef __wasilibc___seek_h +#define __wasilibc___seek_h + +#define SEEK_CUR __WASI_WHENCE_CUR +#define SEEK_END __WASI_WHENCE_END +#define SEEK_SET __WASI_WHENCE_SET + +#endif diff --git a/src/libc-shim/include/assert.h b/src/orca-libc/include/assert.h similarity index 91% rename from src/libc-shim/include/assert.h rename to src/orca-libc/include/assert.h index e537bf31..f5d76cd5 100644 --- a/src/libc-shim/include/assert.h +++ b/src/orca-libc/include/assert.h @@ -1,4 +1,5 @@ #include "platform/platform_debug.h" +#include "util/debug.h" #include #undef assert diff --git a/src/orca-libc/include/bits/alltypes.h b/src/orca-libc/include/bits/alltypes.h new file mode 100644 index 00000000..86ff22df --- /dev/null +++ b/src/orca-libc/include/bits/alltypes.h @@ -0,0 +1,157 @@ +#define _Addr long +#define _Int64 long long +#define _Reg long long + +#define __BYTE_ORDER __BYTE_ORDER__ + +#define __LONG_MAX __LONG_MAX__ + +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#define __USE_TIME_BITS64 1 + +#if defined(__NEED_size_t) && !defined(__DEFINED_size_t) +typedef unsigned _Addr size_t; +#define __DEFINED_size_t +#endif + +#if defined(__NEED_uintptr_t) && !defined(__DEFINED_uintptr_t) +typedef unsigned _Addr uintptr_t; +#define __DEFINED_uintptr_t +#endif + +#if defined(__NEED_ptrdiff_t) && !defined(__DEFINED_ptrdiff_t) +typedef _Addr ptrdiff_t; +#define __DEFINED_ptrdiff_t +#endif + +#if defined(__NEED_ssize_t) && !defined(__DEFINED_ssize_t) +typedef _Addr ssize_t; +#define __DEFINED_ssize_t +#endif + +#if defined(__NEED_intptr_t) && !defined(__DEFINED_intptr_t) +typedef _Addr intptr_t; +#define __DEFINED_intptr_t +#endif + +#if defined(__NEED_regoff_t) && !defined(__DEFINED_regoff_t) +typedef _Addr regoff_t; +#define __DEFINED_regoff_t +#endif + +#if defined(__NEED_register_t) && !defined(__DEFINED_register_t) +typedef _Reg register_t; +#define __DEFINED_register_t +#endif + +#if defined(__NEED_int8_t) && !defined(__DEFINED_int8_t) +typedef signed char int8_t; +#define __DEFINED_int8_t +#endif + +#if defined(__NEED_int16_t) && !defined(__DEFINED_int16_t) +typedef signed short int16_t; +#define __DEFINED_int16_t +#endif + +#if defined(__NEED_int32_t) && !defined(__DEFINED_int32_t) +typedef signed int int32_t; +#define __DEFINED_int32_t +#endif + +#if defined(__NEED_int64_t) && !defined(__DEFINED_int64_t) +typedef signed _Int64 int64_t; +#define __DEFINED_int64_t +#endif + +#if defined(__NEED_intmax_t) && !defined(__DEFINED_intmax_t) +typedef signed _Int64 intmax_t; +#define __DEFINED_intmax_t +#endif + +#if defined(__NEED_uint8_t) && !defined(__DEFINED_uint8_t) +typedef unsigned char uint8_t; +#define __DEFINED_uint8_t +#endif + +#if defined(__NEED_uint16_t) && !defined(__DEFINED_uint16_t) +typedef unsigned short uint16_t; +#define __DEFINED_uint16_t +#endif + +#if defined(__NEED_uint32_t) && !defined(__DEFINED_uint32_t) +typedef unsigned int uint32_t; +#define __DEFINED_uint32_t +#endif + +#if defined(__NEED_uint64_t) && !defined(__DEFINED_uint64_t) +typedef unsigned _Int64 uint64_t; +#define __DEFINED_uint64_t +#endif + +#if defined(__NEED_u_int64_t) && !defined(__DEFINED_u_int64_t) +typedef unsigned _Int64 u_int64_t; +#define __DEFINED_u_int64_t +#endif + +#if defined(__NEED_uintmax_t) && !defined(__DEFINED_uintmax_t) +typedef unsigned _Int64 uintmax_t; +#define __DEFINED_uintmax_t +#endif + + +#if defined(__NEED_float_t) && !defined(__DEFINED_float_t) +typedef float float_t; +#define __DEFINED_float_t +#endif + +#if defined(__NEED_double_t) && !defined(__DEFINED_double_t) +typedef double double_t; +#define __DEFINED_double_t +#endif + + +#if defined(__NEED_wchar_t) && !defined(__DEFINED_wchar_t) +typedef int wchar_t; +#define __DEFINED_wchar_t +#endif + +#if defined(__NEED_off_t) && !defined(__DEFINED_off_t) +typedef _Int64 off_t; +#define __DEFINED_off_t +#endif + +#if defined(__NEED_wint_t) && !defined(__DEFINED_wint_t) +typedef unsigned wint_t; +#define __DEFINED_wint_t +#endif + +#if defined(__NEED_wctype_t) && !defined(__DEFINED_wctype_t) +typedef unsigned long wctype_t; +#define __DEFINED_wctype_t +#endif + +#if defined(__NEED_FILE) && !defined(__DEFINED_FILE) +typedef struct _IO_FILE FILE; +#define __DEFINED_FILE +#endif + +#if defined(__NEED_va_list) && !defined(__DEFINED_va_list) +typedef __builtin_va_list va_list; +#define __DEFINED_va_list +#endif + +#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list) +typedef __builtin_va_list __isoc_va_list; +#define __DEFINED___isoc_va_list +#endif + +#if defined(__NEED_mbstate_t) && !defined(__DEFINED_mbstate_t) +typedef struct __mbstate_t { unsigned __opaque1, __opaque2; } mbstate_t; +#define __DEFINED_mbstate_t +#endif + +#undef _Addr +#undef _Int64 +#undef _Reg diff --git a/src/orca-libc/include/bits/errno.h b/src/orca-libc/include/bits/errno.h new file mode 100644 index 00000000..d2e1eeee --- /dev/null +++ b/src/orca-libc/include/bits/errno.h @@ -0,0 +1,134 @@ +#define EPERM 1 +#define ENOENT 2 +#define ESRCH 3 +#define EINTR 4 +#define EIO 5 +#define ENXIO 6 +#define E2BIG 7 +#define ENOEXEC 8 +#define EBADF 9 +#define ECHILD 10 +#define EAGAIN 11 +#define ENOMEM 12 +#define EACCES 13 +#define EFAULT 14 +#define ENOTBLK 15 +#define EBUSY 16 +#define EEXIST 17 +#define EXDEV 18 +#define ENODEV 19 +#define ENOTDIR 20 +#define EISDIR 21 +#define EINVAL 22 +#define ENFILE 23 +#define EMFILE 24 +#define ENOTTY 25 +#define ETXTBSY 26 +#define EFBIG 27 +#define ENOSPC 28 +#define ESPIPE 29 +#define EROFS 30 +#define EMLINK 31 +#define EPIPE 32 +#define EDOM 33 +#define ERANGE 34 +#define EDEADLK 35 +#define ENAMETOOLONG 36 +#define ENOLCK 37 +#define ENOSYS 38 +#define ENOTEMPTY 39 +#define ELOOP 40 +#define EWOULDBLOCK EAGAIN +#define ENOMSG 42 +#define EIDRM 43 +#define ECHRNG 44 +#define EL2NSYNC 45 +#define EL3HLT 46 +#define EL3RST 47 +#define ELNRNG 48 +#define EUNATCH 49 +#define ENOCSI 50 +#define EL2HLT 51 +#define EBADE 52 +#define EBADR 53 +#define EXFULL 54 +#define ENOANO 55 +#define EBADRQC 56 +#define EBADSLT 57 +#define EDEADLOCK EDEADLK +#define EBFONT 59 +#define ENOSTR 60 +#define ENODATA 61 +#define ETIME 62 +#define ENOSR 63 +#define ENONET 64 +#define ENOPKG 65 +#define EREMOTE 66 +#define ENOLINK 67 +#define EADV 68 +#define ESRMNT 69 +#define ECOMM 70 +#define EPROTO 71 +#define EMULTIHOP 72 +#define EDOTDOT 73 +#define EBADMSG 74 +#define EOVERFLOW 75 +#define ENOTUNIQ 76 +#define EBADFD 77 +#define EREMCHG 78 +#define ELIBACC 79 +#define ELIBBAD 80 +#define ELIBSCN 81 +#define ELIBMAX 82 +#define ELIBEXEC 83 +#define EILSEQ 84 +#define ERESTART 85 +#define ESTRPIPE 86 +#define EUSERS 87 +#define ENOTSOCK 88 +#define EDESTADDRREQ 89 +#define EMSGSIZE 90 +#define EPROTOTYPE 91 +#define ENOPROTOOPT 92 +#define EPROTONOSUPPORT 93 +#define ESOCKTNOSUPPORT 94 +#define EOPNOTSUPP 95 +#define ENOTSUP EOPNOTSUPP +#define EPFNOSUPPORT 96 +#define EAFNOSUPPORT 97 +#define EADDRINUSE 98 +#define EADDRNOTAVAIL 99 +#define ENETDOWN 100 +#define ENETUNREACH 101 +#define ENETRESET 102 +#define ECONNABORTED 103 +#define ECONNRESET 104 +#define ENOBUFS 105 +#define EISCONN 106 +#define ENOTCONN 107 +#define ESHUTDOWN 108 +#define ETOOMANYREFS 109 +#define ETIMEDOUT 110 +#define ECONNREFUSED 111 +#define EHOSTDOWN 112 +#define EHOSTUNREACH 113 +#define EALREADY 114 +#define EINPROGRESS 115 +#define ESTALE 116 +#define EUCLEAN 117 +#define ENOTNAM 118 +#define ENAVAIL 119 +#define EISNAM 120 +#define EREMOTEIO 121 +#define EDQUOT 122 +#define ENOMEDIUM 123 +#define EMEDIUMTYPE 124 +#define ECANCELED 125 +#define ENOKEY 126 +#define EKEYEXPIRED 127 +#define EKEYREVOKED 128 +#define EKEYREJECTED 129 +#define EOWNERDEAD 130 +#define ENOTRECOVERABLE 131 +#define ERFKILL 132 +#define EHWPOISON 133 diff --git a/src/orca-libc/include/bits/fcntl.h b/src/orca-libc/include/bits/fcntl.h new file mode 100644 index 00000000..a2f33416 --- /dev/null +++ b/src/orca-libc/include/bits/fcntl.h @@ -0,0 +1 @@ +/* Use the WASI libc fcntl implementation bits. */ diff --git a/src/orca-libc/include/bits/fenv.h b/src/orca-libc/include/bits/fenv.h new file mode 100644 index 00000000..edbdea2a --- /dev/null +++ b/src/orca-libc/include/bits/fenv.h @@ -0,0 +1,10 @@ +#define FE_ALL_EXCEPT 0 +#define FE_TONEAREST 0 + +typedef unsigned long fexcept_t; + +typedef struct { + unsigned long __cw; +} fenv_t; + +#define FE_DFL_ENV ((const fenv_t *) -1) diff --git a/src/orca-libc/include/bits/float.h b/src/orca-libc/include/bits/float.h new file mode 100644 index 00000000..719c7908 --- /dev/null +++ b/src/orca-libc/include/bits/float.h @@ -0,0 +1,16 @@ +#define FLT_EVAL_METHOD 0 + +#define LDBL_TRUE_MIN 6.47517511943802511092443895822764655e-4966L +#define LDBL_MIN 3.36210314311209350626267781732175260e-4932L +#define LDBL_MAX 1.18973149535723176508575932662800702e+4932L +#define LDBL_EPSILON 1.92592994438723585305597794258492732e-34L + +#define LDBL_MANT_DIG 113 +#define LDBL_MIN_EXP (-16381) +#define LDBL_MAX_EXP 16384 + +#define LDBL_DIG 33 +#define LDBL_MIN_10_EXP (-4931) +#define LDBL_MAX_10_EXP 4932 + +#define DECIMAL_DIG 36 diff --git a/src/orca-libc/include/bits/limits.h b/src/orca-libc/include/bits/limits.h new file mode 100644 index 00000000..801bc48f --- /dev/null +++ b/src/orca-libc/include/bits/limits.h @@ -0,0 +1 @@ +#include <__macro_PAGESIZE.h> diff --git a/src/orca-libc/include/bits/stdint.h b/src/orca-libc/include/bits/stdint.h new file mode 100644 index 00000000..6e7c7705 --- /dev/null +++ b/src/orca-libc/include/bits/stdint.h @@ -0,0 +1,20 @@ +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; + +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST32_MIN INT32_MIN + +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MAX INT32_MAX + +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX + +#define INTPTR_MIN INT32_MIN +#define INTPTR_MAX INT32_MAX +#define UINTPTR_MAX UINT32_MAX +#define PTRDIFF_MIN INT32_MIN +#define PTRDIFF_MAX INT32_MAX +#define SIZE_MAX UINT32_MAX diff --git a/src/orca-libc/include/complex.h b/src/orca-libc/include/complex.h new file mode 100644 index 00000000..0616817d --- /dev/null +++ b/src/orca-libc/include/complex.h @@ -0,0 +1,128 @@ +#ifndef _COMPLEX_H +#define _COMPLEX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define complex _Complex +#ifdef __GNUC__ +#define _Complex_I (__extension__ (0.0f+1.0fi)) +#else +#define _Complex_I (0.0f+1.0fi) +#endif +#define I _Complex_I + +double complex cacos(double complex); +float complex cacosf(float complex); +long double complex cacosl(long double complex); + +double complex casin(double complex); +float complex casinf(float complex); +long double complex casinl(long double complex); + +double complex catan(double complex); +float complex catanf(float complex); +long double complex catanl(long double complex); + +double complex ccos(double complex); +float complex ccosf(float complex); +long double complex ccosl(long double complex); + +double complex csin(double complex); +float complex csinf(float complex); +long double complex csinl(long double complex); + +double complex ctan(double complex); +float complex ctanf(float complex); +long double complex ctanl(long double complex); + +double complex cacosh(double complex); +float complex cacoshf(float complex); +long double complex cacoshl(long double complex); + +double complex casinh(double complex); +float complex casinhf(float complex); +long double complex casinhl(long double complex); + +double complex catanh(double complex); +float complex catanhf(float complex); +long double complex catanhl(long double complex); + +double complex ccosh(double complex); +float complex ccoshf(float complex); +long double complex ccoshl(long double complex); + +double complex csinh(double complex); +float complex csinhf(float complex); +long double complex csinhl(long double complex); + +double complex ctanh(double complex); +float complex ctanhf(float complex); +long double complex ctanhl(long double complex); + +double complex cexp(double complex); +float complex cexpf(float complex); +long double complex cexpl(long double complex); + +double complex clog(double complex); +float complex clogf(float complex); +long double complex clogl(long double complex); + +double cabs(double complex); +float cabsf(float complex); +long double cabsl(long double complex); + +double complex cpow(double complex, double complex); +float complex cpowf(float complex, float complex); +long double complex cpowl(long double complex, long double complex); + +double complex csqrt(double complex); +float complex csqrtf(float complex); +long double complex csqrtl(long double complex); + +double carg(double complex); +float cargf(float complex); +long double cargl(long double complex); + +double cimag(double complex); +float cimagf(float complex); +long double cimagl(long double complex); + +double complex conj(double complex); +float complex conjf(float complex); +long double complex conjl(long double complex); + +double complex cproj(double complex); +float complex cprojf(float complex); +long double complex cprojl(long double complex); + +double creal(double complex); +float crealf(float complex); +long double creall(long double complex); + +#define creal(x) (__builtin_creal(x)) +#define crealf(x) (__builtin_crealf(x)) +#define creall(x) (__builtin_creall(x)) + +#define cimag(x) (__builtin_cimag(x)) +#define cimagf(x) (__builtin_cimagf(x)) +#define cimagl(x) (__builtin_cimagl(x)) + +#if __STDC_VERSION__ >= 201112L +#if defined(_Imaginary_I) +#define __CMPLX(x, y, t) ((t)(x) + _Imaginary_I*(t)(y)) +#elif defined(__clang__) +#define __CMPLX(x, y, t) (+(_Complex t){ (t)(x), (t)(y) }) +#else +#define __CMPLX(x, y, t) (__builtin_complex((t)(x), (t)(y))) +#endif +#define CMPLX(x, y) __CMPLX(x, y, double) +#define CMPLXF(x, y) __CMPLX(x, y, float) +#define CMPLXL(x, y) __CMPLX(x, y, long double) +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/orca-libc/include/ctype.h b/src/orca-libc/include/ctype.h new file mode 100644 index 00000000..d156b22c --- /dev/null +++ b/src/orca-libc/include/ctype.h @@ -0,0 +1,52 @@ +#ifndef _CTYPE_H +#define _CTYPE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +int isalnum(int); +int isalpha(int); +int isblank(int); +int iscntrl(int); +int isdigit(int); +int isgraph(int); +int islower(int); +int isprint(int); +int ispunct(int); +int isspace(int); +int isupper(int); +int isxdigit(int); +int tolower(int); +int toupper(int); + +#ifndef __cplusplus +static __inline int __isspace(int _c) +{ + return _c == ' ' || (unsigned)_c-'\t' < 5; +} + +#define isalpha(a) (0 ? isalpha(a) : (((unsigned)(a)|32)-'a') < 26) +#define isdigit(a) (0 ? isdigit(a) : ((unsigned)(a)-'0') < 10) +#define islower(a) (0 ? islower(a) : ((unsigned)(a)-'a') < 26) +#define isupper(a) (0 ? isupper(a) : ((unsigned)(a)-'A') < 26) +#define isprint(a) (0 ? isprint(a) : ((unsigned)(a)-0x20) < 0x5f) +#define isgraph(a) (0 ? isgraph(a) : ((unsigned)(a)-0x21) < 0x5e) +#define isspace(a) __isspace(a) +#endif + +int isascii(int); +int toascii(int); +#define _tolower(a) ((a)|0x20) +#define _toupper(a) ((a)&0x5f) +#ifndef __cplusplus +#define isascii(a) (0 ? isascii(a) : (unsigned)(a) < 128) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/orca-libc/include/endian.h b/src/orca-libc/include/endian.h new file mode 100644 index 00000000..172c4320 --- /dev/null +++ b/src/orca-libc/include/endian.h @@ -0,0 +1,80 @@ +#ifndef _ENDIAN_H +#define _ENDIAN_H + +#include + +#define __NEED_uint16_t +#define __NEED_uint32_t +#define __NEED_uint64_t + +#include + +#define __PDP_ENDIAN 3412 + +#define BIG_ENDIAN __BIG_ENDIAN +#define LITTLE_ENDIAN __LITTLE_ENDIAN +#define PDP_ENDIAN __PDP_ENDIAN +#define BYTE_ORDER __BYTE_ORDER + +static __inline uint16_t __bswap16(uint16_t __x) +{ + return __x<<8 | __x>>8; +} + +static __inline uint32_t __bswap32(uint32_t __x) +{ + return __x>>24 | __x>>8&0xff00 | __x<<8&0xff0000 | __x<<24; +} + +static __inline uint64_t __bswap64(uint64_t __x) +{ + return __bswap32(__x)+0ULL<<32 | __bswap32(__x>>32); +} + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define htobe16(x) __bswap16(x) +#define be16toh(x) __bswap16(x) +#define htobe32(x) __bswap32(x) +#define be32toh(x) __bswap32(x) +#define htobe64(x) __bswap64(x) +#define be64toh(x) __bswap64(x) +#define htole16(x) (uint16_t)(x) +#define le16toh(x) (uint16_t)(x) +#define htole32(x) (uint32_t)(x) +#define le32toh(x) (uint32_t)(x) +#define htole64(x) (uint64_t)(x) +#define le64toh(x) (uint64_t)(x) +#else +#define htobe16(x) (uint16_t)(x) +#define be16toh(x) (uint16_t)(x) +#define htobe32(x) (uint32_t)(x) +#define be32toh(x) (uint32_t)(x) +#define htobe64(x) (uint64_t)(x) +#define be64toh(x) (uint64_t)(x) +#define htole16(x) __bswap16(x) +#define le16toh(x) __bswap16(x) +#define htole32(x) __bswap32(x) +#define le32toh(x) __bswap32(x) +#define htole64(x) __bswap64(x) +#define le64toh(x) __bswap64(x) +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define betoh16(x) __bswap16(x) +#define betoh32(x) __bswap32(x) +#define betoh64(x) __bswap64(x) +#define letoh16(x) (uint16_t)(x) +#define letoh32(x) (uint32_t)(x) +#define letoh64(x) (uint64_t)(x) +#else +#define betoh16(x) (uint16_t)(x) +#define betoh32(x) (uint32_t)(x) +#define betoh64(x) (uint64_t)(x) +#define letoh16(x) __bswap16(x) +#define letoh32(x) __bswap32(x) +#define letoh64(x) __bswap64(x) +#endif +#endif + +#endif diff --git a/src/orca-libc/include/errno.h b/src/orca-libc/include/errno.h new file mode 100644 index 00000000..152a0237 --- /dev/null +++ b/src/orca-libc/include/errno.h @@ -0,0 +1,22 @@ +#ifndef _ERRNO_H +#define _ERRNO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#ifdef __GNUC__ +__attribute__((const)) +#endif +int *__errno_location(void); +#define errno (*__errno_location()) + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/orca-libc/include/fcntl.h b/src/orca-libc/include/fcntl.h new file mode 100644 index 00000000..05e4cb72 --- /dev/null +++ b/src/orca-libc/include/fcntl.h @@ -0,0 +1,246 @@ +#ifndef _FCNTL_H +#define _FCNTL_H + +#ifdef __wasilibc_unmodified_upstream /* Use alternate WASI libc headers */ +#else +#include <__header_fcntl.h> +#endif +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_off_t +#define __NEED_pid_t +#define __NEED_mode_t + +#ifdef _GNU_SOURCE +#define __NEED_size_t +#define __NEED_ssize_t +#define __NEED_struct_iovec +#endif + +#include + +#include + +// struct flock { +// short l_type; +// short l_whence; +// off_t l_start; +// off_t l_len; +// pid_t l_pid; +// }; + +// int creat(const char *, mode_t); +// int fcntl(int, int, ...); +// int open(const char *, int, ...); +// int openat(int, const char *, int, ...); +// int posix_fadvise(int, off_t, off_t, int); +// int posix_fallocate(int, off_t, off_t); + +#ifdef __wasilibc_unmodified_upstream /* Use alternate WASI libc headers */ +#define O_SEARCH O_PATH +#define O_EXEC O_PATH +#define O_TTY_INIT 0 + +#define O_ACCMODE (03|O_SEARCH) +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 + +#define F_OFD_GETLK 36 +#define F_OFD_SETLK 37 +#define F_OFD_SETLKW 38 + +#define F_DUPFD_CLOEXEC 1030 + +#define F_RDLCK 0 +#define F_WRLCK 1 +#define F_UNLCK 2 + +#define FD_CLOEXEC 1 + +#define AT_FDCWD (-100) +#define AT_SYMLINK_NOFOLLOW 0x100 +#define AT_REMOVEDIR 0x200 +#define AT_SYMLINK_FOLLOW 0x400 +#define AT_EACCESS 0x200 + +#define POSIX_FADV_NORMAL 0 +#define POSIX_FADV_RANDOM 1 +#define POSIX_FADV_SEQUENTIAL 2 +#define POSIX_FADV_WILLNEED 3 +#ifndef POSIX_FADV_DONTNEED +#define POSIX_FADV_DONTNEED 4 +#define POSIX_FADV_NOREUSE 5 +#endif + +#undef SEEK_SET +#undef SEEK_CUR +#undef SEEK_END +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#ifndef S_IRUSR +#define S_ISUID 04000 +#define S_ISGID 02000 +#define S_ISVTX 01000 +#define S_IRUSR 0400 +#define S_IWUSR 0200 +#define S_IXUSR 0100 +#define S_IRWXU 0700 +#define S_IRGRP 0040 +#define S_IWGRP 0020 +#define S_IXGRP 0010 +#define S_IRWXG 0070 +#define S_IROTH 0004 +#define S_IWOTH 0002 +#define S_IXOTH 0001 +#define S_IRWXO 0007 +#endif + +// #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +// #define AT_NO_AUTOMOUNT 0x800 +// #define AT_EMPTY_PATH 0x1000 +// #define AT_STATX_SYNC_TYPE 0x6000 +// #define AT_STATX_SYNC_AS_STAT 0x0000 +// #define AT_STATX_FORCE_SYNC 0x2000 +// #define AT_STATX_DONT_SYNC 0x4000 +// #define AT_RECURSIVE 0x8000 + +// #define FAPPEND O_APPEND +// #define FFSYNC O_SYNC +// #define FASYNC O_ASYNC +// #define FNONBLOCK O_NONBLOCK +// #define FNDELAY O_NDELAY + +// #define F_OK 0 +// #define R_OK 4 +// #define W_OK 2 +// #define X_OK 1 +// #define F_ULOCK 0 +// #define F_LOCK 1 +// #define F_TLOCK 2 +// #define F_TEST 3 + +// #define F_SETLEASE 1024 +// #define F_GETLEASE 1025 +// #define F_NOTIFY 1026 +// #define F_CANCELLK 1029 +// #define F_SETPIPE_SZ 1031 +// #define F_GETPIPE_SZ 1032 +// #define F_ADD_SEALS 1033 +// #define F_GET_SEALS 1034 + +// #define F_SEAL_SEAL 0x0001 +// #define F_SEAL_SHRINK 0x0002 +// #define F_SEAL_GROW 0x0004 +// #define F_SEAL_WRITE 0x0008 +// #define F_SEAL_FUTURE_WRITE 0x0010 + +// #define F_GET_RW_HINT 1035 +// #define F_SET_RW_HINT 1036 +// #define F_GET_FILE_RW_HINT 1037 +// #define F_SET_FILE_RW_HINT 1038 + +// #define RWF_WRITE_LIFE_NOT_SET 0 +// #define RWH_WRITE_LIFE_NONE 1 +// #define RWH_WRITE_LIFE_SHORT 2 +// #define RWH_WRITE_LIFE_MEDIUM 3 +// #define RWH_WRITE_LIFE_LONG 4 +// #define RWH_WRITE_LIFE_EXTREME 5 + +// #define DN_ACCESS 0x00000001 +// #define DN_MODIFY 0x00000002 +// #define DN_CREATE 0x00000004 +// #define DN_DELETE 0x00000008 +// #define DN_RENAME 0x00000010 +// #define DN_ATTRIB 0x00000020 +// #define DN_MULTISHOT 0x80000000 + +// int lockf(int, int, off_t); +// #endif // defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#endif + +#if defined(_GNU_SOURCE) +// #ifdef __wasilibc_unmodified_upstream /* WASI has no name_to_handle_at */ +// #define F_OWNER_TID 0 +// #define F_OWNER_PID 1 +// #define F_OWNER_PGRP 2 +// #define F_OWNER_GID 2 +// struct file_handle { +// unsigned handle_bytes; +// int handle_type; +// unsigned char f_handle[]; +// }; +// #endif +// #ifdef __wasilibc_unmodified_upstream /* WASI has no F_GETOWN_EX */ +// struct f_owner_ex { +// int type; +// pid_t pid; +// }; +// #endif +// #ifdef __wasilibc_unmodified_upstream /* WASI has no fallocate */ +// #define FALLOC_FL_KEEP_SIZE 1 +// #define FALLOC_FL_PUNCH_HOLE 2 +// #endif +// #ifdef __wasilibc_unmodified_upstream /* WASI has no name_to_handle_at */ +// #define MAX_HANDLE_SZ 128 +// #endif +// #ifdef __wasilibc_unmodified_upstream /* WASI has no syc_file_range */ +// #define SYNC_FILE_RANGE_WAIT_BEFORE 1 +// #define SYNC_FILE_RANGE_WRITE 2 +// #define SYNC_FILE_RANGE_WAIT_AFTER 4 +// #endif +// #ifdef __wasilibc_unmodified_upstream /* WASI has no splice */ +// #define SPLICE_F_MOVE 1 +// #define SPLICE_F_NONBLOCK 2 +// #define SPLICE_F_MORE 4 +// #define SPLICE_F_GIFT 8 +// #endif +// #ifdef __wasilibc_unmodified_upstream /* WASI has no fallocate */ +// int fallocate(int, int, off_t, off_t); +// #define fallocate64 fallocate +// #endif +// #ifdef __wasilibc_unmodified_upstream /* WASI has no name_to_handle_at */ +// int name_to_handle_at(int, const char *, struct file_handle *, int *, int); +// int open_by_handle_at(int, struct file_handle *, int); +// #endif +// #ifdef __wasilibc_unmodified_upstream /* WASI has no readahead */ +// ssize_t readahead(int, off_t, size_t); +// #endif +// #ifdef __wasilibc_unmodified_upstream /* WASI has no splice, syc_file_range, or tee */ +// int sync_file_range(int, off_t, off_t, unsigned); +// ssize_t vmsplice(int, const struct iovec *, size_t, unsigned); +// ssize_t splice(int, off_t *, int, off_t *, size_t, unsigned); +// ssize_t tee(int, int, size_t, unsigned); +// #endif +#define loff_t off_t +#endif + +#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#ifdef __wasilibc_unmodified_upstream /* WASI has no POSIX file locking */ +#define F_GETLK64 F_GETLK +#define F_SETLK64 F_SETLK +#define F_SETLKW64 F_SETLKW +#define flock64 flock +#endif +#define open64 open +#define openat64 openat +#define creat64 creat +// #ifdef __wasilibc_unmodified_upstream /* WASI has no POSIX file locking */ +// #define lockf64 lockf +// #endif +#define posix_fadvise64 posix_fadvise +#define posix_fallocate64 posix_fallocate +#define off64_t off_t +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/orca-libc/include/features.h b/src/orca-libc/include/features.h new file mode 100644 index 00000000..77032e88 --- /dev/null +++ b/src/orca-libc/include/features.h @@ -0,0 +1,23 @@ +#ifndef _FEATURES_H +#define _FEATURES_H + +#if __STDC_VERSION__ >= 199901L +#define __restrict restrict +#elif !defined(__GNUC__) +#define __restrict +#endif + +#if __STDC_VERSION__ >= 199901L || defined(__cplusplus) +#define __inline inline +#elif !defined(__GNUC__) +#define __inline +#endif + +#if __STDC_VERSION__ >= 201112L +#elif defined(__GNUC__) +#define _Noreturn __attribute__((__noreturn__)) +#else +#define _Noreturn +#endif + +#endif diff --git a/src/orca-libc/include/fenv.h b/src/orca-libc/include/fenv.h new file mode 100644 index 00000000..05de990c --- /dev/null +++ b/src/orca-libc/include/fenv.h @@ -0,0 +1,28 @@ +#ifndef _FENV_H +#define _FENV_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +int feclearexcept(int); +int fegetexceptflag(fexcept_t *, int); +int feraiseexcept(int); +int fesetexceptflag(const fexcept_t *, int); +int fetestexcept(int); + +int fegetround(void); +int fesetround(int); + +int fegetenv(fenv_t *); +int feholdexcept(fenv_t *); +int fesetenv(const fenv_t *); +int feupdateenv(const fenv_t *); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/libc-shim/include/float.h b/src/orca-libc/include/float.h similarity index 92% rename from src/libc-shim/include/float.h rename to src/orca-libc/include/float.h index 671f1ae4..b4377cb8 100644 --- a/src/libc-shim/include/float.h +++ b/src/orca-libc/include/float.h @@ -2,12 +2,10 @@ #define _FLOAT_H #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif - int __flt_rounds(void); -#define FLT_ROUNDS (__flt_rounds()) +#define FLT_ROUNDS (__builtin_flt_rounds()) #define FLT_RADIX 2 diff --git a/src/orca-libc/include/inttypes.h b/src/orca-libc/include/inttypes.h new file mode 100644 index 00000000..61dcb727 --- /dev/null +++ b/src/orca-libc/include/inttypes.h @@ -0,0 +1,229 @@ +#ifndef _INTTYPES_H +#define _INTTYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define __NEED_wchar_t +#include + +typedef struct { intmax_t quot, rem; } imaxdiv_t; + +intmax_t imaxabs(intmax_t); +imaxdiv_t imaxdiv(intmax_t, intmax_t); + +intmax_t strtoimax(const char *__restrict, char **__restrict, int); +uintmax_t strtoumax(const char *__restrict, char **__restrict, int); + +intmax_t wcstoimax(const wchar_t *__restrict, wchar_t **__restrict, int); +uintmax_t wcstoumax(const wchar_t *__restrict, wchar_t **__restrict, int); + +#if UINTPTR_MAX == UINT64_MAX +#define __PRI64 "l" +#define __PRIPTR "l" +#else +#define __PRI64 "ll" +#define __PRIPTR "" +#endif + +#define PRId8 "d" +#define PRId16 "d" +#define PRId32 "d" +#define PRId64 __PRI64 "d" + +#define PRIdLEAST8 "d" +#define PRIdLEAST16 "d" +#define PRIdLEAST32 "d" +#define PRIdLEAST64 __PRI64 "d" + +#define PRIdFAST8 "d" +#define PRIdFAST16 "d" +#define PRIdFAST32 "d" +#define PRIdFAST64 __PRI64 "d" + +#define PRIi8 "i" +#define PRIi16 "i" +#define PRIi32 "i" +#define PRIi64 __PRI64 "i" + +#define PRIiLEAST8 "i" +#define PRIiLEAST16 "i" +#define PRIiLEAST32 "i" +#define PRIiLEAST64 __PRI64 "i" + +#define PRIiFAST8 "i" +#define PRIiFAST16 "i" +#define PRIiFAST32 "i" +#define PRIiFAST64 __PRI64 "i" + +#define PRIo8 "o" +#define PRIo16 "o" +#define PRIo32 "o" +#define PRIo64 __PRI64 "o" + +#define PRIoLEAST8 "o" +#define PRIoLEAST16 "o" +#define PRIoLEAST32 "o" +#define PRIoLEAST64 __PRI64 "o" + +#define PRIoFAST8 "o" +#define PRIoFAST16 "o" +#define PRIoFAST32 "o" +#define PRIoFAST64 __PRI64 "o" + +#define PRIu8 "u" +#define PRIu16 "u" +#define PRIu32 "u" +#define PRIu64 __PRI64 "u" + +#define PRIuLEAST8 "u" +#define PRIuLEAST16 "u" +#define PRIuLEAST32 "u" +#define PRIuLEAST64 __PRI64 "u" + +#define PRIuFAST8 "u" +#define PRIuFAST16 "u" +#define PRIuFAST32 "u" +#define PRIuFAST64 __PRI64 "u" + +#define PRIx8 "x" +#define PRIx16 "x" +#define PRIx32 "x" +#define PRIx64 __PRI64 "x" + +#define PRIxLEAST8 "x" +#define PRIxLEAST16 "x" +#define PRIxLEAST32 "x" +#define PRIxLEAST64 __PRI64 "x" + +#define PRIxFAST8 "x" +#define PRIxFAST16 "x" +#define PRIxFAST32 "x" +#define PRIxFAST64 __PRI64 "x" + +#define PRIX8 "X" +#define PRIX16 "X" +#define PRIX32 "X" +#define PRIX64 __PRI64 "X" + +#define PRIXLEAST8 "X" +#define PRIXLEAST16 "X" +#define PRIXLEAST32 "X" +#define PRIXLEAST64 __PRI64 "X" + +#define PRIXFAST8 "X" +#define PRIXFAST16 "X" +#define PRIXFAST32 "X" +#define PRIXFAST64 __PRI64 "X" + +#define PRIdMAX __PRI64 "d" +#define PRIiMAX __PRI64 "i" +#define PRIoMAX __PRI64 "o" +#define PRIuMAX __PRI64 "u" +#define PRIxMAX __PRI64 "x" +#define PRIXMAX __PRI64 "X" + +#define PRIdPTR __PRIPTR "d" +#define PRIiPTR __PRIPTR "i" +#define PRIoPTR __PRIPTR "o" +#define PRIuPTR __PRIPTR "u" +#define PRIxPTR __PRIPTR "x" +#define PRIXPTR __PRIPTR "X" + +#define SCNd8 "hhd" +#define SCNd16 "hd" +#define SCNd32 "d" +#define SCNd64 __PRI64 "d" + +#define SCNdLEAST8 "hhd" +#define SCNdLEAST16 "hd" +#define SCNdLEAST32 "d" +#define SCNdLEAST64 __PRI64 "d" + +#define SCNdFAST8 "hhd" +#define SCNdFAST16 "d" +#define SCNdFAST32 "d" +#define SCNdFAST64 __PRI64 "d" + +#define SCNi8 "hhi" +#define SCNi16 "hi" +#define SCNi32 "i" +#define SCNi64 __PRI64 "i" + +#define SCNiLEAST8 "hhi" +#define SCNiLEAST16 "hi" +#define SCNiLEAST32 "i" +#define SCNiLEAST64 __PRI64 "i" + +#define SCNiFAST8 "hhi" +#define SCNiFAST16 "i" +#define SCNiFAST32 "i" +#define SCNiFAST64 __PRI64 "i" + +#define SCNu8 "hhu" +#define SCNu16 "hu" +#define SCNu32 "u" +#define SCNu64 __PRI64 "u" + +#define SCNuLEAST8 "hhu" +#define SCNuLEAST16 "hu" +#define SCNuLEAST32 "u" +#define SCNuLEAST64 __PRI64 "u" + +#define SCNuFAST8 "hhu" +#define SCNuFAST16 "u" +#define SCNuFAST32 "u" +#define SCNuFAST64 __PRI64 "u" + +#define SCNo8 "hho" +#define SCNo16 "ho" +#define SCNo32 "o" +#define SCNo64 __PRI64 "o" + +#define SCNoLEAST8 "hho" +#define SCNoLEAST16 "ho" +#define SCNoLEAST32 "o" +#define SCNoLEAST64 __PRI64 "o" + +#define SCNoFAST8 "hho" +#define SCNoFAST16 "o" +#define SCNoFAST32 "o" +#define SCNoFAST64 __PRI64 "o" + +#define SCNx8 "hhx" +#define SCNx16 "hx" +#define SCNx32 "x" +#define SCNx64 __PRI64 "x" + +#define SCNxLEAST8 "hhx" +#define SCNxLEAST16 "hx" +#define SCNxLEAST32 "x" +#define SCNxLEAST64 __PRI64 "x" + +#define SCNxFAST8 "hhx" +#define SCNxFAST16 "x" +#define SCNxFAST32 "x" +#define SCNxFAST64 __PRI64 "x" + +#define SCNdMAX __PRI64 "d" +#define SCNiMAX __PRI64 "i" +#define SCNoMAX __PRI64 "o" +#define SCNuMAX __PRI64 "u" +#define SCNxMAX __PRI64 "x" + +#define SCNdPTR __PRIPTR "d" +#define SCNiPTR __PRIPTR "i" +#define SCNoPTR __PRIPTR "o" +#define SCNuPTR __PRIPTR "u" +#define SCNxPTR __PRIPTR "x" + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/orca-libc/include/iso646.h b/src/orca-libc/include/iso646.h new file mode 100644 index 00000000..88ff53d7 --- /dev/null +++ b/src/orca-libc/include/iso646.h @@ -0,0 +1,20 @@ +#ifndef _ISO646_H +#define _ISO646_H + +#ifndef __cplusplus + +#define and && +#define and_eq &= +#define bitand & +#define bitor | +#define compl ~ +#define not ! +#define not_eq != +#define or || +#define or_eq |= +#define xor ^ +#define xor_eq ^= + +#endif + +#endif diff --git a/src/orca-libc/include/limits.h b/src/orca-libc/include/limits.h new file mode 100644 index 00000000..6a4becb3 --- /dev/null +++ b/src/orca-libc/include/limits.h @@ -0,0 +1,81 @@ +#ifndef _LIMITS_H +#define _LIMITS_H + +#include + +#include /* __LONG_MAX */ + +/* Support signed or unsigned plain-char */ + +#if '\xff' > 0 +#define CHAR_MIN 0 +#define CHAR_MAX 255 +#else +#define CHAR_MIN (-128) +#define CHAR_MAX 127 +#endif + +#define CHAR_BIT 8 +#define SCHAR_MIN (-128) +#define SCHAR_MAX 127 +#define UCHAR_MAX 255 +#define SHRT_MIN (-1-0x7fff) +#define SHRT_MAX 0x7fff +#define USHRT_MAX 0xffff +#define INT_MIN (-1-0x7fffffff) +#define INT_MAX 0x7fffffff +#define UINT_MAX 0xffffffffU +#define LONG_MIN (-LONG_MAX-1) +#define LONG_MAX __LONG_MAX +#define ULONG_MAX (2UL*LONG_MAX+1) +#define LLONG_MIN (-LLONG_MAX-1) +#define LLONG_MAX 0x7fffffffffffffffLL +#define ULLONG_MAX (2ULL*LLONG_MAX+1) + +#define MB_LEN_MAX 4 + +#include + + +#define FILESIZEBITS 64 +#ifndef NAME_MAX +#define NAME_MAX 255 +#endif +#define PATH_MAX 4096 +#define NGROUPS_MAX 32 +#define ARG_MAX 131072 +#define IOV_MAX 1024 +#define SYMLOOP_MAX 40 +#define WORD_BIT 32 +#define SSIZE_MAX LONG_MAX +#define TZNAME_MAX 6 +#define TTY_NAME_MAX 32 +#define HOST_NAME_MAX 255 + +#if LONG_MAX == 0x7fffffffL +#define LONG_BIT 32 +#else +#define LONG_BIT 64 +#endif + +/* Implementation choices... */ + +#define DELAYTIMER_MAX 0x7fffffff + +/* Arbitrary numbers... */ + +#define CHARCLASS_NAME_MAX 14 +#define COLL_WEIGHTS_MAX 2 +#define RE_DUP_MAX 255 + +#define NL_ARGMAX 9 +#define NL_MSGMAX 32767 +#define NL_SETMAX 255 +#define NL_TEXTMAX 2048 + +#ifdef PAGESIZE +#define PAGE_SIZE PAGESIZE +#endif +#define NZERO 20 + +#endif diff --git a/src/orca-libc/include/math.h b/src/orca-libc/include/math.h new file mode 100644 index 00000000..9d591740 --- /dev/null +++ b/src/orca-libc/include/math.h @@ -0,0 +1,361 @@ +#ifndef _MATH_H +#define _MATH_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_float_t +#define __NEED_double_t +#include + +#if 100*__GNUC__+__GNUC_MINOR__ >= 303 +#define NAN __builtin_nanf("") +#define INFINITY __builtin_inff() +#else +#define NAN (0.0f/0.0f) +#define INFINITY 1e5000f +#endif + +#define HUGE_VALF INFINITY +#define HUGE_VAL ((double)INFINITY) +#define HUGE_VALL ((long double)INFINITY) + +#define MATH_ERRNO 1 +#define MATH_ERREXCEPT 2 +#define math_errhandling 2 + +#define FP_ILOGBNAN (-1-0x7fffffff) +#define FP_ILOGB0 FP_ILOGBNAN + +#define FP_NAN 0 +#define FP_INFINITE 1 +#define FP_ZERO 2 +#define FP_SUBNORMAL 3 +#define FP_NORMAL 4 + +#ifdef __FP_FAST_FMA +#define FP_FAST_FMA 1 +#endif + +#ifdef __FP_FAST_FMAF +#define FP_FAST_FMAF 1 +#endif + +#ifdef __FP_FAST_FMAL +#define FP_FAST_FMAL 1 +#endif + +#define fpclassify(x) (__builtin_fpclassify(FP_NAN, FP_INFINITE, \ + FP_NORMAL, FP_SUBNORMAL, \ + FP_ZERO, x)) +#define isinf(x) (__builtin_isinf(x)) +#define isnan(x) (__builtin_isnan(x)) +#define isnormal(x) (__builtin_isnormal(x)) +#define isfinite(x) (__builtin_isfinite(x)) +#define signbit(x) (__builtin_signbit(x)) +#define isunordered(x, y) (__builtin_isunordered(x, y)) +#define isless(x, y) (__builtin_isless(x, y)) +#define islessequal(x, y) (__builtin_islessequal(x, y)) +#define islessgreater(x, y) (__builtin_islessgreater(x, y)) +#define isgreater(x, y) (__builtin_isgreater(x, y)) +#define isgreaterequal(x, y) (__builtin_isgreaterequal(x, y)) + +double acos(double); +float acosf(float); +long double acosl(long double); + +double acosh(double); +float acoshf(float); +long double acoshl(long double); + +double asin(double); +float asinf(float); +long double asinl(long double); + +double asinh(double); +float asinhf(float); +long double asinhl(long double); + +double atan(double); +float atanf(float); +long double atanl(long double); + +double atan2(double, double); +float atan2f(float, float); +long double atan2l(long double, long double); + +double atanh(double); +float atanhf(float); +long double atanhl(long double); + +double cbrt(double); +float cbrtf(float); +long double cbrtl(long double); + +double ceil(double); +float ceilf(float); +long double ceill(long double); + +double copysign(double, double); +float copysignf(float, float); +long double copysignl(long double, long double); + +double cos(double); +float cosf(float); +long double cosl(long double); + +double cosh(double); +float coshf(float); +long double coshl(long double); + +double erf(double); +float erff(float); +long double erfl(long double); + +double erfc(double); +float erfcf(float); +long double erfcl(long double); + +double exp(double); +float expf(float); +long double expl(long double); + +double exp2(double); +float exp2f(float); +long double exp2l(long double); + +double expm1(double); +float expm1f(float); +long double expm1l(long double); + +double fabs(double); +float fabsf(float); +long double fabsl(long double); + +double fdim(double, double); +float fdimf(float, float); +long double fdiml(long double, long double); + +double floor(double); +float floorf(float); +long double floorl(long double); + +double fma(double, double, double); +float fmaf(float, float, float); +long double fmal(long double, long double, long double); + +double fmax(double, double); +float fmaxf(float, float); +long double fmaxl(long double, long double); + +double fmin(double, double); +float fminf(float, float); +long double fminl(long double, long double); + +double fmod(double, double); +float fmodf(float, float); +long double fmodl(long double, long double); + +double frexp(double, int *); +float frexpf(float, int *); +long double frexpl(long double, int *); + +double hypot(double, double); +float hypotf(float, float); +long double hypotl(long double, long double); + +int ilogb(double); +int ilogbf(float); +int ilogbl(long double); + +double ldexp(double, int); +float ldexpf(float, int); +long double ldexpl(long double, int); + +double lgamma(double); +float lgammaf(float); +long double lgammal(long double); + +long long llrint(double); +long long llrintf(float); +long long llrintl(long double); + +long long llround(double); +long long llroundf(float); +long long llroundl(long double); + +double log(double); +float logf(float); +long double logl(long double); + +double log10(double); +float log10f(float); +long double log10l(long double); + +double log1p(double); +float log1pf(float); +long double log1pl(long double); + +double log2(double); +float log2f(float); +long double log2l(long double); + +double logb(double); +float logbf(float); +long double logbl(long double); + +long lrint(double); +long lrintf(float); +long lrintl(long double); + +long lround(double); +long lroundf(float); +long lroundl(long double); + +double modf(double, double *); +float modff(float, float *); +long double modfl(long double, long double *); + +double nan(const char *); +float nanf(const char *); +long double nanl(const char *); + +double nearbyint(double); +float nearbyintf(float); +long double nearbyintl(long double); + +double nextafter(double, double); +float nextafterf(float, float); +long double nextafterl(long double, long double); + +double nexttoward(double, long double); +float nexttowardf(float, long double); +long double nexttowardl(long double, long double); + +double pow(double, double); +float powf(float, float); +long double powl(long double, long double); + +double remainder(double, double); +float remainderf(float, float); +long double remainderl(long double, long double); + +double remquo(double, double, int *); +float remquof(float, float, int *); +long double remquol(long double, long double, int *); + +double rint(double); +float rintf(float); +long double rintl(long double); + +double round(double); +float roundf(float); +long double roundl(long double); + +double scalbln(double, long); +float scalblnf(float, long); +long double scalblnl(long double, long); + +double scalbn(double, int); +float scalbnf(float, int); +long double scalbnl(long double, int); + +double sin(double); +float sinf(float); +long double sinl(long double); + +double sinh(double); +float sinhf(float); +long double sinhl(long double); + +double sqrt(double); +float sqrtf(float); +long double sqrtl(long double); + +double tan(double); +float tanf(float); +long double tanl(long double); + +double tanh(double); +float tanhf(float); +long double tanhl(long double); + +double tgamma(double); +float tgammaf(float); +long double tgammal(long double); + +double trunc(double); +float truncf(float); +long double truncl(long double); + +#define M_E 2.7182818284590452354 /* e */ +#define M_LOG2E 1.4426950408889634074 /* log_2 e */ +#define M_LOG10E 0.43429448190325182765 /* log_10 e */ +#define M_LN2 0.69314718055994530942 /* log_e 2 */ +#define M_LN10 2.30258509299404568402 /* log_e 10 */ +#define M_PI 3.14159265358979323846 /* pi */ +#define M_PI_2 1.57079632679489661923 /* pi/2 */ +#define M_PI_4 0.78539816339744830962 /* pi/4 */ +#define M_1_PI 0.31830988618379067154 /* 1/pi */ +#define M_2_PI 0.63661977236758134308 /* 2/pi */ +#define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */ +#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ +#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ + +extern int signgam; + +double j0(double); +double j1(double); +double jn(int, double); + +double y0(double); +double y1(double); +double yn(int, double); + +#define HUGE 3.40282346638528859812e+38F + +double drem(double, double); +float dremf(float, float); + +int finite(double); +int finitef(float); + +double scalb(double, double); +float scalbf(float, float); + +double significand(double); +float significandf(float); + +double lgamma_r(double, int*); +float lgammaf_r(float, int*); + +float j0f(float); +float j1f(float); +float jnf(int, float); + +float y0f(float); +float y1f(float); +float ynf(int, float); + +long double lgammal_r(long double, int*); + +void sincos(double, double*, double*); +void sincosf(float, float*, float*); +void sincosl(long double, long double*, long double*); + +double exp10(double); +float exp10f(float); +long double exp10l(long double); + +double pow10(double); +float pow10f(float); +long double pow10l(long double); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/orca-libc/include/private/printscan.h b/src/orca-libc/include/private/printscan.h new file mode 100644 index 00000000..7c21f99d --- /dev/null +++ b/src/orca-libc/include/private/printscan.h @@ -0,0 +1,59 @@ +#if defined(__wasilibc_printscan_no_floating_point) + +#include + +__attribute__((__cold__, __noreturn__)) +static void floating_point_not_supported(void) { + void abort(void) __attribute__((__noreturn__)); + fputs("Support for floating-point formatting is currently disabled.\n" + "To enable it, " __wasilibc_printscan_floating_point_support_option ".\n", stderr); + abort(); +} + +#elif defined(__wasilibc_printscan_no_long_double) + +#include + +typedef double long_double; +#undef LDBL_TRUE_MIN +#define LDBL_TRUE_MIN DBL_DENORM_MIN +#undef LDBL_MIN +#define LDBL_MIN DBL_MIN +#undef LDBL_MAX +#define LDBL_MAX DBL_MAX +#undef LDBL_EPSILON +#define LDBL_EPSILON DBL_EPSILON +#undef LDBL_MANT_DIG +#define LDBL_MANT_DIG DBL_MANT_DIG +#undef LDBL_MIN_EXP +#define LDBL_MIN_EXP DBL_MIN_EXP +#undef LDBL_MAX_EXP +#define LDBL_MAX_EXP DBL_MAX_EXP +#undef LDBL_DIG +#define LDBL_DIG DBL_DIG +#undef LDBL_MIN_10_EXP +#define LDBL_MIN_10_EXP DBL_MIN_10_EXP +#undef LDBL_MAX_10_EXP +#define LDBL_MAX_10_EXP DBL_MAX_10_EXP +#undef frexpl +#define frexpl(x, exp) frexp(x, exp) +#undef copysignl +#define copysignl(x, y) copysign(x, y) +#undef fmodl +#define fmodl(x, y) fmod(x, y) +#undef scalbnl +#define scalbnl(arg, exp) scalbn(arg, exp) +__attribute__((__cold__, __noreturn__)) +static void long_double_not_supported(void) { + void abort(void) __attribute__((__noreturn__)); + fputs("Support for formatting long double values is currently disabled.\n" + "To enable it, " __wasilibc_printscan_full_support_option ".\n", &__stderr_FILE); + abort(); +} + +#else + +// Full long double support. +typedef long double long_double; + +#endif diff --git a/src/orca-libc/include/stdalign.h b/src/orca-libc/include/stdalign.h new file mode 100644 index 00000000..2cc94be3 --- /dev/null +++ b/src/orca-libc/include/stdalign.h @@ -0,0 +1,20 @@ +#ifndef _STDALIGN_H +#define _STDALIGN_H + +#ifndef __cplusplus + +/* this whole header only works in C11 or with compiler extensions */ +#if __STDC_VERSION__ < 201112L && defined( __GNUC__) +#define _Alignas(t) __attribute__((__aligned__(t))) +#define _Alignof(t) __alignof__(t) +#endif + +#define alignas _Alignas +#define alignof _Alignof + +#endif + +#define __alignas_is_defined 1 +#define __alignof_is_defined 1 + +#endif diff --git a/src/orca-libc/include/stdarg.h b/src/orca-libc/include/stdarg.h new file mode 100644 index 00000000..3256f805 --- /dev/null +++ b/src/orca-libc/include/stdarg.h @@ -0,0 +1,21 @@ +#ifndef _STDARG_H +#define _STDARG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_va_list + +#include + +#define va_start(v,l) __builtin_va_start(v,l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v,l) __builtin_va_arg(v,l) +#define va_copy(d,s) __builtin_va_copy(d,s) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/orca-libc/include/stdbool.h b/src/orca-libc/include/stdbool.h new file mode 100644 index 00000000..a9d7ab78 --- /dev/null +++ b/src/orca-libc/include/stdbool.h @@ -0,0 +1,14 @@ +#ifndef _STDBOOL_H +#define _STDBOOL_H + +#ifndef __cplusplus + +#define true 1 +#define false 0 +#define bool _Bool + +#endif + +#define __bool_true_false_are_defined 1 + +#endif diff --git a/src/orca-libc/include/stddef.h b/src/orca-libc/include/stddef.h new file mode 100644 index 00000000..f25b8639 --- /dev/null +++ b/src/orca-libc/include/stddef.h @@ -0,0 +1,27 @@ +#ifndef _STDDEF_H +#define _STDDEF_H + +#if __cplusplus >= 201103L +#define NULL nullptr +#elif defined(__cplusplus) +#define NULL 0L +#else +#define NULL ((void*)0) +#endif + +#define __NEED_ptrdiff_t +#define __NEED_size_t +#define __NEED_wchar_t +#if __STDC_VERSION__ >= 201112L || __cplusplus >= 201103L +#define __NEED_max_align_t +#endif + +#include + +#if __GNUC__ > 3 +#define offsetof(type, member) __builtin_offsetof(type, member) +#else +#define offsetof(type, member) ((size_t)( (char *)&(((type *)0)->member) - (char *)0 )) +#endif + +#endif diff --git a/src/orca-libc/include/stdint.h b/src/orca-libc/include/stdint.h new file mode 100644 index 00000000..a2968197 --- /dev/null +++ b/src/orca-libc/include/stdint.h @@ -0,0 +1,117 @@ +#ifndef _STDINT_H +#define _STDINT_H + +#define __NEED_int8_t +#define __NEED_int16_t +#define __NEED_int32_t +#define __NEED_int64_t + +#define __NEED_uint8_t +#define __NEED_uint16_t +#define __NEED_uint32_t +#define __NEED_uint64_t + +#define __NEED_intptr_t +#define __NEED_uintptr_t + +#define __NEED_intmax_t +#define __NEED_uintmax_t + +#include + +typedef int8_t int_fast8_t; +typedef int64_t int_fast64_t; + +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; + +typedef uint8_t uint_fast8_t; +typedef uint64_t uint_fast64_t; + +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +#define INT8_MIN (-1-0x7f) +#define INT16_MIN (-1-0x7fff) +#define INT32_MIN (-1-0x7fffffff) +#define INT64_MIN (-1-0x7fffffffffffffff) + +#define INT8_MAX (0x7f) +#define INT16_MAX (0x7fff) +#define INT32_MAX (0x7fffffff) +#define INT64_MAX (0x7fffffffffffffff) + +#define UINT8_MAX (0xff) +#define UINT16_MAX (0xffff) +#define UINT32_MAX (0xffffffffu) +#define UINT64_MAX (0xffffffffffffffffu) + +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST64_MIN INT64_MIN + +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST64_MIN INT64_MIN + +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST64_MAX INT64_MAX + +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MAX INT64_MAX + +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST64_MAX UINT64_MAX + +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +#define WINT_MIN 0U +#define WINT_MAX UINT32_MAX + +#if L'\0'-1 > 0 +#define WCHAR_MAX (0xffffffffu+L'\0') +#define WCHAR_MIN (0+L'\0') +#else +#define WCHAR_MAX (0x7fffffff+L'\0') +#define WCHAR_MIN (-1-0x7fffffff+L'\0') +#endif + +#define SIG_ATOMIC_MIN INT32_MIN +#define SIG_ATOMIC_MAX INT32_MAX + +#include + +#define INT8_C(c) c +#define INT16_C(c) c +#define INT32_C(c) c + +#define UINT8_C(c) c +#define UINT16_C(c) c +#define UINT32_C(c) c ## U + +#if UINTPTR_MAX == UINT64_MAX +#define INT64_C(c) c ## L +#define UINT64_C(c) c ## UL +#define INTMAX_C(c) c ## L +#define UINTMAX_C(c) c ## UL +#else +#define INT64_C(c) c ## LL +#define UINT64_C(c) c ## ULL +#define INTMAX_C(c) c ## LL +#define UINTMAX_C(c) c ## ULL +#endif + +#endif diff --git a/src/orca-libc/include/stdio.h b/src/orca-libc/include/stdio.h new file mode 100644 index 00000000..de9fd927 --- /dev/null +++ b/src/orca-libc/include/stdio.h @@ -0,0 +1,102 @@ +#ifndef _STDIO_H +#define _STDIO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_FILE +#define __NEED___isoc_va_list +#define __NEED_size_t +#define __NEED_ssize_t +#define __NEED_off_t +#define __NEED_va_list + +#include + +#define __need_NULL +#include + +#undef EOF +#define EOF (-1) + +#undef SEEK_SET +#undef SEEK_CUR +#undef SEEK_END +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#define _IOFBF 0 +#define _IOLBF 1 +#define _IONBF 2 + +#define BUFSIZ 1024 +#define FILENAME_MAX 4096 +#define FOPEN_MAX 1000 + +typedef union _G_fpos64_t +{ + char __opaque[16]; + long long __lldata; + double __align; +} fpos_t; + +extern FILE* const stdin; +extern FILE* const stdout; +extern FILE* const stderr; + +#define stdin (stdin) +#define stdout (stdout) +#define stderr (stderr) + +char* fgets(char* restrict str, int num, FILE* restrict stream ); +FILE* fopen(const char* restrict name, const char* restrict type); +FILE* freopen(const char* restrict filename, const char* restrict mode, FILE* restrict f); +int fclose(FILE* stream); +int feof(FILE* stream); +int ferror(FILE* stream); +int fflush(FILE* stream); +int fgetc(FILE* stream); +int fgetpos(FILE* restrict stream, fpos_t* restrict pos); +int fputc(int character, FILE* stream); +int fputs(const char* restrict str, FILE* restrict stream ); +int fseek(FILE* stream, long int offset, int origin); +int fsetpos(FILE* restrict stream, const fpos_t* pos); +int getchar(void); +int putchar(int character); +int setvbuf(FILE* restrict f, char* restrict buf, int type, size_t size); +int ungetc(int c, FILE* f); +long int ftell(FILE* stream); +size_t fread(void* restrict buffer, size_t size, size_t n, FILE* restrict stream); +size_t fwrite(const void* restrict buffer, size_t size, size_t n, FILE* restrict stream); +void clearerr(FILE *f); +void perror(const char* msg); +void rewind(FILE* stream); +void setbuf(FILE* restrict f, char* restrict buf); + +#define putc fputc +#define getc fgetc + +int printf(const char* format, ...); +int fprintf(FILE* restrict f, const char* restrict fmt, ...); +int snprintf(char* restrict s, size_t n, const char* restrict fmt, ...); +int sprintf(char* restrict s, const char* restrict fmt, ...); +int vfprintf(FILE* restrict f, const char* restrict fmt, va_list ap); +int vsnprintf(char* restrict s, size_t n, const char* restrict fmt, __isoc_va_list); +int vsprintf(char* restrict, const char* restrict, __isoc_va_list); + +int scanf(const char* format, ...); +int fscanf(FILE* restrict f, const char* restrict fmt, ...); +int sscanf(const char* restrict, const char* restrict, ...); +int vfscanf(FILE* restrict f, const char* restrict fmt, va_list ap); +int vsscanf(const char* restrict, const char* restrict, __isoc_va_list); +int vscanf(const char* restrict fmt, __isoc_va_list); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/orca-libc/include/stdlib.h b/src/orca-libc/include/stdlib.h new file mode 100644 index 00000000..e0c2aa9d --- /dev/null +++ b/src/orca-libc/include/stdlib.h @@ -0,0 +1,96 @@ +#ifndef _STDLIB_H +#define _STDLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __need_NULL +#include + +#define __NEED_size_t +#define __NEED_wchar_t + +#include + +int atoi(const char*); +long atol(const char*); +long long atoll(const char*); +double atof(const char*); + +float strtof(const char* __restrict, char** __restrict); +double strtod(const char* __restrict, char** __restrict); +long double strtold(const char* __restrict, char** __restrict); + +long strtol(const char* __restrict, char** __restrict, int); +unsigned long strtoul(const char* __restrict, char** __restrict, int); +long long strtoll(const char* __restrict, char** __restrict, int); +unsigned long long strtoull(const char* __restrict, char** __restrict, int); + +int rand(void); +void srand(unsigned); + +void* malloc(size_t); +void* calloc(size_t, size_t); +void* realloc(void*, size_t); +void free(void*); + +void* aligned_alloc(size_t, size_t); + +_Noreturn void abort(void); +int atexit(void (*)(void)); +_Noreturn void exit(int); +_Noreturn void _Exit(int); + +void* bsearch(const void*, const void*, size_t, size_t, int (*)(const void*, const void*)); +void qsort(void*, size_t, size_t, int (*)(const void*, const void*)); + +int abs(int); +long labs(long); +long long llabs(long long); + +typedef struct +{ + int quot, rem; +} div_t; + +typedef struct +{ + long quot, rem; +} ldiv_t; + +typedef struct +{ + long long quot, rem; +} lldiv_t; + +div_t div(int, int); +ldiv_t ldiv(long, long); +lldiv_t lldiv(long long, long long); + +int mblen(const char*, size_t); +int mbtowc(wchar_t* __restrict, const char* __restrict, size_t); +int wctomb(char*, wchar_t); +size_t mbstowcs(wchar_t* __restrict, const char* __restrict, size_t); +size_t wcstombs(char* __restrict, const wchar_t* __restrict, size_t); + +#define EXIT_FAILURE 1 +#define EXIT_SUCCESS 0 + +#define RAND_MAX (0x7fffffff) + +int rand_r(unsigned*); +long int random(void); +void srandom(unsigned int); +char* initstate(unsigned int, char*, size_t); +char* setstate(char*); + +void qsort_r(void*, size_t, size_t, int (*)(const void*, const void*, void*), void*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/orca-libc/include/stdnoreturn.h b/src/orca-libc/include/stdnoreturn.h new file mode 100644 index 00000000..5c6aeeb0 --- /dev/null +++ b/src/orca-libc/include/stdnoreturn.h @@ -0,0 +1,7 @@ +#ifndef _STDNORETURN_H +#define _STDNORETURN_H +#ifndef __cplusplus +#include +#define noreturn _Noreturn +#endif +#endif diff --git a/src/orca-libc/include/string.h b/src/orca-libc/include/string.h new file mode 100644 index 00000000..0c29533f --- /dev/null +++ b/src/orca-libc/include/string.h @@ -0,0 +1,72 @@ +#ifndef _STRING_H +#define _STRING_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __need_NULL +#include + +#define __NEED_size_t + +#include + + +void *memcpy (void *__restrict, const void *__restrict, size_t); +void *memmove (void *, const void *, size_t); +void *memset (void *, int, size_t); +int memcmp (const void *, const void *, size_t); +void *memchr (const void *, int, size_t); + +char *strcpy (char *__restrict, const char *__restrict); +char *strncpy (char *__restrict, const char *__restrict, size_t); + +char *strcat (char *__restrict, const char *__restrict); +char *strncat (char *__restrict, const char *__restrict, size_t); + +int strcmp (const char *, const char *); +int strncmp (const char *, const char *, size_t); + +int strcoll (const char *, const char *); +size_t strxfrm (char *__restrict, const char *__restrict, size_t); + +char *strchr (const char *, int); +char *strrchr (const char *, int); + +size_t strcspn (const char *, const char *); +size_t strspn (const char *, const char *); +char *strpbrk (const char *, const char *); +char *strstr (const char *, const char *); +char *strtok (char *__restrict, const char *__restrict); + +size_t strlen (const char *); + +char *strerror (int); + +#include + +char *strtok_r (char *__restrict, const char *__restrict, char **__restrict); +int strerror_r (int, char *, size_t); +char *stpcpy(char *__restrict, const char *__restrict); +char *stpncpy(char *__restrict, const char *__restrict, size_t); +size_t strnlen (const char *, size_t); +char *strdup (const char *); +char *strndup (const char *, size_t); +char *strsignal(int); + +void *memccpy (void *__restrict, const void *__restrict, int, size_t); + +char *strsep(char **, const char *); +size_t strlcat (char *, const char *, size_t); +size_t strlcpy (char *, const char *, size_t); +void explicit_bzero (void *, size_t); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/orca-libc/include/strings.h b/src/orca-libc/include/strings.h new file mode 100644 index 00000000..492037d4 --- /dev/null +++ b/src/orca-libc/include/strings.h @@ -0,0 +1,28 @@ +#ifndef _STRINGS_H +#define _STRINGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_size_t +#include + +int bcmp (const void *, const void *, size_t); +void bcopy (const void *, void *, size_t); +void bzero (void *, size_t); +char *index (const char *, int); +char *rindex (const char *, int); + +int ffs (int); +int ffsl (long); +int ffsll (long long); + +int strcasecmp (const char *, const char *); +int strncasecmp (const char *, const char *, size_t); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/orca-libc/include/tgmath.h b/src/orca-libc/include/tgmath.h new file mode 100644 index 00000000..e41ccac9 --- /dev/null +++ b/src/orca-libc/include/tgmath.h @@ -0,0 +1,270 @@ +#ifndef _TGMATH_H +#define _TGMATH_H + +/* +the return types are only correct with gcc (__GNUC__) +otherwise they are long double or long double complex + +the long double version of a function is never chosen when +sizeof(double) == sizeof(long double) +(but the return type is set correctly with gcc) +*/ + +#include +#include + +#define __IS_FP(x) (sizeof((x)+1ULL) == sizeof((x)+1.0f)) +#define __IS_CX(x) (__IS_FP(x) && sizeof(x) == sizeof((x)+I)) +#define __IS_REAL(x) (__IS_FP(x) && 2*sizeof(x) == sizeof((x)+I)) + +#define __FLT(x) (__IS_REAL(x) && sizeof(x) == sizeof(float)) +#define __LDBL(x) (__IS_REAL(x) && sizeof(x) == sizeof(long double) && sizeof(long double) != sizeof(double)) + +#define __FLTCX(x) (__IS_CX(x) && sizeof(x) == sizeof(float complex)) +#define __DBLCX(x) (__IS_CX(x) && sizeof(x) == sizeof(double complex)) +#define __LDBLCX(x) (__IS_CX(x) && sizeof(x) == sizeof(long double complex) && sizeof(long double) != sizeof(double)) + +/* return type */ + +#ifdef __GNUC__ +/* +the result must be casted to the right type +(otherwise the result type is determined by the conversion +rules applied to all the function return types so it is long +double or long double complex except for integral functions) + +this cannot be done in c99, so the typeof gcc extension is +used and that the type of ?: depends on wether an operand is +a null pointer constant or not +(in c11 _Generic can be used) + +the c arguments below must be integer constant expressions +so they can be in null pointer constants +(__IS_FP above was carefully chosen this way) +*/ +/* if c then t else void */ +#define __type1(c,t) __typeof__(*(0?(t*)0:(void*)!(c))) +/* if c then t1 else t2 */ +#define __type2(c,t1,t2) __typeof__(*(0?(__type1(c,t1)*)0:(__type1(!(c),t2)*)0)) +/* cast to double when x is integral, otherwise use typeof(x) */ +#define __RETCAST(x) ( \ + __type2(__IS_FP(x), __typeof__(x), double)) +/* 2 args case, should work for complex types (cpow) */ +#define __RETCAST_2(x, y) ( \ + __type2(__IS_FP(x) && __IS_FP(y), \ + __typeof__((x)+(y)), \ + __typeof__((x)+(y)+1.0))) +/* 3 args case (fma only) */ +#define __RETCAST_3(x, y, z) ( \ + __type2(__IS_FP(x) && __IS_FP(y) && __IS_FP(z), \ + __typeof__((x)+(y)+(z)), \ + __typeof__((x)+(y)+(z)+1.0))) +/* drop complex from the type of x */ +/* TODO: wrong when sizeof(long double)==sizeof(double) */ +#define __RETCAST_REAL(x) ( \ + __type2(__IS_FP(x) && sizeof((x)+I) == sizeof(float complex), float, \ + __type2(sizeof((x)+1.0+I) == sizeof(double complex), double, \ + long double))) +/* add complex to the type of x */ +#define __RETCAST_CX(x) (__typeof__(__RETCAST(x)0+I)) +#else +#define __RETCAST(x) +#define __RETCAST_2(x, y) +#define __RETCAST_3(x, y, z) +#define __RETCAST_REAL(x) +#define __RETCAST_CX(x) +#endif + +/* function selection */ + +#define __tg_real_nocast(fun, x) ( \ + __FLT(x) ? fun ## f (x) : \ + __LDBL(x) ? fun ## l (x) : \ + fun(x) ) + +#define __tg_real(fun, x) (__RETCAST(x)__tg_real_nocast(fun, x)) + +#define __tg_real_2_1(fun, x, y) (__RETCAST(x)( \ + __FLT(x) ? fun ## f (x, y) : \ + __LDBL(x) ? fun ## l (x, y) : \ + fun(x, y) )) + +#define __tg_real_2(fun, x, y) (__RETCAST_2(x, y)( \ + __FLT(x) && __FLT(y) ? fun ## f (x, y) : \ + __LDBL((x)+(y)) ? fun ## l (x, y) : \ + fun(x, y) )) + +#define __tg_complex(fun, x) (__RETCAST_CX(x)( \ + __FLTCX((x)+I) && __IS_FP(x) ? fun ## f (x) : \ + __LDBLCX((x)+I) ? fun ## l (x) : \ + fun(x) )) + +#define __tg_complex_retreal(fun, x) (__RETCAST_REAL(x)( \ + __FLTCX((x)+I) && __IS_FP(x) ? fun ## f (x) : \ + __LDBLCX((x)+I) ? fun ## l (x) : \ + fun(x) )) + +#define __tg_real_complex(fun, x) (__RETCAST(x)( \ + __FLTCX(x) ? c ## fun ## f (x) : \ + __DBLCX(x) ? c ## fun (x) : \ + __LDBLCX(x) ? c ## fun ## l (x) : \ + __FLT(x) ? fun ## f (x) : \ + __LDBL(x) ? fun ## l (x) : \ + fun(x) )) + +/* special cases */ + +#define __tg_real_remquo(x, y, z) (__RETCAST_2(x, y)( \ + __FLT(x) && __FLT(y) ? remquof(x, y, z) : \ + __LDBL((x)+(y)) ? remquol(x, y, z) : \ + remquo(x, y, z) )) + +#define __tg_real_fma(x, y, z) (__RETCAST_3(x, y, z)( \ + __FLT(x) && __FLT(y) && __FLT(z) ? fmaf(x, y, z) : \ + __LDBL((x)+(y)+(z)) ? fmal(x, y, z) : \ + fma(x, y, z) )) + +#define __tg_real_complex_pow(x, y) (__RETCAST_2(x, y)( \ + __FLTCX((x)+(y)) && __IS_FP(x) && __IS_FP(y) ? cpowf(x, y) : \ + __FLTCX((x)+(y)) ? cpow(x, y) : \ + __DBLCX((x)+(y)) ? cpow(x, y) : \ + __LDBLCX((x)+(y)) ? cpowl(x, y) : \ + __FLT(x) && __FLT(y) ? powf(x, y) : \ + __LDBL((x)+(y)) ? powl(x, y) : \ + pow(x, y) )) + +#define __tg_real_complex_fabs(x) (__RETCAST_REAL(x)( \ + __FLTCX(x) ? cabsf(x) : \ + __DBLCX(x) ? cabs(x) : \ + __LDBLCX(x) ? cabsl(x) : \ + __FLT(x) ? fabsf(x) : \ + __LDBL(x) ? fabsl(x) : \ + fabs(x) )) + +/* suppress any macros in math.h or complex.h */ + +#undef acos +#undef acosh +#undef asin +#undef asinh +#undef atan +#undef atan2 +#undef atanh +#undef carg +#undef cbrt +#undef ceil +#undef cimag +#undef conj +#undef copysign +#undef cos +#undef cosh +#undef cproj +#undef creal +#undef erf +#undef erfc +#undef exp +#undef exp2 +#undef expm1 +#undef fabs +#undef fdim +#undef floor +#undef fma +#undef fmax +#undef fmin +#undef fmod +#undef frexp +#undef hypot +#undef ilogb +#undef ldexp +#undef lgamma +#undef llrint +#undef llround +#undef log +#undef log10 +#undef log1p +#undef log2 +#undef logb +#undef lrint +#undef lround +#undef nearbyint +#undef nextafter +#undef nexttoward +#undef pow +#undef remainder +#undef remquo +#undef rint +#undef round +#undef scalbln +#undef scalbn +#undef sin +#undef sinh +#undef sqrt +#undef tan +#undef tanh +#undef tgamma +#undef trunc + +/* tg functions */ + +#define acos(x) __tg_real_complex(acos, (x)) +#define acosh(x) __tg_real_complex(acosh, (x)) +#define asin(x) __tg_real_complex(asin, (x)) +#define asinh(x) __tg_real_complex(asinh, (x)) +#define atan(x) __tg_real_complex(atan, (x)) +#define atan2(x,y) __tg_real_2(atan2, (x), (y)) +#define atanh(x) __tg_real_complex(atanh, (x)) +#define carg(x) __tg_complex_retreal(carg, (x)) +#define cbrt(x) __tg_real(cbrt, (x)) +#define ceil(x) __tg_real(ceil, (x)) +#define cimag(x) __tg_complex_retreal(cimag, (x)) +#define conj(x) __tg_complex(conj, (x)) +#define copysign(x,y) __tg_real_2(copysign, (x), (y)) +#define cos(x) __tg_real_complex(cos, (x)) +#define cosh(x) __tg_real_complex(cosh, (x)) +#define cproj(x) __tg_complex(cproj, (x)) +#define creal(x) __tg_complex_retreal(creal, (x)) +#define erf(x) __tg_real(erf, (x)) +#define erfc(x) __tg_real(erfc, (x)) +#define exp(x) __tg_real_complex(exp, (x)) +#define exp2(x) __tg_real(exp2, (x)) +#define expm1(x) __tg_real(expm1, (x)) +#define fabs(x) __tg_real_complex_fabs(x) +#define fdim(x,y) __tg_real_2(fdim, (x), (y)) +#define floor(x) __tg_real(floor, (x)) +#define fma(x,y,z) __tg_real_fma((x), (y), (z)) +#define fmax(x,y) __tg_real_2(fmax, (x), (y)) +#define fmin(x,y) __tg_real_2(fmin, (x), (y)) +#define fmod(x,y) __tg_real_2(fmod, (x), (y)) +#define frexp(x,y) __tg_real_2_1(frexp, (x), (y)) +#define hypot(x,y) __tg_real_2(hypot, (x), (y)) +#define ilogb(x) __tg_real_nocast(ilogb, (x)) +#define ldexp(x,y) __tg_real_2_1(ldexp, (x), (y)) +#define lgamma(x) __tg_real(lgamma, (x)) +#define llrint(x) __tg_real_nocast(llrint, (x)) +#define llround(x) __tg_real_nocast(llround, (x)) +#define log(x) __tg_real_complex(log, (x)) +#define log10(x) __tg_real(log10, (x)) +#define log1p(x) __tg_real(log1p, (x)) +#define log2(x) __tg_real(log2, (x)) +#define logb(x) __tg_real(logb, (x)) +#define lrint(x) __tg_real_nocast(lrint, (x)) +#define lround(x) __tg_real_nocast(lround, (x)) +#define nearbyint(x) __tg_real(nearbyint, (x)) +#define nextafter(x,y) __tg_real_2(nextafter, (x), (y)) +#define nexttoward(x,y) __tg_real_2(nexttoward, (x), (y)) +#define pow(x,y) __tg_real_complex_pow((x), (y)) +#define remainder(x,y) __tg_real_2(remainder, (x), (y)) +#define remquo(x,y,z) __tg_real_remquo((x), (y), (z)) +#define rint(x) __tg_real(rint, (x)) +#define round(x) __tg_real(round, (x)) +#define scalbln(x,y) __tg_real_2_1(scalbln, (x), (y)) +#define scalbn(x,y) __tg_real_2_1(scalbn, (x), (y)) +#define sin(x) __tg_real_complex(sin, (x)) +#define sinh(x) __tg_real_complex(sinh, (x)) +#define sqrt(x) __tg_real_complex(sqrt, (x)) +#define tan(x) __tg_real_complex(tan, (x)) +#define tanh(x) __tg_real_complex(tanh, (x)) +#define tgamma(x) __tg_real(tgamma, (x)) +#define trunc(x) __tg_real(trunc, (x)) + +#endif diff --git a/src/orca-libc/include/wchar.h b/src/orca-libc/include/wchar.h new file mode 100644 index 00000000..c3b6e5aa --- /dev/null +++ b/src/orca-libc/include/wchar.h @@ -0,0 +1,146 @@ +#ifndef _WCHAR_H +#define _WCHAR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_FILE +#define __NEED___isoc_va_list +#define __NEED_size_t +#define __NEED_wchar_t +#define __NEED_wint_t +#define __NEED_mbstate_t +#define __NEED_va_list +#define __NEED_wctype_t + +#include + +#if L'\0'-1 > 0 +#define WCHAR_MAX (0xffffffffu+L'\0') +#define WCHAR_MIN (0+L'\0') +#else +#define WCHAR_MAX (0x7fffffff+L'\0') +#define WCHAR_MIN (-1-0x7fffffff+L'\0') +#endif + +#ifdef __wasilibc_unmodified_upstream /* Use the compiler's definition of NULL */ +#if __cplusplus >= 201103L +#define NULL nullptr +#elif defined(__cplusplus) +#define NULL 0L +#else +#define NULL ((void*)0) +#endif +#else +#define __need_NULL +#include +#endif + +#undef WEOF +#define WEOF 0xffffffffU + +wchar_t *wcscpy (wchar_t *__restrict, const wchar_t *__restrict); +wchar_t *wcsncpy (wchar_t *__restrict, const wchar_t *__restrict, size_t); + +wchar_t *wcscat (wchar_t *__restrict, const wchar_t *__restrict); +wchar_t *wcsncat (wchar_t *__restrict, const wchar_t *__restrict, size_t); + +int wcscmp (const wchar_t *, const wchar_t *); +int wcsncmp (const wchar_t *, const wchar_t *, size_t); + +int wcscoll(const wchar_t *, const wchar_t *); +size_t wcsxfrm (wchar_t *__restrict, const wchar_t *__restrict, size_t); + +wchar_t *wcschr (const wchar_t *, wchar_t); +wchar_t *wcsrchr (const wchar_t *, wchar_t); + +size_t wcscspn (const wchar_t *, const wchar_t *); +size_t wcsspn (const wchar_t *, const wchar_t *); +wchar_t *wcspbrk (const wchar_t *, const wchar_t *); + +wchar_t *wcstok (wchar_t *__restrict, const wchar_t *__restrict, wchar_t **__restrict); + +size_t wcslen (const wchar_t *); + +wchar_t *wcsstr (const wchar_t *__restrict, const wchar_t *__restrict); +wchar_t *wcswcs (const wchar_t *, const wchar_t *); + +wchar_t *wmemchr (const wchar_t *, wchar_t, size_t); +int wmemcmp (const wchar_t *, const wchar_t *, size_t); +wchar_t *wmemcpy (wchar_t *__restrict, const wchar_t *__restrict, size_t); +wchar_t *wmemmove (wchar_t *, const wchar_t *, size_t); +wchar_t *wmemset (wchar_t *, wchar_t, size_t); + +wint_t btowc (int); +int wctob (wint_t); + +int mbsinit (const mbstate_t *); +size_t mbrtowc (wchar_t *__restrict, const char *__restrict, size_t, mbstate_t *__restrict); +size_t wcrtomb (char *__restrict, wchar_t, mbstate_t *__restrict); + +size_t mbrlen (const char *__restrict, size_t, mbstate_t *__restrict); + +size_t mbsrtowcs (wchar_t *__restrict, const char **__restrict, size_t, mbstate_t *__restrict); +size_t wcsrtombs (char *__restrict, const wchar_t **__restrict, size_t, mbstate_t *__restrict); + +float wcstof (const wchar_t *__restrict, wchar_t **__restrict); +double wcstod (const wchar_t *__restrict, wchar_t **__restrict); +long double wcstold (const wchar_t *__restrict, wchar_t **__restrict); + +long wcstol (const wchar_t *__restrict, wchar_t **__restrict, int); +unsigned long wcstoul (const wchar_t *__restrict, wchar_t **__restrict, int); + +long long wcstoll (const wchar_t *__restrict, wchar_t **__restrict, int); +unsigned long long wcstoull (const wchar_t *__restrict, wchar_t **__restrict, int); + + +int swprintf (wchar_t *__restrict, size_t, const wchar_t *__restrict, ...); +int vswprintf (wchar_t *__restrict, size_t, const wchar_t *__restrict, __isoc_va_list); + +int swscanf (const wchar_t *__restrict, const wchar_t *__restrict, ...); +int vswscanf (const wchar_t *__restrict, const wchar_t *__restrict, __isoc_va_list); + +#undef iswdigit + +size_t mbsnrtowcs(wchar_t *__restrict, const char **__restrict, size_t, size_t, mbstate_t *__restrict); +size_t wcsnrtombs(char *__restrict, const wchar_t **__restrict, size_t, size_t, mbstate_t *__restrict); +wchar_t *wcsdup(const wchar_t *); +size_t wcsnlen (const wchar_t *, size_t); +wchar_t *wcpcpy (wchar_t *__restrict, const wchar_t *__restrict); +wchar_t *wcpncpy (wchar_t *__restrict, const wchar_t *__restrict, size_t); +int wcscasecmp(const wchar_t *, const wchar_t *); +int wcsncasecmp(const wchar_t *, const wchar_t *, size_t); + +int wcwidth (wchar_t); +int wcswidth (const wchar_t *, size_t); +int iswalnum(wint_t); +int iswalpha(wint_t); +int iswblank(wint_t); +int iswcntrl(wint_t); +int iswdigit(wint_t); +int iswgraph(wint_t); +int iswlower(wint_t); +int iswprint(wint_t); +int iswpunct(wint_t); +int iswspace(wint_t); +int iswupper(wint_t); +int iswxdigit(wint_t); +int iswctype(wint_t, wctype_t); +wint_t towlower(wint_t); +wint_t towupper(wint_t); +wctype_t wctype(const char *); + +#ifndef __cplusplus +#undef iswdigit +#define iswdigit(a) (0 ? iswdigit(a) : ((unsigned)(a)-'0') < 10) +#endif + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/orca-libc/include/wctype.h b/src/orca-libc/include/wctype.h new file mode 100644 index 00000000..8e64ea78 --- /dev/null +++ b/src/orca-libc/include/wctype.h @@ -0,0 +1,50 @@ +#ifndef _WCTYPE_H +#define _WCTYPE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define __NEED_wint_t +#define __NEED_wctype_t + +#include + +typedef const int * wctrans_t; + +#undef WEOF +#define WEOF 0xffffffffU + +#undef iswdigit + +int iswalnum(wint_t); +int iswalpha(wint_t); +int iswblank(wint_t); +int iswcntrl(wint_t); +int iswdigit(wint_t); +int iswgraph(wint_t); +int iswlower(wint_t); +int iswprint(wint_t); +int iswpunct(wint_t); +int iswspace(wint_t); +int iswupper(wint_t); +int iswxdigit(wint_t); +int iswctype(wint_t, wctype_t); +wint_t towctrans(wint_t, wctrans_t); +wint_t towlower(wint_t); +wint_t towupper(wint_t); +wctrans_t wctrans(const char *); +wctype_t wctype(const char *); + +#ifndef __cplusplus +#undef iswdigit +#define iswdigit(a) (0 ? iswdigit(a) : ((unsigned)(a)-'0') < 10) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/orca-libc/notes.md b/src/orca-libc/notes.md new file mode 100644 index 00000000..96364d17 --- /dev/null +++ b/src/orca-libc/notes.md @@ -0,0 +1,23 @@ + +To Review: + +- `exit`, `assert` + +Should be included but missing or incomplete: + +- `malloc` --> replace with our modified `dlmalloc` +- in `stdio.h`: `scanf` family +- in `stdlib.h`: `atof`, `strtol` family + +Missing or incomplete, maybe included later: + +- `stdatomic.h` (when we have atomics) +- `threads.h` (when we have threading) +- `time.h` (except things depending on locale or setting time) + +Excluded APIs: + +- `locale.h` +- `setjmp.h` +- `signal.h` +- File IO, `wchar`, `uchar` diff --git a/src/orca-libc/src/complex/__cexp.c b/src/orca-libc/src/complex/__cexp.c new file mode 100644 index 00000000..003d20af --- /dev/null +++ b/src/orca-libc/src/complex/__cexp.c @@ -0,0 +1,87 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_exp.c */ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "complex_impl.h" + +static const uint32_t k = 1799; /* constant for reduction */ +static const double kln2 = 1246.97177782734161156; /* k * ln2 */ + +/* + * Compute exp(x), scaled to avoid spurious overflow. An exponent is + * returned separately in 'expt'. + * + * Input: ln(DBL_MAX) <= x < ln(2 * DBL_MAX / DBL_MIN_DENORM) ~= 1454.91 + * Output: 2**1023 <= y < 2**1024 + */ +static double __frexp_exp(double x, int *expt) +{ + double exp_x; + uint32_t hx; + + /* + * We use exp(x) = exp(x - kln2) * 2**k, carefully chosen to + * minimize |exp(kln2) - 2**k|. We also scale the exponent of + * exp_x to MAX_EXP so that the result can be multiplied by + * a tiny number without losing accuracy due to denormalization. + */ + exp_x = exp(x - kln2); + GET_HIGH_WORD(hx, exp_x); + *expt = (hx >> 20) - (0x3ff + 1023) + k; + SET_HIGH_WORD(exp_x, (hx & 0xfffff) | ((0x3ff + 1023) << 20)); + return exp_x; +} + +/* + * __ldexp_cexp(x, expt) compute exp(x) * 2**expt. + * It is intended for large arguments (real part >= ln(DBL_MAX)) + * where care is needed to avoid overflow. + * + * The present implementation is narrowly tailored for our hyperbolic and + * exponential functions. We assume expt is small (0 or -1), and the caller + * has filtered out very large x, for which overflow would be inevitable. + */ +double complex __ldexp_cexp(double complex z, int expt) +{ + double x, y, exp_x, scale1, scale2; + int ex_expt, half_expt; + + x = creal(z); + y = cimag(z); + exp_x = __frexp_exp(x, &ex_expt); + expt += ex_expt; + + /* + * Arrange so that scale1 * scale2 == 2**expt. We use this to + * compensate for scalbn being horrendously slow. + */ + half_expt = expt / 2; + INSERT_WORDS(scale1, (0x3ff + half_expt) << 20, 0); + half_expt = expt - half_expt; + INSERT_WORDS(scale2, (0x3ff + half_expt) << 20, 0); + + return CMPLX(cos(y) * exp_x * scale1 * scale2, sin(y) * exp_x * scale1 * scale2); +} diff --git a/src/orca-libc/src/complex/__cexpf.c b/src/orca-libc/src/complex/__cexpf.c new file mode 100644 index 00000000..ee5ff2bc --- /dev/null +++ b/src/orca-libc/src/complex/__cexpf.c @@ -0,0 +1,68 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_expf.c */ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "complex_impl.h" + +static const uint32_t k = 235; /* constant for reduction */ +static const float kln2 = 162.88958740F; /* k * ln2 */ + +/* + * See __cexp.c for details. + * + * Input: ln(FLT_MAX) <= x < ln(2 * FLT_MAX / FLT_MIN_DENORM) ~= 192.7 + * Output: 2**127 <= y < 2**128 + */ +static float __frexp_expf(float x, int *expt) +{ + float exp_x; + uint32_t hx; + + exp_x = expf(x - kln2); + GET_FLOAT_WORD(hx, exp_x); + *expt = (hx >> 23) - (0x7f + 127) + k; + SET_FLOAT_WORD(exp_x, (hx & 0x7fffff) | ((0x7f + 127) << 23)); + return exp_x; +} + +float complex __ldexp_cexpf(float complex z, int expt) +{ + float x, y, exp_x, scale1, scale2; + int ex_expt, half_expt; + + x = crealf(z); + y = cimagf(z); + exp_x = __frexp_expf(x, &ex_expt); + expt += ex_expt; + + half_expt = expt / 2; + SET_FLOAT_WORD(scale1, (0x7f + half_expt) << 23); + half_expt = expt - half_expt; + SET_FLOAT_WORD(scale2, (0x7f + half_expt) << 23); + + return CMPLXF(cosf(y) * exp_x * scale1 * scale2, + sinf(y) * exp_x * scale1 * scale2); +} diff --git a/src/orca-libc/src/complex/cabs.c b/src/orca-libc/src/complex/cabs.c new file mode 100644 index 00000000..c5ad58ab --- /dev/null +++ b/src/orca-libc/src/complex/cabs.c @@ -0,0 +1,6 @@ +#include "complex_impl.h" + +double cabs(double complex z) +{ + return hypot(creal(z), cimag(z)); +} diff --git a/src/orca-libc/src/complex/cabsf.c b/src/orca-libc/src/complex/cabsf.c new file mode 100644 index 00000000..619f28d3 --- /dev/null +++ b/src/orca-libc/src/complex/cabsf.c @@ -0,0 +1,6 @@ +#include "complex_impl.h" + +float cabsf(float complex z) +{ + return hypotf(crealf(z), cimagf(z)); +} diff --git a/src/orca-libc/src/complex/cabsl.c b/src/orca-libc/src/complex/cabsl.c new file mode 100644 index 00000000..d37e3f2e --- /dev/null +++ b/src/orca-libc/src/complex/cabsl.c @@ -0,0 +1,13 @@ +#include "complex_impl.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double cabsl(long double complex z) +{ + return cabs(z); +} +#else +long double cabsl(long double complex z) +{ + return hypotl(creall(z), cimagl(z)); +} +#endif diff --git a/src/orca-libc/src/complex/cacos.c b/src/orca-libc/src/complex/cacos.c new file mode 100644 index 00000000..c39d257b --- /dev/null +++ b/src/orca-libc/src/complex/cacos.c @@ -0,0 +1,11 @@ +#include "complex_impl.h" + +// FIXME: Hull et al. "Implementing the complex arcsine and arccosine functions using exception handling" 1997 + +/* acos(z) = pi/2 - asin(z) */ + +double complex cacos(double complex z) +{ + z = casin(z); + return CMPLX(M_PI_2 - creal(z), -cimag(z)); +} diff --git a/src/orca-libc/src/complex/cacosf.c b/src/orca-libc/src/complex/cacosf.c new file mode 100644 index 00000000..ed8acf0f --- /dev/null +++ b/src/orca-libc/src/complex/cacosf.c @@ -0,0 +1,11 @@ +#include "complex_impl.h" + +// FIXME + +static const float float_pi_2 = M_PI_2; + +float complex cacosf(float complex z) +{ + z = casinf(z); + return CMPLXF(float_pi_2 - crealf(z), -cimagf(z)); +} diff --git a/src/orca-libc/src/complex/cacosh.c b/src/orca-libc/src/complex/cacosh.c new file mode 100644 index 00000000..76127f75 --- /dev/null +++ b/src/orca-libc/src/complex/cacosh.c @@ -0,0 +1,12 @@ +#include "complex_impl.h" + +/* acosh(z) = i acos(z) */ + +double complex cacosh(double complex z) +{ + int zineg = signbit(cimag(z)); + + z = cacos(z); + if (zineg) return CMPLX(cimag(z), -creal(z)); + else return CMPLX(-cimag(z), creal(z)); +} diff --git a/src/orca-libc/src/complex/cacoshf.c b/src/orca-libc/src/complex/cacoshf.c new file mode 100644 index 00000000..8bd80581 --- /dev/null +++ b/src/orca-libc/src/complex/cacoshf.c @@ -0,0 +1,10 @@ +#include "complex_impl.h" + +float complex cacoshf(float complex z) +{ + int zineg = signbit(cimagf(z)); + + z = cacosf(z); + if (zineg) return CMPLXF(cimagf(z), -crealf(z)); + else return CMPLXF(-cimagf(z), crealf(z)); +} diff --git a/src/orca-libc/src/complex/cacoshl.c b/src/orca-libc/src/complex/cacoshl.c new file mode 100644 index 00000000..3a284be9 --- /dev/null +++ b/src/orca-libc/src/complex/cacoshl.c @@ -0,0 +1,17 @@ +#include "complex_impl.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex cacoshl(long double complex z) +{ + return cacosh(z); +} +#else +long double complex cacoshl(long double complex z) +{ + int zineg = signbit(cimagl(z)); + + z = cacosl(z); + if (zineg) return CMPLXL(cimagl(z), -creall(z)); + else return CMPLXL(-cimagl(z), creall(z)); +} +#endif diff --git a/src/orca-libc/src/complex/cacosl.c b/src/orca-libc/src/complex/cacosl.c new file mode 100644 index 00000000..cc20dcd7 --- /dev/null +++ b/src/orca-libc/src/complex/cacosl.c @@ -0,0 +1,16 @@ +#include "complex_impl.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex cacosl(long double complex z) +{ + return cacos(z); +} +#else +// FIXME +#define PI_2 1.57079632679489661923132169163975144L +long double complex cacosl(long double complex z) +{ + z = casinl(z); + return CMPLXL(PI_2 - creall(z), -cimagl(z)); +} +#endif diff --git a/src/orca-libc/src/complex/carg.c b/src/orca-libc/src/complex/carg.c new file mode 100644 index 00000000..dfe9b97a --- /dev/null +++ b/src/orca-libc/src/complex/carg.c @@ -0,0 +1,6 @@ +#include "complex_impl.h" + +double carg(double complex z) +{ + return atan2(cimag(z), creal(z)); +} diff --git a/src/orca-libc/src/complex/cargf.c b/src/orca-libc/src/complex/cargf.c new file mode 100644 index 00000000..9a6c19b6 --- /dev/null +++ b/src/orca-libc/src/complex/cargf.c @@ -0,0 +1,6 @@ +#include "complex_impl.h" + +float cargf(float complex z) +{ + return atan2f(cimagf(z), crealf(z)); +} diff --git a/src/orca-libc/src/complex/cargl.c b/src/orca-libc/src/complex/cargl.c new file mode 100644 index 00000000..88f95f96 --- /dev/null +++ b/src/orca-libc/src/complex/cargl.c @@ -0,0 +1,13 @@ +#include "complex_impl.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double cargl(long double complex z) +{ + return carg(z); +} +#else +long double cargl(long double complex z) +{ + return atan2l(cimagl(z), creall(z)); +} +#endif diff --git a/src/orca-libc/src/complex/casin.c b/src/orca-libc/src/complex/casin.c new file mode 100644 index 00000000..3244bebb --- /dev/null +++ b/src/orca-libc/src/complex/casin.c @@ -0,0 +1,17 @@ +#include "complex_impl.h" + +// FIXME + +/* asin(z) = -i log(i z + sqrt(1 - z*z)) */ + +double complex casin(double complex z) +{ + double complex w; + double x, y; + + x = creal(z); + y = cimag(z); + w = CMPLX(1.0 - (x - y)*(x + y), -2.0*x*y); + double complex r = clog(CMPLX(-y, x) + csqrt(w)); + return CMPLX(cimag(r), -creal(r)); +} diff --git a/src/orca-libc/src/complex/casinf.c b/src/orca-libc/src/complex/casinf.c new file mode 100644 index 00000000..2cda2f08 --- /dev/null +++ b/src/orca-libc/src/complex/casinf.c @@ -0,0 +1,15 @@ +#include "complex_impl.h" + +// FIXME + +float complex casinf(float complex z) +{ + float complex w; + float x, y; + + x = crealf(z); + y = cimagf(z); + w = CMPLXF(1.0 - (x - y)*(x + y), -2.0*x*y); + float complex r = clogf(CMPLXF(-y, x) + csqrtf(w)); + return CMPLXF(cimagf(r), -crealf(r)); +} diff --git a/src/orca-libc/src/complex/casinh.c b/src/orca-libc/src/complex/casinh.c new file mode 100644 index 00000000..50bf27ce --- /dev/null +++ b/src/orca-libc/src/complex/casinh.c @@ -0,0 +1,9 @@ +#include "complex_impl.h" + +/* asinh(z) = -i asin(i z) */ + +double complex casinh(double complex z) +{ + z = casin(CMPLX(-cimag(z), creal(z))); + return CMPLX(cimag(z), -creal(z)); +} diff --git a/src/orca-libc/src/complex/casinhf.c b/src/orca-libc/src/complex/casinhf.c new file mode 100644 index 00000000..93d82e5f --- /dev/null +++ b/src/orca-libc/src/complex/casinhf.c @@ -0,0 +1,7 @@ +#include "complex_impl.h" + +float complex casinhf(float complex z) +{ + z = casinf(CMPLXF(-cimagf(z), crealf(z))); + return CMPLXF(cimagf(z), -crealf(z)); +} diff --git a/src/orca-libc/src/complex/casinhl.c b/src/orca-libc/src/complex/casinhl.c new file mode 100644 index 00000000..68ba3ddf --- /dev/null +++ b/src/orca-libc/src/complex/casinhl.c @@ -0,0 +1,14 @@ +#include "complex_impl.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex casinhl(long double complex z) +{ + return casinh(z); +} +#else +long double complex casinhl(long double complex z) +{ + z = casinl(CMPLXL(-cimagl(z), creall(z))); + return CMPLXL(cimagl(z), -creall(z)); +} +#endif diff --git a/src/orca-libc/src/complex/casinl.c b/src/orca-libc/src/complex/casinl.c new file mode 100644 index 00000000..072adc45 --- /dev/null +++ b/src/orca-libc/src/complex/casinl.c @@ -0,0 +1,21 @@ +#include "complex_impl.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex casinl(long double complex z) +{ + return casin(z); +} +#else +// FIXME +long double complex casinl(long double complex z) +{ + long double complex w; + long double x, y; + + x = creall(z); + y = cimagl(z); + w = CMPLXL(1.0 - (x - y)*(x + y), -2.0*x*y); + long double complex r = clogl(CMPLXL(-y, x) + csqrtl(w)); + return CMPLXL(cimagl(r), -creall(r)); +} +#endif diff --git a/src/orca-libc/src/complex/catan.c b/src/orca-libc/src/complex/catan.c new file mode 100644 index 00000000..ccc2fb53 --- /dev/null +++ b/src/orca-libc/src/complex/catan.c @@ -0,0 +1,107 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/s_catan.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Complex circular arc tangent + * + * + * SYNOPSIS: + * + * double complex catan(); + * double complex z, w; + * + * w = catan (z); + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * 1 ( 2x ) + * Re w = - arctan(-----------) + k PI + * 2 ( 2 2) + * (1 - x - y ) + * + * ( 2 2) + * 1 (x + (y+1) ) + * Im w = - log(------------) + * 4 ( 2 2) + * (x + (y-1) ) + * + * Where k is an arbitrary integer. + * + * catan(z) = -i catanh(iz). + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 5900 1.3e-16 7.8e-18 + * IEEE -10,+10 30000 2.3e-15 8.5e-17 + * The check catan( ctan(z) ) = z, with |x| and |y| < PI/2, + * had peak relative error 1.5e-16, rms relative error + * 2.9e-17. See also clog(). + */ + +#include "complex_impl.h" + +#define MAXNUM 1.0e308 + +static const double DP1 = 3.14159265160560607910E0; +static const double DP2 = 1.98418714791870343106E-9; +static const double DP3 = 1.14423774522196636802E-17; + +static double _redupi(double x) +{ + double t; + long i; + + t = x/M_PI; + if (t >= 0.0) + t += 0.5; + else + t -= 0.5; + + i = t; /* the multiple */ + t = i; + t = ((x - t * DP1) - t * DP2) - t * DP3; + return t; +} + +double complex catan(double complex z) +{ + double complex w; + double a, t, x, x2, y; + + x = creal(z); + y = cimag(z); + + x2 = x * x; + a = 1.0 - x2 - (y * y); + + t = 0.5 * atan2(2.0 * x, a); + w = _redupi(t); + + t = y - 1.0; + a = x2 + (t * t); + + t = y + 1.0; + a = (x2 + t * t)/a; + w = CMPLX(w, 0.25 * log(a)); + return w; +} diff --git a/src/orca-libc/src/complex/catanf.c b/src/orca-libc/src/complex/catanf.c new file mode 100644 index 00000000..1d569f2d --- /dev/null +++ b/src/orca-libc/src/complex/catanf.c @@ -0,0 +1,105 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/s_catanf.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Complex circular arc tangent + * + * + * SYNOPSIS: + * + * float complex catanf(); + * float complex z, w; + * + * w = catanf( z ); + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * 1 ( 2x ) + * Re w = - arctan(-----------) + k PI + * 2 ( 2 2) + * (1 - x - y ) + * + * ( 2 2) + * 1 (x + (y+1) ) + * Im w = - log(------------) + * 4 ( 2 2) + * (x + (y-1) ) + * + * Where k is an arbitrary integer. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -10,+10 30000 2.3e-6 5.2e-8 + */ + +#include "complex_impl.h" + +#define MAXNUMF 1.0e38F + +static const double DP1 = 3.140625; +static const double DP2 = 9.67502593994140625E-4; +static const double DP3 = 1.509957990978376432E-7; + +static const float float_pi = M_PI; + +static float _redupif(float xx) +{ + float x, t; + long i; + + x = xx; + t = x/float_pi; + if (t >= 0.0f) + t += 0.5f; + else + t -= 0.5f; + + i = t; /* the multiple */ + t = i; + t = ((x - t * DP1) - t * DP2) - t * DP3; + return t; +} + +float complex catanf(float complex z) +{ + float complex w; + float a, t, x, x2, y; + + x = crealf(z); + y = cimagf(z); + + x2 = x * x; + a = 1.0f - x2 - (y * y); + + t = 0.5f * atan2f(2.0f * x, a); + w = _redupif(t); + + t = y - 1.0f; + a = x2 + (t * t); + + t = y + 1.0f; + a = (x2 + (t * t))/a; + w = CMPLXF(w, 0.25f * logf(a)); + return w; +} diff --git a/src/orca-libc/src/complex/catanh.c b/src/orca-libc/src/complex/catanh.c new file mode 100644 index 00000000..c324c7f2 --- /dev/null +++ b/src/orca-libc/src/complex/catanh.c @@ -0,0 +1,9 @@ +#include "complex_impl.h" + +/* atanh = -i atan(i z) */ + +double complex catanh(double complex z) +{ + z = catan(CMPLX(-cimag(z), creal(z))); + return CMPLX(cimag(z), -creal(z)); +} diff --git a/src/orca-libc/src/complex/catanhf.c b/src/orca-libc/src/complex/catanhf.c new file mode 100644 index 00000000..b0505f60 --- /dev/null +++ b/src/orca-libc/src/complex/catanhf.c @@ -0,0 +1,7 @@ +#include "complex_impl.h" + +float complex catanhf(float complex z) +{ + z = catanf(CMPLXF(-cimagf(z), crealf(z))); + return CMPLXF(cimagf(z), -crealf(z)); +} diff --git a/src/orca-libc/src/complex/catanhl.c b/src/orca-libc/src/complex/catanhl.c new file mode 100644 index 00000000..6025c414 --- /dev/null +++ b/src/orca-libc/src/complex/catanhl.c @@ -0,0 +1,14 @@ +#include "complex_impl.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex catanhl(long double complex z) +{ + return catanh(z); +} +#else +long double complex catanhl(long double complex z) +{ + z = catanl(CMPLXL(-cimagl(z), creall(z))); + return CMPLXL(cimagl(z), -creall(z)); +} +#endif diff --git a/src/orca-libc/src/complex/catanl.c b/src/orca-libc/src/complex/catanl.c new file mode 100644 index 00000000..e62526c0 --- /dev/null +++ b/src/orca-libc/src/complex/catanl.c @@ -0,0 +1,114 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/s_catanl.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Complex circular arc tangent + * + * + * SYNOPSIS: + * + * long double complex catanl(); + * long double complex z, w; + * + * w = catanl( z ); + * + * + * DESCRIPTION: + * + * If + * z = x + iy, + * + * then + * 1 ( 2x ) + * Re w = - arctan(-----------) + k PI + * 2 ( 2 2) + * (1 - x - y ) + * + * ( 2 2) + * 1 (x + (y+1) ) + * Im w = - log(------------) + * 4 ( 2 2) + * (x + (y-1) ) + * + * Where k is an arbitrary integer. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * DEC -10,+10 5900 1.3e-16 7.8e-18 + * IEEE -10,+10 30000 2.3e-15 8.5e-17 + * The check catan( ctan(z) ) = z, with |x| and |y| < PI/2, + * had peak relative error 1.5e-16, rms relative error + * 2.9e-17. See also clog(). + */ + +#include +#include +#include "complex_impl.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex catanl(long double complex z) +{ + return catan(z); +} +#else +static const long double PIL = 3.141592653589793238462643383279502884197169L; +static const long double DP1 = 3.14159265358979323829596852490908531763125L; +static const long double DP2 = 1.6667485837041756656403424829301998703007e-19L; +static const long double DP3 = 1.8830410776607851167459095484560349402753e-39L; + +static long double redupil(long double x) +{ + long double t; + long i; + + t = x / PIL; + if (t >= 0.0L) + t += 0.5L; + else + t -= 0.5L; + + i = t; /* the multiple */ + t = i; + t = ((x - t * DP1) - t * DP2) - t * DP3; + return t; +} + +long double complex catanl(long double complex z) +{ + long double complex w; + long double a, t, x, x2, y; + + x = creall(z); + y = cimagl(z); + + x2 = x * x; + a = 1.0L - x2 - (y * y); + + t = atan2l(2.0L * x, a) * 0.5L; + w = redupil(t); + + t = y - 1.0L; + a = x2 + (t * t); + + t = y + 1.0L; + a = (x2 + (t * t)) / a; + w = CMPLXF(w, 0.25L * logl(a)); + return w; +} +#endif diff --git a/src/orca-libc/src/complex/ccos.c b/src/orca-libc/src/complex/ccos.c new file mode 100644 index 00000000..f32e1fad --- /dev/null +++ b/src/orca-libc/src/complex/ccos.c @@ -0,0 +1,8 @@ +#include "complex_impl.h" + +/* cos(z) = cosh(i z) */ + +double complex ccos(double complex z) +{ + return ccosh(CMPLX(-cimag(z), creal(z))); +} diff --git a/src/orca-libc/src/complex/ccosf.c b/src/orca-libc/src/complex/ccosf.c new file mode 100644 index 00000000..490be9b3 --- /dev/null +++ b/src/orca-libc/src/complex/ccosf.c @@ -0,0 +1,6 @@ +#include "complex_impl.h" + +float complex ccosf(float complex z) +{ + return ccoshf(CMPLXF(-cimagf(z), crealf(z))); +} diff --git a/src/orca-libc/src/complex/ccosh.c b/src/orca-libc/src/complex/ccosh.c new file mode 100644 index 00000000..c995da7b --- /dev/null +++ b/src/orca-libc/src/complex/ccosh.c @@ -0,0 +1,140 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_ccosh.c */ +/*- + * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Hyperbolic cosine of a complex argument z = x + i y. + * + * cosh(z) = cosh(x+iy) + * = cosh(x) cos(y) + i sinh(x) sin(y). + * + * Exceptional values are noted in the comments within the source code. + * These values and the return value were taken from n1124.pdf. + */ + +#include "complex_impl.h" + +static const double huge = 0x1p1023; + +double complex ccosh(double complex z) +{ + double x, y, h; + int32_t hx, hy, ix, iy, lx, ly; + + x = creal(z); + y = cimag(z); + + EXTRACT_WORDS(hx, lx, x); + EXTRACT_WORDS(hy, ly, y); + + ix = 0x7fffffff & hx; + iy = 0x7fffffff & hy; + + /* Handle the nearly-non-exceptional cases where x and y are finite. */ + if (ix < 0x7ff00000 && iy < 0x7ff00000) { + if ((iy | ly) == 0) + return CMPLX(cosh(x), x * y); + if (ix < 0x40360000) /* small x: normal case */ + return CMPLX(cosh(x) * cos(y), sinh(x) * sin(y)); + + /* |x| >= 22, so cosh(x) ~= exp(|x|) */ + if (ix < 0x40862e42) { + /* x < 710: exp(|x|) won't overflow */ + h = exp(fabs(x)) * 0.5; + return CMPLX(h * cos(y), copysign(h, x) * sin(y)); + } else if (ix < 0x4096bbaa) { + /* x < 1455: scale to avoid overflow */ + z = __ldexp_cexp(CMPLX(fabs(x), y), -1); + return CMPLX(creal(z), cimag(z) * copysign(1, x)); + } else { + /* x >= 1455: the result always overflows */ + h = huge * x; + return CMPLX(h * h * cos(y), h * sin(y)); + } + } + + /* + * cosh(+-0 +- I Inf) = dNaN + I sign(d(+-0, dNaN))0. + * The sign of 0 in the result is unspecified. Choice = normally + * the same as dNaN. Raise the invalid floating-point exception. + * + * cosh(+-0 +- I NaN) = d(NaN) + I sign(d(+-0, NaN))0. + * The sign of 0 in the result is unspecified. Choice = normally + * the same as d(NaN). + */ + if ((ix | lx) == 0 && iy >= 0x7ff00000) + return CMPLX(y - y, copysign(0, x * (y - y))); + + /* + * cosh(+-Inf +- I 0) = +Inf + I (+-)(+-)0. + * + * cosh(NaN +- I 0) = d(NaN) + I sign(d(NaN, +-0))0. + * The sign of 0 in the result is unspecified. + */ + if ((iy | ly) == 0 && ix >= 0x7ff00000) { + if (((hx & 0xfffff) | lx) == 0) + return CMPLX(x * x, copysign(0, x) * y); + return CMPLX(x * x, copysign(0, (x + x) * y)); + } + + /* + * cosh(x +- I Inf) = dNaN + I dNaN. + * Raise the invalid floating-point exception for finite nonzero x. + * + * cosh(x + I NaN) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception for finite + * nonzero x. Choice = don't raise (except for signaling NaNs). + */ + if (ix < 0x7ff00000 && iy >= 0x7ff00000) + return CMPLX(y - y, x * (y - y)); + + /* + * cosh(+-Inf + I NaN) = +Inf + I d(NaN). + * + * cosh(+-Inf +- I Inf) = +Inf + I dNaN. + * The sign of Inf in the result is unspecified. Choice = always +. + * Raise the invalid floating-point exception. + * + * cosh(+-Inf + I y) = +Inf cos(y) +- I Inf sin(y) + */ + if (ix >= 0x7ff00000 && ((hx & 0xfffff) | lx) == 0) { + if (iy >= 0x7ff00000) + return CMPLX(x * x, x * (y - y)); + return CMPLX((x * x) * cos(y), x * sin(y)); + } + + /* + * cosh(NaN + I NaN) = d(NaN) + I d(NaN). + * + * cosh(NaN +- I Inf) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception. + * Choice = raise. + * + * cosh(NaN + I y) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception for finite + * nonzero y. Choice = don't raise (except for signaling NaNs). + */ + return CMPLX((x * x) * (y - y), (x + x) * (y - y)); +} diff --git a/src/orca-libc/src/complex/ccoshf.c b/src/orca-libc/src/complex/ccoshf.c new file mode 100644 index 00000000..189ce946 --- /dev/null +++ b/src/orca-libc/src/complex/ccoshf.c @@ -0,0 +1,90 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_ccoshf.c */ +/*- + * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Hyperbolic cosine of a complex argument. See s_ccosh.c for details. + */ + +#include "complex_impl.h" + +static const float huge = 0x1p127; + +float complex ccoshf(float complex z) +{ + float x, y, h; + int32_t hx, hy, ix, iy; + + x = crealf(z); + y = cimagf(z); + + GET_FLOAT_WORD(hx, x); + GET_FLOAT_WORD(hy, y); + + ix = 0x7fffffff & hx; + iy = 0x7fffffff & hy; + + if (ix < 0x7f800000 && iy < 0x7f800000) { + if (iy == 0) + return CMPLXF(coshf(x), x * y); + if (ix < 0x41100000) /* small x: normal case */ + return CMPLXF(coshf(x) * cosf(y), sinhf(x) * sinf(y)); + + /* |x| >= 9, so cosh(x) ~= exp(|x|) */ + if (ix < 0x42b17218) { + /* x < 88.7: expf(|x|) won't overflow */ + h = expf(fabsf(x)) * 0.5f; + return CMPLXF(h * cosf(y), copysignf(h, x) * sinf(y)); + } else if (ix < 0x4340b1e7) { + /* x < 192.7: scale to avoid overflow */ + z = __ldexp_cexpf(CMPLXF(fabsf(x), y), -1); + return CMPLXF(crealf(z), cimagf(z) * copysignf(1, x)); + } else { + /* x >= 192.7: the result always overflows */ + h = huge * x; + return CMPLXF(h * h * cosf(y), h * sinf(y)); + } + } + + if (ix == 0 && iy >= 0x7f800000) + return CMPLXF(y - y, copysignf(0, x * (y - y))); + + if (iy == 0 && ix >= 0x7f800000) { + if ((hx & 0x7fffff) == 0) + return CMPLXF(x * x, copysignf(0, x) * y); + return CMPLXF(x * x, copysignf(0, (x + x) * y)); + } + + if (ix < 0x7f800000 && iy >= 0x7f800000) + return CMPLXF(y - y, x * (y - y)); + + if (ix >= 0x7f800000 && (hx & 0x7fffff) == 0) { + if (iy >= 0x7f800000) + return CMPLXF(x * x, x * (y - y)); + return CMPLXF((x * x) * cosf(y), x * sinf(y)); + } + + return CMPLXF((x * x) * (y - y), (x + x) * (y - y)); +} diff --git a/src/orca-libc/src/complex/ccoshl.c b/src/orca-libc/src/complex/ccoshl.c new file mode 100644 index 00000000..ffb4d8a1 --- /dev/null +++ b/src/orca-libc/src/complex/ccoshl.c @@ -0,0 +1,7 @@ +#include "complex_impl.h" + +//FIXME +long double complex ccoshl(long double complex z) +{ + return ccosh(z); +} diff --git a/src/orca-libc/src/complex/ccosl.c b/src/orca-libc/src/complex/ccosl.c new file mode 100644 index 00000000..2530006b --- /dev/null +++ b/src/orca-libc/src/complex/ccosl.c @@ -0,0 +1,13 @@ +#include "complex_impl.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex ccosl(long double complex z) +{ + return ccos(z); +} +#else +long double complex ccosl(long double complex z) +{ + return ccoshl(CMPLXL(-cimagl(z), creall(z))); +} +#endif diff --git a/src/orca-libc/src/complex/cexp.c b/src/orca-libc/src/complex/cexp.c new file mode 100644 index 00000000..7fb489bb --- /dev/null +++ b/src/orca-libc/src/complex/cexp.c @@ -0,0 +1,83 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cexp.c */ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "complex_impl.h" + +static const uint32_t +exp_ovfl = 0x40862e42, /* high bits of MAX_EXP * ln2 ~= 710 */ +cexp_ovfl = 0x4096b8e4; /* (MAX_EXP - MIN_DENORM_EXP) * ln2 */ + +double complex cexp(double complex z) +{ + double x, y, exp_x; + uint32_t hx, hy, lx, ly; + + x = creal(z); + y = cimag(z); + + EXTRACT_WORDS(hy, ly, y); + hy &= 0x7fffffff; + + /* cexp(x + I 0) = exp(x) + I 0 */ + if ((hy | ly) == 0) + return CMPLX(exp(x), y); + EXTRACT_WORDS(hx, lx, x); + /* cexp(0 + I y) = cos(y) + I sin(y) */ + if (((hx & 0x7fffffff) | lx) == 0) + return CMPLX(cos(y), sin(y)); + + if (hy >= 0x7ff00000) { + if (lx != 0 || (hx & 0x7fffffff) != 0x7ff00000) { + /* cexp(finite|NaN +- I Inf|NaN) = NaN + I NaN */ + return CMPLX(y - y, y - y); + } else if (hx & 0x80000000) { + /* cexp(-Inf +- I Inf|NaN) = 0 + I 0 */ + return CMPLX(0.0, 0.0); + } else { + /* cexp(+Inf +- I Inf|NaN) = Inf + I NaN */ + return CMPLX(x, y - y); + } + } + + if (hx >= exp_ovfl && hx <= cexp_ovfl) { + /* + * x is between 709.7 and 1454.3, so we must scale to avoid + * overflow in exp(x). + */ + return __ldexp_cexp(z, 0); + } else { + /* + * Cases covered here: + * - x < exp_ovfl and exp(x) won't overflow (common case) + * - x > cexp_ovfl, so exp(x) * s overflows for all s > 0 + * - x = +-Inf (generated by exp()) + * - x = NaN (spurious inexact exception from y) + */ + exp_x = exp(x); + return CMPLX(exp_x * cos(y), exp_x * sin(y)); + } +} diff --git a/src/orca-libc/src/complex/cexpf.c b/src/orca-libc/src/complex/cexpf.c new file mode 100644 index 00000000..00d258f3 --- /dev/null +++ b/src/orca-libc/src/complex/cexpf.c @@ -0,0 +1,83 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cexpf.c */ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "complex_impl.h" + +static const uint32_t +exp_ovfl = 0x42b17218, /* MAX_EXP * ln2 ~= 88.722839355 */ +cexp_ovfl = 0x43400074; /* (MAX_EXP - MIN_DENORM_EXP) * ln2 */ + +float complex cexpf(float complex z) +{ + float x, y, exp_x; + uint32_t hx, hy; + + x = crealf(z); + y = cimagf(z); + + GET_FLOAT_WORD(hy, y); + hy &= 0x7fffffff; + + /* cexp(x + I 0) = exp(x) + I 0 */ + if (hy == 0) + return CMPLXF(expf(x), y); + GET_FLOAT_WORD(hx, x); + /* cexp(0 + I y) = cos(y) + I sin(y) */ + if ((hx & 0x7fffffff) == 0) + return CMPLXF(cosf(y), sinf(y)); + + if (hy >= 0x7f800000) { + if ((hx & 0x7fffffff) != 0x7f800000) { + /* cexp(finite|NaN +- I Inf|NaN) = NaN + I NaN */ + return CMPLXF(y - y, y - y); + } else if (hx & 0x80000000) { + /* cexp(-Inf +- I Inf|NaN) = 0 + I 0 */ + return CMPLXF(0.0, 0.0); + } else { + /* cexp(+Inf +- I Inf|NaN) = Inf + I NaN */ + return CMPLXF(x, y - y); + } + } + + if (hx >= exp_ovfl && hx <= cexp_ovfl) { + /* + * x is between 88.7 and 192, so we must scale to avoid + * overflow in expf(x). + */ + return __ldexp_cexpf(z, 0); + } else { + /* + * Cases covered here: + * - x < exp_ovfl and exp(x) won't overflow (common case) + * - x > cexp_ovfl, so exp(x) * s overflows for all s > 0 + * - x = +-Inf (generated by exp()) + * - x = NaN (spurious inexact exception from y) + */ + exp_x = expf(x); + return CMPLXF(exp_x * cosf(y), exp_x * sinf(y)); + } +} diff --git a/src/orca-libc/src/complex/cexpl.c b/src/orca-libc/src/complex/cexpl.c new file mode 100644 index 00000000..d4df950e --- /dev/null +++ b/src/orca-libc/src/complex/cexpl.c @@ -0,0 +1,7 @@ +#include "complex_impl.h" + +//FIXME +long double complex cexpl(long double complex z) +{ + return cexp(z); +} diff --git a/src/orca-libc/src/complex/cimag.c b/src/orca-libc/src/complex/cimag.c new file mode 100644 index 00000000..d6b0e683 --- /dev/null +++ b/src/orca-libc/src/complex/cimag.c @@ -0,0 +1,6 @@ +#include "complex_impl.h" + +double (cimag)(double complex z) +{ + return cimag(z); +} diff --git a/src/orca-libc/src/complex/cimagf.c b/src/orca-libc/src/complex/cimagf.c new file mode 100644 index 00000000..b7166dcf --- /dev/null +++ b/src/orca-libc/src/complex/cimagf.c @@ -0,0 +1,6 @@ +#include "complex_impl.h" + +float (cimagf)(float complex z) +{ + return cimagf(z); +} diff --git a/src/orca-libc/src/complex/cimagl.c b/src/orca-libc/src/complex/cimagl.c new file mode 100644 index 00000000..4db77f20 --- /dev/null +++ b/src/orca-libc/src/complex/cimagl.c @@ -0,0 +1,6 @@ +#include "complex_impl.h" + +long double (cimagl)(long double complex z) +{ + return cimagl(z); +} diff --git a/src/orca-libc/src/complex/clog.c b/src/orca-libc/src/complex/clog.c new file mode 100644 index 00000000..b587c291 --- /dev/null +++ b/src/orca-libc/src/complex/clog.c @@ -0,0 +1,14 @@ +#include "complex_impl.h" + +// FIXME + +/* log(z) = log(|z|) + i arg(z) */ + +double complex clog(double complex z) +{ + double r, phi; + + r = cabs(z); + phi = carg(z); + return CMPLX(log(r), phi); +} diff --git a/src/orca-libc/src/complex/clogf.c b/src/orca-libc/src/complex/clogf.c new file mode 100644 index 00000000..0389d472 --- /dev/null +++ b/src/orca-libc/src/complex/clogf.c @@ -0,0 +1,12 @@ +#include "complex_impl.h" + +// FIXME + +float complex clogf(float complex z) +{ + float r, phi; + + r = cabsf(z); + phi = cargf(z); + return CMPLXF(logf(r), phi); +} diff --git a/src/orca-libc/src/complex/clogl.c b/src/orca-libc/src/complex/clogl.c new file mode 100644 index 00000000..88e83e87 --- /dev/null +++ b/src/orca-libc/src/complex/clogl.c @@ -0,0 +1,18 @@ +#include "complex_impl.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex clogl(long double complex z) +{ + return clog(z); +} +#else +// FIXME +long double complex clogl(long double complex z) +{ + long double r, phi; + + r = cabsl(z); + phi = cargl(z); + return CMPLXL(logl(r), phi); +} +#endif diff --git a/src/orca-libc/src/complex/conj.c b/src/orca-libc/src/complex/conj.c new file mode 100644 index 00000000..a3b19a4a --- /dev/null +++ b/src/orca-libc/src/complex/conj.c @@ -0,0 +1,6 @@ +#include "complex_impl.h" + +double complex conj(double complex z) +{ + return CMPLX(creal(z), -cimag(z)); +} diff --git a/src/orca-libc/src/complex/conjf.c b/src/orca-libc/src/complex/conjf.c new file mode 100644 index 00000000..b2195c84 --- /dev/null +++ b/src/orca-libc/src/complex/conjf.c @@ -0,0 +1,6 @@ +#include "complex_impl.h" + +float complex conjf(float complex z) +{ + return CMPLXF(crealf(z), -cimagf(z)); +} diff --git a/src/orca-libc/src/complex/conjl.c b/src/orca-libc/src/complex/conjl.c new file mode 100644 index 00000000..87a4ebec --- /dev/null +++ b/src/orca-libc/src/complex/conjl.c @@ -0,0 +1,6 @@ +#include "complex_impl.h" + +long double complex conjl(long double complex z) +{ + return CMPLXL(creall(z), -cimagl(z)); +} diff --git a/src/orca-libc/src/complex/cpow.c b/src/orca-libc/src/complex/cpow.c new file mode 100644 index 00000000..1137d391 --- /dev/null +++ b/src/orca-libc/src/complex/cpow.c @@ -0,0 +1,8 @@ +#include "complex_impl.h" + +/* pow(z, c) = exp(c log(z)), See C99 G.6.4.1 */ + +double complex cpow(double complex z, double complex c) +{ + return cexp(c * clog(z)); +} diff --git a/src/orca-libc/src/complex/cpowf.c b/src/orca-libc/src/complex/cpowf.c new file mode 100644 index 00000000..f3fd4b7b --- /dev/null +++ b/src/orca-libc/src/complex/cpowf.c @@ -0,0 +1,6 @@ +#include "complex_impl.h" + +float complex cpowf(float complex z, float complex c) +{ + return cexpf(c * clogf(z)); +} diff --git a/src/orca-libc/src/complex/cpowl.c b/src/orca-libc/src/complex/cpowl.c new file mode 100644 index 00000000..be36f046 --- /dev/null +++ b/src/orca-libc/src/complex/cpowl.c @@ -0,0 +1,13 @@ +#include "complex_impl.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex cpowl(long double complex z, long double complex c) +{ + return cpow(z, c); +} +#else +long double complex cpowl(long double complex z, long double complex c) +{ + return cexpl(c * clogl(z)); +} +#endif diff --git a/src/orca-libc/src/complex/cproj.c b/src/orca-libc/src/complex/cproj.c new file mode 100644 index 00000000..d2b8f5a9 --- /dev/null +++ b/src/orca-libc/src/complex/cproj.c @@ -0,0 +1,8 @@ +#include "complex_impl.h" + +double complex cproj(double complex z) +{ + if (isinf(creal(z)) || isinf(cimag(z))) + return CMPLX(INFINITY, copysign(0.0, cimag(z))); + return z; +} diff --git a/src/orca-libc/src/complex/cprojf.c b/src/orca-libc/src/complex/cprojf.c new file mode 100644 index 00000000..15a874bb --- /dev/null +++ b/src/orca-libc/src/complex/cprojf.c @@ -0,0 +1,8 @@ +#include "complex_impl.h" + +float complex cprojf(float complex z) +{ + if (isinf(crealf(z)) || isinf(cimagf(z))) + return CMPLXF(INFINITY, copysignf(0.0, cimagf(z))); + return z; +} diff --git a/src/orca-libc/src/complex/cprojl.c b/src/orca-libc/src/complex/cprojl.c new file mode 100644 index 00000000..531ffa1c --- /dev/null +++ b/src/orca-libc/src/complex/cprojl.c @@ -0,0 +1,15 @@ +#include "complex_impl.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex cprojl(long double complex z) +{ + return cproj(z); +} +#else +long double complex cprojl(long double complex z) +{ + if (isinf(creall(z)) || isinf(cimagl(z))) + return CMPLXL(INFINITY, copysignl(0.0, cimagl(z))); + return z; +} +#endif diff --git a/src/orca-libc/src/complex/creal.c b/src/orca-libc/src/complex/creal.c new file mode 100644 index 00000000..f6703040 --- /dev/null +++ b/src/orca-libc/src/complex/creal.c @@ -0,0 +1,6 @@ +#include + +double (creal)(double complex z) +{ + return creal(z); +} diff --git a/src/orca-libc/src/complex/crealf.c b/src/orca-libc/src/complex/crealf.c new file mode 100644 index 00000000..5dc3ff1d --- /dev/null +++ b/src/orca-libc/src/complex/crealf.c @@ -0,0 +1,6 @@ +#include + +float (crealf)(float complex z) +{ + return crealf(z); +} diff --git a/src/orca-libc/src/complex/creall.c b/src/orca-libc/src/complex/creall.c new file mode 100644 index 00000000..fd9dc347 --- /dev/null +++ b/src/orca-libc/src/complex/creall.c @@ -0,0 +1,6 @@ +#include + +long double (creall)(long double complex z) +{ + return creall(z); +} diff --git a/src/orca-libc/src/complex/csin.c b/src/orca-libc/src/complex/csin.c new file mode 100644 index 00000000..535c4bf8 --- /dev/null +++ b/src/orca-libc/src/complex/csin.c @@ -0,0 +1,9 @@ +#include "complex_impl.h" + +/* sin(z) = -i sinh(i z) */ + +double complex csin(double complex z) +{ + z = csinh(CMPLX(-cimag(z), creal(z))); + return CMPLX(cimag(z), -creal(z)); +} diff --git a/src/orca-libc/src/complex/csinf.c b/src/orca-libc/src/complex/csinf.c new file mode 100644 index 00000000..69f5164e --- /dev/null +++ b/src/orca-libc/src/complex/csinf.c @@ -0,0 +1,7 @@ +#include "complex_impl.h" + +float complex csinf(float complex z) +{ + z = csinhf(CMPLXF(-cimagf(z), crealf(z))); + return CMPLXF(cimagf(z), -crealf(z)); +} diff --git a/src/orca-libc/src/complex/csinh.c b/src/orca-libc/src/complex/csinh.c new file mode 100644 index 00000000..eda0ab59 --- /dev/null +++ b/src/orca-libc/src/complex/csinh.c @@ -0,0 +1,141 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_csinh.c */ +/*- + * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Hyperbolic sine of a complex argument z = x + i y. + * + * sinh(z) = sinh(x+iy) + * = sinh(x) cos(y) + i cosh(x) sin(y). + * + * Exceptional values are noted in the comments within the source code. + * These values and the return value were taken from n1124.pdf. + */ + +#include "complex_impl.h" + +static const double huge = 0x1p1023; + +double complex csinh(double complex z) +{ + double x, y, h; + int32_t hx, hy, ix, iy, lx, ly; + + x = creal(z); + y = cimag(z); + + EXTRACT_WORDS(hx, lx, x); + EXTRACT_WORDS(hy, ly, y); + + ix = 0x7fffffff & hx; + iy = 0x7fffffff & hy; + + /* Handle the nearly-non-exceptional cases where x and y are finite. */ + if (ix < 0x7ff00000 && iy < 0x7ff00000) { + if ((iy | ly) == 0) + return CMPLX(sinh(x), y); + if (ix < 0x40360000) /* small x: normal case */ + return CMPLX(sinh(x) * cos(y), cosh(x) * sin(y)); + + /* |x| >= 22, so cosh(x) ~= exp(|x|) */ + if (ix < 0x40862e42) { + /* x < 710: exp(|x|) won't overflow */ + h = exp(fabs(x)) * 0.5; + return CMPLX(copysign(h, x) * cos(y), h * sin(y)); + } else if (ix < 0x4096bbaa) { + /* x < 1455: scale to avoid overflow */ + z = __ldexp_cexp(CMPLX(fabs(x), y), -1); + return CMPLX(creal(z) * copysign(1, x), cimag(z)); + } else { + /* x >= 1455: the result always overflows */ + h = huge * x; + return CMPLX(h * cos(y), h * h * sin(y)); + } + } + + /* + * sinh(+-0 +- I Inf) = sign(d(+-0, dNaN))0 + I dNaN. + * The sign of 0 in the result is unspecified. Choice = normally + * the same as dNaN. Raise the invalid floating-point exception. + * + * sinh(+-0 +- I NaN) = sign(d(+-0, NaN))0 + I d(NaN). + * The sign of 0 in the result is unspecified. Choice = normally + * the same as d(NaN). + */ + if ((ix | lx) == 0 && iy >= 0x7ff00000) + return CMPLX(copysign(0, x * (y - y)), y - y); + + /* + * sinh(+-Inf +- I 0) = +-Inf + I +-0. + * + * sinh(NaN +- I 0) = d(NaN) + I +-0. + */ + if ((iy | ly) == 0 && ix >= 0x7ff00000) { + if (((hx & 0xfffff) | lx) == 0) + return CMPLX(x, y); + return CMPLX(x, copysign(0, y)); + } + + /* + * sinh(x +- I Inf) = dNaN + I dNaN. + * Raise the invalid floating-point exception for finite nonzero x. + * + * sinh(x + I NaN) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception for finite + * nonzero x. Choice = don't raise (except for signaling NaNs). + */ + if (ix < 0x7ff00000 && iy >= 0x7ff00000) + return CMPLX(y - y, x * (y - y)); + + /* + * sinh(+-Inf + I NaN) = +-Inf + I d(NaN). + * The sign of Inf in the result is unspecified. Choice = normally + * the same as d(NaN). + * + * sinh(+-Inf +- I Inf) = +Inf + I dNaN. + * The sign of Inf in the result is unspecified. Choice = always +. + * Raise the invalid floating-point exception. + * + * sinh(+-Inf + I y) = +-Inf cos(y) + I Inf sin(y) + */ + if (ix >= 0x7ff00000 && ((hx & 0xfffff) | lx) == 0) { + if (iy >= 0x7ff00000) + return CMPLX(x * x, x * (y - y)); + return CMPLX(x * cos(y), INFINITY * sin(y)); + } + + /* + * sinh(NaN + I NaN) = d(NaN) + I d(NaN). + * + * sinh(NaN +- I Inf) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception. + * Choice = raise. + * + * sinh(NaN + I y) = d(NaN) + I d(NaN). + * Optionally raises the invalid floating-point exception for finite + * nonzero y. Choice = don't raise (except for signaling NaNs). + */ + return CMPLX((x * x) * (y - y), (x + x) * (y - y)); +} diff --git a/src/orca-libc/src/complex/csinhf.c b/src/orca-libc/src/complex/csinhf.c new file mode 100644 index 00000000..eb1d98c5 --- /dev/null +++ b/src/orca-libc/src/complex/csinhf.c @@ -0,0 +1,90 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_csinhf.c */ +/*- + * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Hyperbolic sine of a complex argument z. See s_csinh.c for details. + */ + +#include "complex_impl.h" + +static const float huge = 0x1p127; + +float complex csinhf(float complex z) +{ + float x, y, h; + int32_t hx, hy, ix, iy; + + x = crealf(z); + y = cimagf(z); + + GET_FLOAT_WORD(hx, x); + GET_FLOAT_WORD(hy, y); + + ix = 0x7fffffff & hx; + iy = 0x7fffffff & hy; + + if (ix < 0x7f800000 && iy < 0x7f800000) { + if (iy == 0) + return CMPLXF(sinhf(x), y); + if (ix < 0x41100000) /* small x: normal case */ + return CMPLXF(sinhf(x) * cosf(y), coshf(x) * sinf(y)); + + /* |x| >= 9, so cosh(x) ~= exp(|x|) */ + if (ix < 0x42b17218) { + /* x < 88.7: expf(|x|) won't overflow */ + h = expf(fabsf(x)) * 0.5f; + return CMPLXF(copysignf(h, x) * cosf(y), h * sinf(y)); + } else if (ix < 0x4340b1e7) { + /* x < 192.7: scale to avoid overflow */ + z = __ldexp_cexpf(CMPLXF(fabsf(x), y), -1); + return CMPLXF(crealf(z) * copysignf(1, x), cimagf(z)); + } else { + /* x >= 192.7: the result always overflows */ + h = huge * x; + return CMPLXF(h * cosf(y), h * h * sinf(y)); + } + } + + if (ix == 0 && iy >= 0x7f800000) + return CMPLXF(copysignf(0, x * (y - y)), y - y); + + if (iy == 0 && ix >= 0x7f800000) { + if ((hx & 0x7fffff) == 0) + return CMPLXF(x, y); + return CMPLXF(x, copysignf(0, y)); + } + + if (ix < 0x7f800000 && iy >= 0x7f800000) + return CMPLXF(y - y, x * (y - y)); + + if (ix >= 0x7f800000 && (hx & 0x7fffff) == 0) { + if (iy >= 0x7f800000) + return CMPLXF(x * x, x * (y - y)); + return CMPLXF(x * cosf(y), INFINITY * sinf(y)); + } + + return CMPLXF((x * x) * (y - y), (x + x) * (y - y)); +} diff --git a/src/orca-libc/src/complex/csinhl.c b/src/orca-libc/src/complex/csinhl.c new file mode 100644 index 00000000..09fd18f9 --- /dev/null +++ b/src/orca-libc/src/complex/csinhl.c @@ -0,0 +1,7 @@ +#include "complex_impl.h" + +//FIXME +long double complex csinhl(long double complex z) +{ + return csinh(z); +} diff --git a/src/orca-libc/src/complex/csinl.c b/src/orca-libc/src/complex/csinl.c new file mode 100644 index 00000000..90a4eb37 --- /dev/null +++ b/src/orca-libc/src/complex/csinl.c @@ -0,0 +1,14 @@ +#include "complex_impl.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex csinl(long double complex z) +{ + return csin(z); +} +#else +long double complex csinl(long double complex z) +{ + z = csinhl(CMPLXL(-cimagl(z), creall(z))); + return CMPLXL(cimagl(z), -creall(z)); +} +#endif diff --git a/src/orca-libc/src/complex/csqrt.c b/src/orca-libc/src/complex/csqrt.c new file mode 100644 index 00000000..c36de001 --- /dev/null +++ b/src/orca-libc/src/complex/csqrt.c @@ -0,0 +1,100 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_csqrt.c */ +/*- + * Copyright (c) 2007 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "complex_impl.h" + +/* + * gcc doesn't implement complex multiplication or division correctly, + * so we need to handle infinities specially. We turn on this pragma to + * notify conforming c99 compilers that the fast-but-incorrect code that + * gcc generates is acceptable, since the special cases have already been + * handled. + */ +#pragma STDC CX_LIMITED_RANGE ON + +/* We risk spurious overflow for components >= DBL_MAX / (1 + sqrt(2)). */ +#define THRESH 0x1.a827999fcef32p+1022 + +double complex csqrt(double complex z) +{ + double complex result; + double a, b; + double t; + int scale; + + a = creal(z); + b = cimag(z); + + /* Handle special cases. */ + if (z == 0) + return CMPLX(0, b); + if (isinf(b)) + return CMPLX(INFINITY, b); + if (isnan(a)) { + t = (b - b) / (b - b); /* raise invalid if b is not a NaN */ + return CMPLX(a, t); /* return NaN + NaN i */ + } + if (isinf(a)) { + /* + * csqrt(inf + NaN i) = inf + NaN i + * csqrt(inf + y i) = inf + 0 i + * csqrt(-inf + NaN i) = NaN +- inf i + * csqrt(-inf + y i) = 0 + inf i + */ + if (signbit(a)) + return CMPLX(fabs(b - b), copysign(a, b)); + else + return CMPLX(a, copysign(b - b, b)); + } + /* + * The remaining special case (b is NaN) is handled just fine by + * the normal code path below. + */ + + /* Scale to avoid overflow. */ + if (fabs(a) >= THRESH || fabs(b) >= THRESH) { + a *= 0.25; + b *= 0.25; + scale = 1; + } else { + scale = 0; + } + + /* Algorithm 312, CACM vol 10, Oct 1967. */ + if (a >= 0) { + t = sqrt((a + hypot(a, b)) * 0.5); + result = CMPLX(t, b / (2 * t)); + } else { + t = sqrt((-a + hypot(a, b)) * 0.5); + result = CMPLX(fabs(b) / (2 * t), copysign(t, b)); + } + + /* Rescale. */ + if (scale) + result *= 2; + return result; +} diff --git a/src/orca-libc/src/complex/csqrtf.c b/src/orca-libc/src/complex/csqrtf.c new file mode 100644 index 00000000..a6163974 --- /dev/null +++ b/src/orca-libc/src/complex/csqrtf.c @@ -0,0 +1,82 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_csqrtf.c */ +/*- + * Copyright (c) 2007 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "complex_impl.h" + +/* + * gcc doesn't implement complex multiplication or division correctly, + * so we need to handle infinities specially. We turn on this pragma to + * notify conforming c99 compilers that the fast-but-incorrect code that + * gcc generates is acceptable, since the special cases have already been + * handled. + */ +#pragma STDC CX_LIMITED_RANGE ON + +float complex csqrtf(float complex z) +{ + float a = crealf(z), b = cimagf(z); + double t; + + /* Handle special cases. */ + if (z == 0) + return CMPLXF(0, b); + if (isinf(b)) + return CMPLXF(INFINITY, b); + if (isnan(a)) { + t = (b - b) / (b - b); /* raise invalid if b is not a NaN */ + return CMPLXF(a, t); /* return NaN + NaN i */ + } + if (isinf(a)) { + /* + * csqrtf(inf + NaN i) = inf + NaN i + * csqrtf(inf + y i) = inf + 0 i + * csqrtf(-inf + NaN i) = NaN +- inf i + * csqrtf(-inf + y i) = 0 + inf i + */ + if (signbit(a)) + return CMPLXF(fabsf(b - b), copysignf(a, b)); + else + return CMPLXF(a, copysignf(b - b, b)); + } + /* + * The remaining special case (b is NaN) is handled just fine by + * the normal code path below. + */ + + /* + * We compute t in double precision to avoid overflow and to + * provide correct rounding in nearly all cases. + * This is Algorithm 312, CACM vol 10, Oct 1967. + */ + if (a >= 0) { + t = sqrt((a + hypot(a, b)) * 0.5); + return CMPLXF(t, b / (2.0 * t)); + } else { + t = sqrt((-a + hypot(a, b)) * 0.5); + return CMPLXF(fabsf(b) / (2.0 * t), copysignf(t, b)); + } +} diff --git a/src/orca-libc/src/complex/csqrtl.c b/src/orca-libc/src/complex/csqrtl.c new file mode 100644 index 00000000..22539379 --- /dev/null +++ b/src/orca-libc/src/complex/csqrtl.c @@ -0,0 +1,7 @@ +#include "complex_impl.h" + +//FIXME +long double complex csqrtl(long double complex z) +{ + return csqrt(z); +} diff --git a/src/orca-libc/src/complex/ctan.c b/src/orca-libc/src/complex/ctan.c new file mode 100644 index 00000000..918717bf --- /dev/null +++ b/src/orca-libc/src/complex/ctan.c @@ -0,0 +1,9 @@ +#include "complex_impl.h" + +/* tan(z) = -i tanh(i z) */ + +double complex ctan(double complex z) +{ + z = ctanh(CMPLX(-cimag(z), creal(z))); + return CMPLX(cimag(z), -creal(z)); +} diff --git a/src/orca-libc/src/complex/ctanf.c b/src/orca-libc/src/complex/ctanf.c new file mode 100644 index 00000000..04c3ff19 --- /dev/null +++ b/src/orca-libc/src/complex/ctanf.c @@ -0,0 +1,7 @@ +#include "complex_impl.h" + +float complex ctanf(float complex z) +{ + z = ctanhf(CMPLXF(-cimagf(z), crealf(z))); + return CMPLXF(cimagf(z), -crealf(z)); +} diff --git a/src/orca-libc/src/complex/ctanh.c b/src/orca-libc/src/complex/ctanh.c new file mode 100644 index 00000000..54004cd7 --- /dev/null +++ b/src/orca-libc/src/complex/ctanh.c @@ -0,0 +1,129 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_ctanh.c */ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Hyperbolic tangent of a complex argument z = x + i y. + * + * The algorithm is from: + * + * W. Kahan. Branch Cuts for Complex Elementary Functions or Much + * Ado About Nothing's Sign Bit. In The State of the Art in + * Numerical Analysis, pp. 165 ff. Iserles and Powell, eds., 1987. + * + * Method: + * + * Let t = tan(x) + * beta = 1/cos^2(y) + * s = sinh(x) + * rho = cosh(x) + * + * We have: + * + * tanh(z) = sinh(z) / cosh(z) + * + * sinh(x) cos(y) + i cosh(x) sin(y) + * = --------------------------------- + * cosh(x) cos(y) + i sinh(x) sin(y) + * + * cosh(x) sinh(x) / cos^2(y) + i tan(y) + * = ------------------------------------- + * 1 + sinh^2(x) / cos^2(y) + * + * beta rho s + i t + * = ---------------- + * 1 + beta s^2 + * + * Modifications: + * + * I omitted the original algorithm's handling of overflow in tan(x) after + * verifying with nearpi.c that this can't happen in IEEE single or double + * precision. I also handle large x differently. + */ + +#include "complex_impl.h" + +double complex ctanh(double complex z) +{ + double x, y; + double t, beta, s, rho, denom; + uint32_t hx, ix, lx; + + x = creal(z); + y = cimag(z); + + EXTRACT_WORDS(hx, lx, x); + ix = hx & 0x7fffffff; + + /* + * ctanh(NaN + i 0) = NaN + i 0 + * + * ctanh(NaN + i y) = NaN + i NaN for y != 0 + * + * The imaginary part has the sign of x*sin(2*y), but there's no + * special effort to get this right. + * + * ctanh(+-Inf +- i Inf) = +-1 +- 0 + * + * ctanh(+-Inf + i y) = +-1 + 0 sin(2y) for y finite + * + * The imaginary part of the sign is unspecified. This special + * case is only needed to avoid a spurious invalid exception when + * y is infinite. + */ + if (ix >= 0x7ff00000) { + if ((ix & 0xfffff) | lx) /* x is NaN */ + return CMPLX(x, (y == 0 ? y : x * y)); + SET_HIGH_WORD(x, hx - 0x40000000); /* x = copysign(1, x) */ + return CMPLX(x, copysign(0, isinf(y) ? y : sin(y) * cos(y))); + } + + /* + * ctanh(+-0 + i NAN) = +-0 + i NaN + * ctanh(+-0 +- i Inf) = +-0 + i NaN + * ctanh(x + i NAN) = NaN + i NaN + * ctanh(x +- i Inf) = NaN + i NaN + */ + if (!isfinite(y)) + return CMPLX(x ? y - y : x, y - y); + + /* + * ctanh(+-huge + i +-y) ~= +-1 +- i 2sin(2y)/exp(2x), using the + * approximation sinh^2(huge) ~= exp(2*huge) / 4. + * We use a modified formula to avoid spurious overflow. + */ + if (ix >= 0x40360000) { /* x >= 22 */ + double exp_mx = exp(-fabs(x)); + return CMPLX(copysign(1, x), 4 * sin(y) * cos(y) * exp_mx * exp_mx); + } + + /* Kahan's algorithm */ + t = tan(y); + beta = 1.0 + t * t; /* = 1 / cos^2(y) */ + s = sinh(x); + rho = sqrt(1 + s * s); /* = cosh(x) */ + denom = 1 + beta * s * s; + return CMPLX((beta * rho * s) / denom, t / denom); +} diff --git a/src/orca-libc/src/complex/ctanhf.c b/src/orca-libc/src/complex/ctanhf.c new file mode 100644 index 00000000..7f422ba7 --- /dev/null +++ b/src/orca-libc/src/complex/ctanhf.c @@ -0,0 +1,66 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_ctanhf.c */ +/*- + * Copyright (c) 2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Hyperbolic tangent of a complex argument z. See s_ctanh.c for details. + */ + +#include "complex_impl.h" + +float complex ctanhf(float complex z) +{ + float x, y; + float t, beta, s, rho, denom; + uint32_t hx, ix; + + x = crealf(z); + y = cimagf(z); + + GET_FLOAT_WORD(hx, x); + ix = hx & 0x7fffffff; + + if (ix >= 0x7f800000) { + if (ix & 0x7fffff) + return CMPLXF(x, (y == 0 ? y : x * y)); + SET_FLOAT_WORD(x, hx - 0x40000000); + return CMPLXF(x, copysignf(0, isinf(y) ? y : sinf(y) * cosf(y))); + } + + if (!isfinite(y)) + return CMPLXF(ix ? y - y : x, y - y); + + if (ix >= 0x41300000) { /* x >= 11 */ + float exp_mx = expf(-fabsf(x)); + return CMPLXF(copysignf(1, x), 4 * sinf(y) * cosf(y) * exp_mx * exp_mx); + } + + t = tanf(y); + beta = 1.0 + t * t; + s = sinhf(x); + rho = sqrtf(1 + s * s); + denom = 1 + beta * s * s; + return CMPLXF((beta * rho * s) / denom, t / denom); +} diff --git a/src/orca-libc/src/complex/ctanhl.c b/src/orca-libc/src/complex/ctanhl.c new file mode 100644 index 00000000..45d5862c --- /dev/null +++ b/src/orca-libc/src/complex/ctanhl.c @@ -0,0 +1,7 @@ +#include "complex_impl.h" + +//FIXME +long double complex ctanhl(long double complex z) +{ + return ctanh(z); +} diff --git a/src/orca-libc/src/complex/ctanl.c b/src/orca-libc/src/complex/ctanl.c new file mode 100644 index 00000000..4b87420d --- /dev/null +++ b/src/orca-libc/src/complex/ctanl.c @@ -0,0 +1,14 @@ +#include "complex_impl.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double complex ctanl(long double complex z) +{ + return ctan(z); +} +#else +long double complex ctanl(long double complex z) +{ + z = ctanhl(CMPLXL(-cimagl(z), creall(z))); + return CMPLXL(cimagl(z), -creall(z)); +} +#endif diff --git a/src/orca-libc/src/crt/crt1.c b/src/orca-libc/src/crt/crt1.c new file mode 100644 index 00000000..e6897481 --- /dev/null +++ b/src/orca-libc/src/crt/crt1.c @@ -0,0 +1,3 @@ +// We compile a plain crt1.o for toolchain compatibility, but it's +// identical to crt1-command.o. + diff --git a/src/orca-libc/src/ctype/__ctype_b_loc.c b/src/orca-libc/src/ctype/__ctype_b_loc.c new file mode 100644 index 00000000..f43795e9 --- /dev/null +++ b/src/orca-libc/src/ctype/__ctype_b_loc.c @@ -0,0 +1,41 @@ +#include + +#if __BYTE_ORDER == __BIG_ENDIAN +#define X(x) x +#else +#define X(x) (((x)/256 | (x)*256) % 65536) +#endif + +static const unsigned short table[] = { +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +X(0x200),X(0x200),X(0x200),X(0x200),X(0x200),X(0x200),X(0x200),X(0x200), +X(0x200),X(0x320),X(0x220),X(0x220),X(0x220),X(0x220),X(0x200),X(0x200), +X(0x200),X(0x200),X(0x200),X(0x200),X(0x200),X(0x200),X(0x200),X(0x200), +X(0x200),X(0x200),X(0x200),X(0x200),X(0x200),X(0x200),X(0x200),X(0x200), +X(0x160),X(0x4c0),X(0x4c0),X(0x4c0),X(0x4c0),X(0x4c0),X(0x4c0),X(0x4c0), +X(0x4c0),X(0x4c0),X(0x4c0),X(0x4c0),X(0x4c0),X(0x4c0),X(0x4c0),X(0x4c0), +X(0x8d8),X(0x8d8),X(0x8d8),X(0x8d8),X(0x8d8),X(0x8d8),X(0x8d8),X(0x8d8), +X(0x8d8),X(0x8d8),X(0x4c0),X(0x4c0),X(0x4c0),X(0x4c0),X(0x4c0),X(0x4c0), +X(0x4c0),X(0x8d5),X(0x8d5),X(0x8d5),X(0x8d5),X(0x8d5),X(0x8d5),X(0x8c5), +X(0x8c5),X(0x8c5),X(0x8c5),X(0x8c5),X(0x8c5),X(0x8c5),X(0x8c5),X(0x8c5), +X(0x8c5),X(0x8c5),X(0x8c5),X(0x8c5),X(0x8c5),X(0x8c5),X(0x8c5),X(0x8c5), +X(0x8c5),X(0x8c5),X(0x8c5),X(0x4c0),X(0x4c0),X(0x4c0),X(0x4c0),X(0x4c0), +X(0x4c0),X(0x8d6),X(0x8d6),X(0x8d6),X(0x8d6),X(0x8d6),X(0x8d6),X(0x8c6), +X(0x8c6),X(0x8c6),X(0x8c6),X(0x8c6),X(0x8c6),X(0x8c6),X(0x8c6),X(0x8c6), +X(0x8c6),X(0x8c6),X(0x8c6),X(0x8c6),X(0x8c6),X(0x8c6),X(0x8c6),X(0x8c6), +X(0x8c6),X(0x8c6),X(0x8c6),X(0x4c0),X(0x4c0),X(0x4c0),X(0x4c0),X(0x200), +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; + +static const unsigned short *const ptable = table+128; + +const unsigned short **__ctype_b_loc(void) +{ + return (void *)&ptable; +} diff --git a/src/orca-libc/src/ctype/__ctype_tolower_loc.c b/src/orca-libc/src/ctype/__ctype_tolower_loc.c new file mode 100644 index 00000000..efb99105 --- /dev/null +++ b/src/orca-libc/src/ctype/__ctype_tolower_loc.c @@ -0,0 +1,30 @@ +#include + +static const int32_t table[] = { +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, +16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, +32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, +48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, +64, +'a','b','c','d','e','f','g','h','i','j','k','l','m', +'n','o','p','q','r','s','t','u','v','w','x','y','z', +91,92,93,94,95,96, +'a','b','c','d','e','f','g','h','i','j','k','l','m', +'n','o','p','q','r','s','t','u','v','w','x','y','z', +123,124,125,126,127, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; + +static const int32_t *const ptable = table+128; + +const int32_t **__ctype_tolower_loc(void) +{ + return (void *)&ptable; +} diff --git a/src/orca-libc/src/ctype/__ctype_toupper_loc.c b/src/orca-libc/src/ctype/__ctype_toupper_loc.c new file mode 100644 index 00000000..ffaef0e9 --- /dev/null +++ b/src/orca-libc/src/ctype/__ctype_toupper_loc.c @@ -0,0 +1,30 @@ +#include + +static const int32_t table[] = { +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, +16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, +32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, +48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, +64, +'A','B','C','D','E','F','G','H','I','J','K','L','M', +'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', +91,92,93,94,95,96, +'A','B','C','D','E','F','G','H','I','J','K','L','M', +'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', +123,124,125,126,127, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; + +static const int32_t *const ptable = table+128; + +const int32_t **__ctype_toupper_loc(void) +{ + return (void *)&ptable; +} diff --git a/src/orca-libc/src/ctype/alpha.h b/src/orca-libc/src/ctype/alpha.h new file mode 100644 index 00000000..4167f387 --- /dev/null +++ b/src/orca-libc/src/ctype/alpha.h @@ -0,0 +1,172 @@ +18,17,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,17,34,35,36,17,37,38,39,40, +41,42,43,44,17,45,46,47,16,16,48,16,16,16,16,16,16,16,49,50,51,16,52,53,16,16, +17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,54, +17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +17,17,17,55,17,17,17,17,56,17,57,58,59,60,61,62,17,17,17,17,17,17,17,17,17,17, +17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +17,17,17,17,17,17,17,63,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,17,64,65,17,66,67, +68,69,70,71,72,73,74,17,75,76,77,78,79,80,81,16,82,83,84,85,86,87,88,89,90,91, +92,93,16,94,95,96,16,17,17,17,97,98,99,16,16,16,16,16,16,16,16,16,16,17,17,17, +17,100,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,17,17,101,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,17,17,102,103,16,16,104,105,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +17,17,17,17,17,17,17,17,17,106,17,17,107,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,17, +108,109,16,16,16,16,16,16,16,16,16,110,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,111,112,113,114,16,16,16,16,16,16,16,16,115,116, +117,16,16,16,16,16,118,119,16,16,16,16,120,16,16,121,16,16,16,16,16,16,16,16, +16,16,16,16,16, +16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,254,255,255,7,254, +255,255,7,0,0,0,0,0,4,32,4,255,255,127,255,255,255,127,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,195,255,3,0,31,80,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,223,188,64,215,255,255, +251,255,255,255,255,255,255,255,255,255,191,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,3,252,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,254,255,255,255,127,2,255,255,255, +255,255,1,0,0,0,0,255,191,182,0,255,255,255,135,7,0,0,0,255,7,255,255,255,255, +255,255,255,254,255,195,255,255,255,255,255,255,255,255,255,255,255,255,239, +31,254,225,255, +159,0,0,255,255,255,255,255,255,0,224,255,255,255,255,255,255,255,255,255,255, +255,255,3,0,255,255,255,255,255,7,48,4,255,255,255,252,255,31,0,0,255,255,255, +1,255,7,0,0,0,0,0,0,255,255,223,63,0,0,240,255,248,3,255,255,255,255,255,255, +255,255,255,239,255,223,225,255,207,255,254,255,239,159,249,255,255,253,197, +227,159,89,128,176,207,255,3,16,238,135,249,255,255,253,109,195,135,25,2,94, +192,255,63,0,238,191,251,255,255,253,237,227,191,27,1,0,207,255,0,30,238,159, +249,255,255,253,237,227,159,25,192,176,207,255,2,0,236,199,61,214,24,199,255, +195,199,29,129,0,192,255,0,0,239,223,253,255,255,253,255,227,223,29,96,7,207, +255,0,0,239,223,253,255,255,253,239,227,223,29,96,64,207,255,6,0,239,223,253, +255,255,255,255,231,223,93,240,128,207,255,0,252,236,255,127,252,255,255,251, +47,127,128,95,255,192,255,12,0,254,255,255,255,255,127,255,7,63,32,255,3,0,0, +0,0,214,247,255,255,175,255,255,59,95,32,255,243,0,0,0, +0,1,0,0,0,255,3,0,0,255,254,255,255,255,31,254,255,3,255,255,254,255,255,255, +31,0,0,0,0,0,0,0,0,255,255,255,255,255,255,127,249,255,3,255,255,255,255,255, +255,255,255,255,63,255,255,255,255,191,32,255,255,255,255,255,247,255,255,255, +255,255,255,255,255,255,61,127,61,255,255,255,255,255,61,255,255,255,255,61, +127,61,255,127,255,255,255,255,255,255,255,61,255,255,255,255,255,255,255,255, +7,0,0,0,0,255,255,0,0,255,255,255,255,255,255,255,255,255,255,63,63,254,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,159,255,255,254,255,255,7,255,255,255,255,255,255,255,255, +255,199,255,1,255,223,15,0,255,255,15,0,255,255,15,0,255,223,13,0,255,255,255, +255,255,255,207,255,255,1,128,16,255,3,0,0,0,0,255,3,255,255,255,255,255,255, +255,255,255,255,255,1,255,255,255,255,255,7,255,255,255,255,255,255,255,255, +63, +0,255,255,255,127,255,15,255,1,192,255,255,255,255,63,31,0,255,255,255,255, +255,15,255,255,255,3,255,3,0,0,0,0,255,255,255,15,255,255,255,255,255,255,255, +127,254,255,31,0,255,3,255,3,128,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255, +255,239,255,239,15,255,3,0,0,0,0,255,255,255,255,255,243,255,255,255,255,255, +255,191,255,3,0,255,255,255,255,255,255,127,0,255,227,255,255,255,255,255,63, +255,1,255,255,255,255,255,231,0,0,0,0,0,222,111,4,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0, +128,255,31,0,255,255,63,63,255,255,255,255,63,63,255,170,255,255,255,63,255, +255,255,255,255,255,223,95,220,31,207,15,255,31,220,31,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,2,128,0,0,255,31,0,0,0,0,0,0,0,0,0,0,0,0,132,252,47,62,80,189,255,243, +224,67,0,0,255,255,255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,255,255,255,255,255,255,3,0, +0,255,255,255,255,255,127,255,255,255,255,255,127,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,31,120,12,0,255,255,255,255,191,32,255, +255,255,255,255,255,255,128,0,0,255,255,127,0,127,127,127,127,127,127,127,127, +255,255,255,255,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,224,0,0,0,254,3,62,31,254,255,255,255,255,255,255,255,255,255,127,224,254, +255,255,255,255,255,255,255,255,255,255,247,224,255,255,255,255,255,254,255, +255,255,255,255,255,255,255,255,255,127,0,0,255,255,255,7,0,0,0,0,0,0,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,63,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0, +0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,31,0,0, +0,0,0,0,0,0,255,255,255,255,255,63,255,31,255,255,255,15,0,0,255,255,255,255, +255,127,240,143,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0, +0,128,255,252,255,255,255,255,255,255,255,255,255,255,255,255,249,255,255,255, +255,255,255,124,0,0,0,0,0,128,255,191,255,255,255,255,0,0,0,255,255,255,255, +255,255,15,0,255,255,255,255,255,255,255,255,47,0,255,3,0,0,252,232,255,255, +255,255,255,7,255,255,255,255,7,0,255,255,255,31,255,255,255,255,255,255,247, +255,0,128,255,3,255,255,255,127,255,255,255,255,255,255,127,0,255,63,255,3, +255,255,127,252,255,255,255,255,255,255,255,127,5,0,0,56,255,255,60,0,126,126, +126,0,127,127,255,255,255,255,255,247,255,0,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,7,255,3,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,15,0,255,255,127,248,255,255,255,255, +255, +15,255,255,255,255,255,255,255,255,255,255,255,255,255,63,255,255,255,255,255, +255,255,255,255,255,255,255,255,3,0,0,0,0,127,0,248,224,255,253,127,95,219, +255,255,255,255,255,255,255,255,255,255,255,255,255,3,0,0,0,248,255,255,255, +255,255,255,255,255,255,255,255,255,63,0,0,255,255,255,255,255,255,255,255, +252,255,255,255,255,255,255,0,0,0,0,0,255,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,223, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,31,0,0,255,3, +254,255,255,7,254,255,255,7,192,255,255,255,255,255,255,255,255,255,255,127, +252,252,252,28,0,0,0,0,255,239,255,255,127,255,255,183,255,63,255,63,0,0,0,0, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,7,0,0,0,0,0,0,0,0, +255,255,255,255,255,255,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,255,255,255,31,255,255,255,255,255,255,1,0,0,0,0, +0,255,255,255,255,0,224,255,255,255,7,255,255,255,255,255,7,255,255,255,63, +255,255,255,255,15,255,62,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,63,255,3,255,255,255,255,15,255,255,255, +255,15,255,255,255,255,255,0,255,255,255,255,255,255,15,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,255,255,255,255,255,255,127,0,255,255,63,0,255,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,63,253,255,255,255,255,191,145,255,255,63,0,255,255, +127,0,255,255,255,127,0,0,0,0,0,0,0,0,255,255,55,0,255,255,63,0,255,255,255,3, +0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,192,0,0,0,0,0,0,0,0,111,240,239, +254,255,255,63,0,0,0,0,0,255,255,255,31,255,255,255,31,0,0,0,0,255,254,255, +255,31,0,0,0,255,255,255,255,255,255,63,0,255,255,63,0,255,255,7,0,255,255,3, +0,0,0,0,0,0,0,0,0,0,0,0, +0,255,255,255,255,255,255,255,255,255,1,0,0,0,0,0,0,255,255,255,255,255,255,7, +0,255,255,255,255,255,255,7,0,255,255,255,255,255,0,255,3,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,31,128,0,255,255,63,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,255,255,127,0,255,255,255,255,255,255,255,255,63,0,0,0, +192,255,0,0,252,255,255,255,255,255,255,1,0,0,255,255,255,1,255,3,255,255,255, +255,255,255,199,255,112,0,255,255,255,255,71,0,255,255,255,255,255,255,255, +255,30,0,255,23,0,0,0,0,255,255,251,255,255,255,159,64,0,0,0,0,0,0,0,0,127, +189,255,191,255,1,255,255,255,255,255,255,255,1,255,3,239,159,249,255,255,253, +237,227,159,25,129,224,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255, +255,255,255,255,255,187,7,255,131,0,0,0,0,255,255,255,255,255,255,255,255,179, +0,255,3,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,63,127,0,0,0,63,0,0, +0,0,255,255,255,255,255,255,255,127,17,0,255,3,0,0,0,0,255,255,255,255,255, +255,63,1,255,3,0,0,0,0,0,0,255,255,255,231,255,7,255,3,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,1,0,0,0,0,0,0,0,0,0,0,0, +0,255,255,255,255,255,255,255,255,255,3,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,255,252,255,255,255,255,255,252,26,0,0,0,255,255,255,255,255,255,231, +127,0,0,255,255,255,255,255,255,255,255,255,32,0,0,0,0,255,255,255,255,255, +255,255,1,255,253,255,255,255,255,127,127,1,0,255,3,0,0,252,255,255,255,252, +255,255,254,127,0,0,0,0,0,0,0,0,0,127,251,255,255,255,255,127,180,203,0,255,3, +191,253,255,255,255,127,123,1,255,3,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,127,0,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,3,0,0, +0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,127,0, +0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255, +255,255,255,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255, +255,255,255,255,255,255,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, +255,255,255,255,255,255,1,255,255,255,127,255,3,0,0,0,0,0,0,0,0,0,0,0,0,255, +255,255,63,0,0,255,255,255,255,255,255,0,0,15,0,255,3,248,255,255,224,255,255, +0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,255,255,255,255,255,255,255,255,255,135,255,255,255,255,255,255,255,128, +255,255,0,0,0,0,0,0,0,0,11,0,0,0,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,7,0,255,255,255,127,0,0,0,0,0, +0,7,0,240,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,15,255,255,255,255, +255,255,255,255,255,255,255,255,255,7,255,31,255,1,255,67,0,0,0,0,0,0,0,0,0,0, +0,0,255,255,255,255,255,255,255,255,255,255,223,255,255,255,255,255,255,255, +255,223,100,222,255,235,239,255,255,255,255,255,255, +255,191,231,223,223,255,255,255,123,95,252,253,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,63,255,255,255, +253,255,255,247,255,255,255,247,255,255,223,255,255,255,223,255,255,127,255, +255,255,127,255,255,255,253,255,255,255,253,255,255,247,207,255,255,255,255, +255,255,127,255,255,249,219,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,255,255,255,255,255,31,128,63,255,67,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255, +15,255,3,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,31,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255, +143,8,255,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,239,255,255,255,150,254,247,10,132,234,150,170,150,247,247,94,255,251,255, +15,238,251,255,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,3,255,255,255,3,255, +255,255,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0, diff --git a/src/orca-libc/src/ctype/casemap.h b/src/orca-libc/src/ctype/casemap.h new file mode 100644 index 00000000..6ee1209b --- /dev/null +++ b/src/orca-libc/src/ctype/casemap.h @@ -0,0 +1,297 @@ +static const unsigned char tab[] = { + 7, 8, 9, 10, 11, 12, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 13, 6, 6, 14, 6, 6, 6, 6, 6, 6, 6, 6, 15, 16, 17, 18, + 6, 19, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 20, 21, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 22, 23, 6, 6, 6, 24, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 25, + 6, 6, 6, 6, 26, 6, 6, 6, 6, 6, 6, 6, 27, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 28, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 29, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 30, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, + 43, 43, 43, 43, 43, 43, 43, 43, 1, 0, 84, 86, 86, 86, 86, 86, + 86, 86, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 43, 43, 43, 43, 43, 43, + 43, 7, 43, 43, 91, 86, 86, 86, 86, 86, 86, 86, 74, 86, 86, 5, + 49, 80, 49, 80, 49, 80, 49, 80, 49, 80, 49, 80, 49, 80, 49, 80, + 36, 80, 121, 49, 80, 49, 80, 49, 56, 80, 49, 80, 49, 80, 49, 80, + 49, 80, 49, 80, 49, 80, 49, 80, 78, 49, 2, 78, 13, 13, 78, 3, + 78, 0, 36, 110, 0, 78, 49, 38, 110, 81, 78, 36, 80, 78, 57, 20, + 129, 27, 29, 29, 83, 49, 80, 49, 80, 13, 49, 80, 49, 80, 49, 80, + 27, 83, 36, 80, 49, 2, 92, 123, 92, 123, 92, 123, 92, 123, 92, 123, + 20, 121, 92, 123, 92, 123, 92, 45, 43, 73, 3, 72, 3, 120, 92, 123, + 20, 0, 150, 10, 1, 43, 40, 6, 6, 0, 42, 6, 42, 42, 43, 7, + 187, 181, 43, 30, 0, 43, 7, 43, 43, 43, 1, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 1, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 42, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 205, 70, 205, 43, 0, 37, 43, 7, 1, 6, 1, 85, 86, 86, 86, + 86, 86, 85, 86, 86, 2, 36, 129, 129, 129, 129, 129, 21, 129, 129, 129, + 0, 0, 43, 0, 178, 209, 178, 209, 178, 209, 178, 209, 0, 0, 205, 204, + 1, 0, 215, 215, 215, 215, 215, 131, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 28, 0, 0, 0, + 0, 0, 49, 80, 49, 80, 49, 80, 49, 80, 49, 80, 49, 2, 0, 0, + 49, 80, 49, 80, 49, 80, 49, 80, 49, 80, 49, 80, 49, 80, 49, 80, + 49, 80, 78, 49, 80, 49, 80, 78, 49, 80, 49, 80, 49, 80, 49, 80, + 49, 80, 49, 80, 49, 80, 49, 2, 135, 166, 135, 166, 135, 166, 135, 166, + 135, 166, 135, 166, 135, 166, 135, 166, 42, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 0, 0, 0, 84, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 84, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 12, 0, 12, 42, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 7, 42, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 86, 86, 108, 129, 21, 0, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 7, 108, 3, 65, 43, 43, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 44, 86, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 12, 108, 0, 0, 0, 0, 0, 6, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 6, 37, 6, 37, 6, 37, 6, 37, 6, 37, + 6, 37, 6, 37, 6, 37, 6, 37, 6, 37, 6, 37, 6, 37, 6, 37, + 6, 37, 6, 37, 6, 37, 6, 37, 6, 37, 6, 37, 6, 37, 6, 37, + 6, 37, 6, 37, 6, 37, 6, 37, 86, 122, 158, 38, 6, 37, 6, 37, + 6, 37, 6, 37, 6, 37, 6, 37, 6, 37, 6, 37, 6, 37, 6, 37, + 6, 37, 6, 37, 6, 37, 6, 37, 6, 37, 6, 1, 43, 43, 79, 86, + 86, 44, 43, 127, 86, 86, 57, 43, 43, 85, 86, 86, 43, 43, 79, 86, + 86, 44, 43, 127, 86, 86, 129, 55, 117, 91, 123, 92, 43, 43, 79, 86, + 86, 2, 172, 4, 0, 0, 57, 43, 43, 85, 86, 86, 43, 43, 79, 86, + 86, 44, 43, 43, 86, 86, 50, 19, 129, 87, 0, 111, 129, 126, 201, 215, + 126, 45, 129, 129, 14, 126, 57, 127, 111, 87, 0, 129, 129, 126, 21, 0, + 126, 3, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 7, 43, + 36, 43, 151, 43, 43, 43, 43, 43, 43, 43, 43, 43, 42, 43, 43, 43, + 43, 43, 86, 86, 86, 86, 86, 128, 129, 129, 129, 129, 57, 187, 42, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 1, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 201, 172, 172, 172, 172, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 172, 208, 13, 0, 78, 49, 2, 180, 193, 193, + 215, 215, 36, 80, 49, 80, 49, 80, 49, 80, 49, 80, 49, 80, 49, 80, + 49, 80, 49, 80, 49, 80, 49, 80, 49, 80, 49, 80, 49, 80, 49, 80, + 49, 80, 49, 80, 215, 215, 83, 193, 71, 212, 215, 215, 215, 5, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 7, 1, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 78, 49, 80, 49, 80, 49, 80, + 49, 80, 49, 80, 49, 80, 49, 80, 13, 0, 0, 0, 0, 0, 36, 80, + 49, 80, 49, 80, 49, 80, 49, 80, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 121, 92, 123, 92, 123, 79, 123, 92, 123, 92, 123, + 92, 123, 92, 123, 92, 123, 92, 123, 92, 123, 92, 123, 92, 123, 92, 45, + 43, 43, 121, 20, 92, 123, 92, 45, 121, 42, 92, 39, 92, 123, 92, 123, + 92, 123, 164, 0, 10, 180, 92, 123, 92, 123, 79, 3, 42, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 42, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 43, 43, 43, 43, 43, 43, 43, 43, 7, 0, 72, 86, 86, 86, 86, + 86, 86, 86, 86, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 85, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 36, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 7, 0, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 7, 0, 0, + 0, 0, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 42, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 85, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 14, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; +static const int rules[] = { + 0x0, 0x2001, -0x2000, 0x1dbf00, 0x2e700, 0x7900, + 0x2402, 0x101, -0x100, 0x0, 0x201, -0x200, + -0xc6ff, -0xe800, -0x78ff, -0x12c00, 0xc300, 0xd201, + 0xce01, 0xcd01, 0x4f01, 0xca01, 0xcb01, 0xcf01, + 0x6100, 0xd301, 0xd101, 0xa300, 0xd501, 0x8200, + 0xd601, 0xda01, 0xd901, 0xdb01, 0x3800, 0x3, + -0x4f00, -0x60ff, -0x37ff, 0x242802, 0x0, 0x101, + -0x100, -0xcd00, -0xda00, -0x81ff, 0x2a2b01, -0xa2ff, + 0x2a2801, 0x2a3f00, -0xc2ff, 0x4501, 0x4701, 0x2a1f00, + 0x2a1c00, 0x2a1e00, -0xd200, -0xce00, -0xca00, -0xcb00, + 0xa54f00, 0xa54b00, -0xcf00, 0xa52800, 0xa54400, -0xd100, + -0xd300, 0x29f700, 0xa54100, 0x29fd00, -0xd500, -0xd600, + 0x29e700, 0xa54300, 0xa52a00, -0x4500, -0xd900, -0x4700, + -0xdb00, 0xa51500, 0xa51200, 0x4c2402, 0x0, 0x2001, + -0x2000, 0x101, -0x100, 0x5400, 0x7401, 0x2601, + 0x2501, 0x4001, 0x3f01, -0x2600, -0x2500, -0x1f00, + -0x4000, -0x3f00, 0x801, -0x3e00, -0x3900, -0x2f00, + -0x3600, -0x800, -0x5600, -0x5000, 0x700, -0x7400, + -0x3bff, -0x6000, -0x6ff, 0x701a02, 0x101, -0x100, + 0x2001, -0x2000, 0x5001, 0xf01, -0xf00, 0x0, + 0x3001, -0x3000, 0x101, -0x100, 0x0, 0xbc000, + 0x1c6001, 0x0, 0x97d001, 0x801, -0x800, 0x8a0502, + 0x0, -0xbbfff, -0x186200, 0x89c200, -0x182500, -0x186e00, + -0x186d00, -0x186400, -0x186300, -0x185c00, 0x0, 0x8a3800, + 0x8a0400, 0xee600, 0x101, -0x100, 0x0, -0x3b00, + -0x1dbeff, 0x8f1d02, 0x800, -0x7ff, 0x0, 0x5600, + -0x55ff, 0x4a00, 0x6400, 0x8000, 0x7000, 0x7e00, + 0x900, -0x49ff, -0x8ff, -0x1c2500, -0x63ff, -0x6fff, + -0x7fff, -0x7dff, 0xac0502, 0x0, 0x1001, -0x1000, + 0x1c01, 0x101, -0x1d5cff, -0x20beff, -0x2045ff, -0x1c00, + 0xb10b02, 0x101, -0x100, 0x3001, -0x3000, 0x0, + -0x29f6ff, -0xee5ff, -0x29e6ff, -0x2a2b00, -0x2a2800, -0x2a1bff, + -0x29fcff, -0x2a1eff, -0x2a1dff, -0x2a3eff, 0x0, -0x1c6000, + 0x0, 0x101, -0x100, 0xbc0c02, 0x0, 0x101, + -0x100, -0xa543ff, 0x3a001, -0x8a03ff, -0xa527ff, 0x3000, + -0xa54eff, -0xa54aff, -0xa540ff, -0xa511ff, -0xa529ff, -0xa514ff, + -0x2fff, -0xa542ff, -0x8a37ff, 0x0, -0x97d000, -0x3a000, + 0x0, 0x2001, -0x2000, 0x0, 0x2801, -0x2800, + 0x0, 0x4001, -0x4000, 0x0, 0x2001, -0x2000, + 0x0, 0x2001, -0x2000, 0x0, 0x2201, -0x2200, +}; +static const unsigned char rulebases[] = { + 0, 6, 39, 81, 111, 119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 124, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 131, 142, 146, 151, + 0, 170, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 196, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 198, 201, 0, 0, 0, 219, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, + 0, 0, 0, 0, 225, 0, 0, 0, 0, 0, 0, 0, 228, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 231, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 234, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 237, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; +static const unsigned char exceptions[][2] = { + { 48, 12 }, { 49, 13 }, { 120, 14 }, { 127, 15 }, + { 128, 16 }, { 129, 17 }, { 134, 18 }, { 137, 19 }, + { 138, 19 }, { 142, 20 }, { 143, 21 }, { 144, 22 }, + { 147, 19 }, { 148, 23 }, { 149, 24 }, { 150, 25 }, + { 151, 26 }, { 154, 27 }, { 156, 25 }, { 157, 28 }, + { 158, 29 }, { 159, 30 }, { 166, 31 }, { 169, 31 }, + { 174, 31 }, { 177, 32 }, { 178, 32 }, { 183, 33 }, + { 191, 34 }, { 197, 35 }, { 200, 35 }, { 203, 35 }, + { 221, 36 }, { 242, 35 }, { 246, 37 }, { 247, 38 }, + { 32, 45 }, { 58, 46 }, { 61, 47 }, { 62, 48 }, + { 63, 49 }, { 64, 49 }, { 67, 50 }, { 68, 51 }, + { 69, 52 }, { 80, 53 }, { 81, 54 }, { 82, 55 }, + { 83, 56 }, { 84, 57 }, { 89, 58 }, { 91, 59 }, + { 92, 60 }, { 97, 61 }, { 99, 62 }, { 101, 63 }, + { 102, 64 }, { 104, 65 }, { 105, 66 }, { 106, 64 }, + { 107, 67 }, { 108, 68 }, { 111, 66 }, { 113, 69 }, + { 114, 70 }, { 117, 71 }, { 125, 72 }, { 130, 73 }, + { 135, 74 }, { 137, 75 }, { 138, 76 }, { 139, 76 }, + { 140, 77 }, { 146, 78 }, { 157, 79 }, { 158, 80 }, + { 69, 87 }, { 123, 29 }, { 124, 29 }, { 125, 29 }, + { 127, 88 }, { 134, 89 }, { 136, 90 }, { 137, 90 }, + { 138, 90 }, { 140, 91 }, { 142, 92 }, { 143, 92 }, + { 172, 93 }, { 173, 94 }, { 174, 94 }, { 175, 94 }, + { 194, 95 }, { 204, 96 }, { 205, 97 }, { 206, 97 }, + { 207, 98 }, { 208, 99 }, { 209, 100 }, { 213, 101 }, + { 214, 102 }, { 215, 103 }, { 240, 104 }, { 241, 105 }, + { 242, 106 }, { 243, 107 }, { 244, 108 }, { 245, 109 }, + { 249, 110 }, { 253, 45 }, { 254, 45 }, { 255, 45 }, + { 80, 105 }, { 81, 105 }, { 82, 105 }, { 83, 105 }, + { 84, 105 }, { 85, 105 }, { 86, 105 }, { 87, 105 }, + { 88, 105 }, { 89, 105 }, { 90, 105 }, { 91, 105 }, + { 92, 105 }, { 93, 105 }, { 94, 105 }, { 95, 105 }, + { 130, 0 }, { 131, 0 }, { 132, 0 }, { 133, 0 }, + { 134, 0 }, { 135, 0 }, { 136, 0 }, { 137, 0 }, + { 192, 117 }, { 207, 118 }, { 128, 137 }, { 129, 138 }, + { 130, 139 }, { 133, 140 }, { 134, 141 }, { 112, 157 }, + { 113, 157 }, { 118, 158 }, { 119, 158 }, { 120, 159 }, + { 121, 159 }, { 122, 160 }, { 123, 160 }, { 124, 161 }, + { 125, 161 }, { 179, 162 }, { 186, 163 }, { 187, 163 }, + { 188, 164 }, { 190, 165 }, { 195, 162 }, { 204, 164 }, + { 218, 166 }, { 219, 166 }, { 229, 106 }, { 234, 167 }, + { 235, 167 }, { 236, 110 }, { 243, 162 }, { 248, 168 }, + { 249, 168 }, { 250, 169 }, { 251, 169 }, { 252, 164 }, + { 38, 176 }, { 42, 177 }, { 43, 178 }, { 78, 179 }, + { 132, 8 }, { 98, 186 }, { 99, 187 }, { 100, 188 }, + { 101, 189 }, { 102, 190 }, { 109, 191 }, { 110, 192 }, + { 111, 193 }, { 112, 194 }, { 126, 195 }, { 127, 195 }, + { 125, 207 }, { 141, 208 }, { 148, 209 }, { 171, 210 }, + { 172, 211 }, { 173, 212 }, { 176, 213 }, { 177, 214 }, + { 178, 215 }, { 196, 216 }, { 197, 217 }, { 198, 218 }, +}; diff --git a/src/orca-libc/src/ctype/isalnum.c b/src/orca-libc/src/ctype/isalnum.c new file mode 100644 index 00000000..e3d2cf0b --- /dev/null +++ b/src/orca-libc/src/ctype/isalnum.c @@ -0,0 +1,6 @@ +#include + +int isalnum(int c) +{ + return isalpha(c) || isdigit(c); +} diff --git a/src/orca-libc/src/ctype/isalpha.c b/src/orca-libc/src/ctype/isalpha.c new file mode 100644 index 00000000..53e115c2 --- /dev/null +++ b/src/orca-libc/src/ctype/isalpha.c @@ -0,0 +1,7 @@ +#include +#undef isalpha + +int isalpha(int c) +{ + return ((unsigned)c|32)-'a' < 26; +} diff --git a/src/orca-libc/src/ctype/isascii.c b/src/orca-libc/src/ctype/isascii.c new file mode 100644 index 00000000..54ad3bf0 --- /dev/null +++ b/src/orca-libc/src/ctype/isascii.c @@ -0,0 +1,7 @@ +#include +#undef isascii + +int isascii(int c) +{ + return !(c&~0x7f); +} diff --git a/src/orca-libc/src/ctype/isblank.c b/src/orca-libc/src/ctype/isblank.c new file mode 100644 index 00000000..957400b2 --- /dev/null +++ b/src/orca-libc/src/ctype/isblank.c @@ -0,0 +1,6 @@ +#include + +int isblank(int c) +{ + return (c == ' ' || c == '\t'); +} diff --git a/src/orca-libc/src/ctype/iscntrl.c b/src/orca-libc/src/ctype/iscntrl.c new file mode 100644 index 00000000..92ed7f0e --- /dev/null +++ b/src/orca-libc/src/ctype/iscntrl.c @@ -0,0 +1,6 @@ +#include + +int iscntrl(int c) +{ + return (unsigned)c < 0x20 || c == 0x7f; +} diff --git a/src/orca-libc/src/ctype/isdigit.c b/src/orca-libc/src/ctype/isdigit.c new file mode 100644 index 00000000..0bc82a6d --- /dev/null +++ b/src/orca-libc/src/ctype/isdigit.c @@ -0,0 +1,7 @@ +#include +#undef isdigit + +int isdigit(int c) +{ + return (unsigned)c-'0' < 10; +} diff --git a/src/orca-libc/src/ctype/isgraph.c b/src/orca-libc/src/ctype/isgraph.c new file mode 100644 index 00000000..f8fac160 --- /dev/null +++ b/src/orca-libc/src/ctype/isgraph.c @@ -0,0 +1,7 @@ +#include +#undef isgraph + +int isgraph(int c) +{ + return (unsigned)c-0x21 < 0x5e; +} diff --git a/src/orca-libc/src/ctype/islower.c b/src/orca-libc/src/ctype/islower.c new file mode 100644 index 00000000..d72fb212 --- /dev/null +++ b/src/orca-libc/src/ctype/islower.c @@ -0,0 +1,7 @@ +#include +#undef islower + +int islower(int c) +{ + return (unsigned)c-'a' < 26; +} diff --git a/src/orca-libc/src/ctype/isprint.c b/src/orca-libc/src/ctype/isprint.c new file mode 100644 index 00000000..d0ebdf79 --- /dev/null +++ b/src/orca-libc/src/ctype/isprint.c @@ -0,0 +1,7 @@ +#include +#undef isprint + +int isprint(int c) +{ + return (unsigned)c-0x20 < 0x5f; +} diff --git a/src/orca-libc/src/ctype/ispunct.c b/src/orca-libc/src/ctype/ispunct.c new file mode 100644 index 00000000..fc455352 --- /dev/null +++ b/src/orca-libc/src/ctype/ispunct.c @@ -0,0 +1,6 @@ +#include + +int ispunct(int c) +{ + return isgraph(c) && !isalnum(c); +} diff --git a/src/orca-libc/src/ctype/isspace.c b/src/orca-libc/src/ctype/isspace.c new file mode 100644 index 00000000..55f9d59e --- /dev/null +++ b/src/orca-libc/src/ctype/isspace.c @@ -0,0 +1,7 @@ +#include +#undef isspace + +int isspace(int c) +{ + return c == ' ' || (unsigned)c-'\t' < 5; +} diff --git a/src/orca-libc/src/ctype/isupper.c b/src/orca-libc/src/ctype/isupper.c new file mode 100644 index 00000000..f09d88c5 --- /dev/null +++ b/src/orca-libc/src/ctype/isupper.c @@ -0,0 +1,7 @@ +#include +#undef isupper + +int isupper(int c) +{ + return (unsigned)c-'A' < 26; +} diff --git a/src/orca-libc/src/ctype/iswalnum.c b/src/orca-libc/src/ctype/iswalnum.c new file mode 100644 index 00000000..5842991b --- /dev/null +++ b/src/orca-libc/src/ctype/iswalnum.c @@ -0,0 +1,6 @@ +#include + +int iswalnum(wint_t wc) +{ + return iswdigit(wc) || iswalpha(wc); +} diff --git a/src/orca-libc/src/ctype/iswalpha.c b/src/orca-libc/src/ctype/iswalpha.c new file mode 100644 index 00000000..d558faef --- /dev/null +++ b/src/orca-libc/src/ctype/iswalpha.c @@ -0,0 +1,14 @@ +#include + +static const unsigned char table[] = { +#include "alpha.h" +}; + +int iswalpha(wint_t wc) +{ + if (wc<0x20000U) + return (table[table[wc>>8]*32+((wc&255)>>3)]>>(wc&7))&1; + if (wc<0x2fffeU) + return 1; + return 0; +} diff --git a/src/orca-libc/src/ctype/iswblank.c b/src/orca-libc/src/ctype/iswblank.c new file mode 100644 index 00000000..0a66843e --- /dev/null +++ b/src/orca-libc/src/ctype/iswblank.c @@ -0,0 +1,7 @@ +#include +#include + +int iswblank(wint_t wc) +{ + return isblank(wc); +} diff --git a/src/orca-libc/src/ctype/iswcntrl.c b/src/orca-libc/src/ctype/iswcntrl.c new file mode 100644 index 00000000..6f6edf9e --- /dev/null +++ b/src/orca-libc/src/ctype/iswcntrl.c @@ -0,0 +1,9 @@ +#include + +int iswcntrl(wint_t wc) +{ + return (unsigned)wc < 32 + || (unsigned)(wc-0x7f) < 33 + || (unsigned)(wc-0x2028) < 2 + || (unsigned)(wc-0xfff9) < 3; +} diff --git a/src/orca-libc/src/ctype/iswctype.c b/src/orca-libc/src/ctype/iswctype.c new file mode 100644 index 00000000..a431c909 --- /dev/null +++ b/src/orca-libc/src/ctype/iswctype.c @@ -0,0 +1,62 @@ +#include +#include + +#define WCTYPE_ALNUM 1 +#define WCTYPE_ALPHA 2 +#define WCTYPE_BLANK 3 +#define WCTYPE_CNTRL 4 +#define WCTYPE_DIGIT 5 +#define WCTYPE_GRAPH 6 +#define WCTYPE_LOWER 7 +#define WCTYPE_PRINT 8 +#define WCTYPE_PUNCT 9 +#define WCTYPE_SPACE 10 +#define WCTYPE_UPPER 11 +#define WCTYPE_XDIGIT 12 + +int iswctype(wint_t wc, wctype_t type) +{ + switch (type) { + case WCTYPE_ALNUM: + return iswalnum(wc); + case WCTYPE_ALPHA: + return iswalpha(wc); + case WCTYPE_BLANK: + return iswblank(wc); + case WCTYPE_CNTRL: + return iswcntrl(wc); + case WCTYPE_DIGIT: + return iswdigit(wc); + case WCTYPE_GRAPH: + return iswgraph(wc); + case WCTYPE_LOWER: + return iswlower(wc); + case WCTYPE_PRINT: + return iswprint(wc); + case WCTYPE_PUNCT: + return iswpunct(wc); + case WCTYPE_SPACE: + return iswspace(wc); + case WCTYPE_UPPER: + return iswupper(wc); + case WCTYPE_XDIGIT: + return iswxdigit(wc); + } + return 0; +} + +wctype_t wctype(const char *s) +{ + int i; + const char *p; + /* order must match! */ + static const char names[] = + "alnum\0" "alpha\0" "blank\0" + "cntrl\0" "digit\0" "graph\0" + "lower\0" "print\0" "punct\0" + "space\0" "upper\0" "xdigit"; + for (i=1, p=names; *p; i++, p+=6) + if (*s == *p && !strcmp(s, p)) + return i; + return 0; +} diff --git a/src/orca-libc/src/ctype/iswdigit.c b/src/orca-libc/src/ctype/iswdigit.c new file mode 100644 index 00000000..b1d9fa94 --- /dev/null +++ b/src/orca-libc/src/ctype/iswdigit.c @@ -0,0 +1,8 @@ +#include + +#undef iswdigit + +int iswdigit(wint_t wc) +{ + return (unsigned)wc-'0' < 10; +} diff --git a/src/orca-libc/src/ctype/iswgraph.c b/src/orca-libc/src/ctype/iswgraph.c new file mode 100644 index 00000000..fdc97853 --- /dev/null +++ b/src/orca-libc/src/ctype/iswgraph.c @@ -0,0 +1,7 @@ +#include + +int iswgraph(wint_t wc) +{ + /* ISO C defines this function as: */ + return !iswspace(wc) && iswprint(wc); +} diff --git a/src/orca-libc/src/ctype/iswlower.c b/src/orca-libc/src/ctype/iswlower.c new file mode 100644 index 00000000..0a568e77 --- /dev/null +++ b/src/orca-libc/src/ctype/iswlower.c @@ -0,0 +1,6 @@ +#include + +int iswlower(wint_t wc) +{ + return towupper(wc) != wc; +} diff --git a/src/orca-libc/src/ctype/iswprint.c b/src/orca-libc/src/ctype/iswprint.c new file mode 100644 index 00000000..333f19c2 --- /dev/null +++ b/src/orca-libc/src/ctype/iswprint.c @@ -0,0 +1,19 @@ +#include + +/* Consider all legal codepoints as printable except for: + * - C0 and C1 control characters + * - U+2028 and U+2029 (line/para break) + * - U+FFF9 through U+FFFB (interlinear annotation controls) + * The following code is optimized heavily to make hot paths for the + * expected printable characters. */ + +int iswprint(wint_t wc) +{ + if (wc < 0xffU) + return (wc+1 & 0x7f) >= 0x21; + if (wc < 0x2028U || wc-0x202aU < 0xd800-0x202a || wc-0xe000U < 0xfff9-0xe000) + return 1; + if (wc-0xfffcU > 0x10ffff-0xfffc || (wc&0xfffe)==0xfffe) + return 0; + return 1; +} diff --git a/src/orca-libc/src/ctype/iswpunct.c b/src/orca-libc/src/ctype/iswpunct.c new file mode 100644 index 00000000..16e8703b --- /dev/null +++ b/src/orca-libc/src/ctype/iswpunct.c @@ -0,0 +1,12 @@ +#include + +static const unsigned char table[] = { +#include "punct.h" +}; + +int iswpunct(wint_t wc) +{ + if (wc<0x20000U) + return (table[table[wc>>8]*32+((wc&255)>>3)]>>(wc&7))&1; + return 0; +} diff --git a/src/orca-libc/src/ctype/iswspace.c b/src/orca-libc/src/ctype/iswspace.c new file mode 100644 index 00000000..c3b20f33 --- /dev/null +++ b/src/orca-libc/src/ctype/iswspace.c @@ -0,0 +1,17 @@ +#include +#include + +/* Our definition of whitespace is the Unicode White_Space property, + * minus non-breaking spaces (U+00A0, U+2007, and U+202F) and script- + * specific characters with non-blank glyphs (U+1680 and U+180E). */ + +int iswspace(wint_t wc) +{ + static const wchar_t spaces[] = { + ' ', '\t', '\n', '\r', 11, 12, 0x0085, + 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, + 0x2006, 0x2008, 0x2009, 0x200a, + 0x2028, 0x2029, 0x205f, 0x3000, 0 + }; + return wc && wcschr(spaces, wc); +} diff --git a/src/orca-libc/src/ctype/iswupper.c b/src/orca-libc/src/ctype/iswupper.c new file mode 100644 index 00000000..eae59a75 --- /dev/null +++ b/src/orca-libc/src/ctype/iswupper.c @@ -0,0 +1,6 @@ +#include + +int iswupper(wint_t wc) +{ + return towlower(wc) != wc; +} diff --git a/src/orca-libc/src/ctype/iswxdigit.c b/src/orca-libc/src/ctype/iswxdigit.c new file mode 100644 index 00000000..4e0bedeb --- /dev/null +++ b/src/orca-libc/src/ctype/iswxdigit.c @@ -0,0 +1,6 @@ +#include + +int iswxdigit(wint_t wc) +{ + return (unsigned)(wc-'0') < 10 || (unsigned)((wc|32)-'a') < 6; +} diff --git a/src/orca-libc/src/ctype/isxdigit.c b/src/orca-libc/src/ctype/isxdigit.c new file mode 100644 index 00000000..ae68a3dc --- /dev/null +++ b/src/orca-libc/src/ctype/isxdigit.c @@ -0,0 +1,6 @@ +#include + +int isxdigit(int c) +{ + return isdigit(c) || ((unsigned)c|32)-'a' < 6; +} diff --git a/src/orca-libc/src/ctype/nonspacing.h b/src/orca-libc/src/ctype/nonspacing.h new file mode 100644 index 00000000..7746f3b6 --- /dev/null +++ b/src/orca-libc/src/ctype/nonspacing.h @@ -0,0 +1,91 @@ +16,16,16,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,16,33,16,16,16,34,35,36, +37,38,39,40,16,16,41,16,16,16,16,16,16,16,16,16,16,16,42,43,16,16,44,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,45,16,46,47,48,49,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,50,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,51,16,16,52, +53,16,54,55,56,16,16,16,16,16,16,57,16,16,58,16,59,60,61,62,63,64,65,66,67,68, +69,70,16,71,72,73,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,74,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,75,76,16,16,16,77,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,78,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,79,80,16,16,16,16,16,16,16,81,16,16,16,16,16,82,83,84,16,16,16,16,16,85, +86,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,248,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,254,255,255,255,255,191,182,0,0,0,0,0,0,0,63,0,255,23,0,0,0,0,0,248,255, +255,0,0,1,0,0,0,0,0,0,0,0,0,0,0,192,191,159,61,0,0,0,128,2,0,0,0,255,255,255, +7,0,0,0,0,0,0,0,0,0,0,192,255,1,0,0,0,0,0,0,248,15,32,0,0,192,251,239,62,0,0, +0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,248,255,255,255,255, +255,7,0,0,0,0,0,0,20,254,33,254,0,12,0,0,0,2,0,0,0,0,0,0,16,30,32,0,0,12,0,0, +64,6,0,0,0,0,0,0,16,134,57,2,0,0,0,35,0,6,0,0,0,0,0,0,16,190,33,0,0,12,0,0, +252,2,0,0,0,0,0,0,144,30,32,64,0,12,0,0,0,4,0,0,0,0,0,0,0,1,32,0,0,0,0,0,0,17, +0,0,0,0,0,0,192,193,61,96,0,12,0,0,0,2,0,0,0,0,0,0,144,64,48,0,0,12,0,0,0,3,0, +0,0,0,0,0,24,30,32,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,4,92,0,0,0,0,0,0,0,0,0,0,0, +242,7,128,127,0,0,0,0,0,0,0,0,0,0,0,0,242,31,0,63,0,0,0,0,0,0,0,0,0,3,0,0,160, +2,0,0,0,0,0,0,254,127,223,224,255,254,255,255,255,31,64,0,0,0,0,0,0,0,0,0,0,0, +0,224,253,102,0,0,0,195,1,0,30,0,100,32,0,32,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,224,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,28,0,0,0,28,0,0,0,12,0,0,0,12,0,0,0,0,0,0,0,176,63,64,254, +15,32,0,0,0,0,0,120,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,0,0,0,0,2,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,135,1,4,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +128,9,0,0,0,0,0,0,64,127,229,31,248,159,0,0,0,0,0,0,255,127,0,0,0,0,0,0,0,0, +15,0,0,0,0,0,208,23,4,0,0,0,0,248,15,0,3,0,0,0,60,59,0,0,0,0,0,0,64,163,3,0,0, +0,0,0,0,240,207,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,247,255,253,33,16, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255, +251,0,248,0,0,0,124,0,0,0,0,0,0,223,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255, +255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,3,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0, +0,60,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,128,247,63,0,0,0,192,0,0,0,0,0,0,0,0,0,0,3,0,68,8,0,0,96,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,48,0,0,0,255,255,3,128,0,0,0,0,192,63,0,0,128,255,3,0, +0,0,0,0,7,0,0,0,0,0,200,51,0,0,0,0,32,0,0, +0,0,0,0,0,0,126,102,0,8,16,0,0,0,0,0,16,0,0,0,0,0,0,157,193,2,0,0,0,0,48,64,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,33,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,0,0,0, +64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,0,0,255, +255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,110,240,0, +0,0,0,0,135,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,0,0,0,0,0,0,0,240,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,255,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,255,127,0,0,0,0,0,0,128, +3,0,0,0,0,0,120,38,0,32,0,0,0,0,0,0,7,0,0,0,128,239,31,0,0,0,0,0,0,0,8,0,3,0, +0,0,0,0,192,127,0,30,0,0,0,0,0,0,0,0,0,0,0,128,211,64,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,128,248,7,0,0,3,0,0,0,0,0,0,24,1,0,0,0,192,31,31,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,255,92,0,0,64,0,0,0,0,0,0,0,0,0,0,248,133,13,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,60,176,1,0,0,48,0,0,0,0,0,0,0,0,0,0, +248,167,1,0,0,0,0,0,0,0,0,0,0,0,0,40,191,0,0,0,0,0,0,0,0,0,0,0,0,224,188,15,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,255,6,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,240,12,1,0,0,0,254,7,0,0,0,0,248,121,128,0,126,14,0,0,0,0,0,252, +127,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,191,0,0,0,0,0,0,0,0,0,0,252,255, +255,252,109,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,126,180,191,0,0,0,0,0,0,0,0,0,163,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,0,0,0,0,0,0,0,255, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,128,7,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,15,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,3,248,255,231,15,0,0,0,60,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255, +255,255,255,255,127,248,255,255,255,255,255,31,32,0,16,0,0,248,254,255,0,0,0, +0,0,0,0,0,0,0,127,255,255,249,219,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,240,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,240,7,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, diff --git a/src/orca-libc/src/ctype/punct.h b/src/orca-libc/src/ctype/punct.h new file mode 100644 index 00000000..67929470 --- /dev/null +++ b/src/orca-libc/src/ctype/punct.h @@ -0,0 +1,141 @@ +18,16,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,16,16,34,35,16,36,37,38,39, +40,41,42,43,16,44,45,46,17,17,47,17,17,17,17,17,17,48,49,50,51,52,53,54,55,17, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,56, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,57,16,58,59,60,61,62,63,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,64,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,65,16,16,66,16,67,68, +69,16,70,71,72,16,73,16,16,74,75,76,77,78,16,79,80,81,82,83,84,85,86,87,88,89, +90,91,16,92,93,94,95,16,16,16,16,96,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,97,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,98,99,16,16,100,101,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,102,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,103,104,105,106,16,16,107,108,17,17,109,16,16,16,16,16,16,110,111,16, +16,16,16,16,112,113,16,16,114,115,116,16,117,118,119,17,17,17,120,121,122,123, +124,16,16,16,16, +16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,254,255,0,252,1,0,0,248,1, +0,0,120,0,0,0,0,255,251,223,251,0,0,128,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,60,0,252,255,224,175,255,255,255,255,255,255,255,255, +255,255,223,255,255,255,255,255,32,64,176,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,252,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,252,0,0,0,0,0,230,254,255,255,255,0,64,73,0,0,0,0,0,24,0,255,255,0,216, +0,0,0,0,0,0,0,1,0,60,0,0,0,0,0,0,0,0,0,0,0,0,16,224,1,30,0, +96,255,191,0,0,0,0,0,0,255,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,248,207, +227,0,0,0,3,0,32,255,127,0,0,0,78,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,7,252,0,0,0, +0,0,0,0,0,0,16,0,32,30,0,48,0,1,0,0,0,0,0,0,0,0,16,0,32,0,0,0,0,252,111,0,0,0, +0,0,0,0,16,0,32,0,0,0,0,64,0,0,0,0,0,0,0,0,16,0,32,0,0,0,0,3,224,0,0,0,0,0,0, +0,16,0,32,0,0,0,0,253,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,255,7,16,0,0,0,0,0,0,0,0, +32,0,0,0,0,128,255,16,0,0,0,0,0,0,16,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,24,0,160, +0,127,0,0,255,3,0,0,0,0,0,0,0,0,0,4,0,0,0,0,16,0,0,0,0,0,0,128,0,128,192,223, +0,12,0,0,0,0,0,0,0,0,0,0,0,4,0,31,0,0,0,0,0, +0,254,255,255,255,0,252,255,255,0,0,0,0,0,0,0,0,252,0,0,0,0,0,0,192,255,223, +255,7,0,0,0,0,0,0,0,0,0,0,128,6,0,252,0,0,0,0,0,0,0,0,0,192,0,0,0,0,0,0,0,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,224,255,255,255,31,0,0,255,3,0,0,0,0,0,0,0,0,0,0, +0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,96,0,0,1,0,0,24,0,0,0,0,0,0,0,0,0,56,0,0,0,0,16,0,0,0,112,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,48,0,0,254,127,47,0,0,255,3,255,127,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,49,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,196,255,255,255, +255,0,0,0,192,0,0,0,0,0,0,0,0,1,0,224,159,0,0,0,0,127,63,255,127,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,16,0,16,0,0,252,255,255,255,31,0,0,0,0,0,12,0,0,0,0,0,0,64,0, +12,240,0,0,0,0,0,0,128,248,0,0,0,0,0,0,0,192,0,0,0,0,0,0,0,0,255,0,255,255, +255,33,144,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255, +127,0,224,251,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,160,3,224,0,224,0, +224,0,96,128,248,255,255,255,252,255,255,255,255,255,127,223,255,241,127,255, +127,0,0,255,255,255,255,0,0,255,255,255,255,1,0,123,3,208,193,175,66,0,12,31, +188,255,255,0,0,0,0,0,14,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,127,0,0,0,255,7,0,0,255,255,255,255,255,255,255,255,255, +255,63,0,0,0,0,0,0,252,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,207,255,255,255, +63,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,224,135,3,254,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,127,255,255,255,255,0, +0,0,0,0,0,255,255,255,251,255,255,255,255,255,255,255,255,255,255,15,0,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,63,0,0,0,255,15,30,255,255,255,1,252,193,224,0,0,0,0, +0,0,0,0,0,0,0,30,1,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +255,255,0,0,0,0,255,255,255,255,15,0,0,0,255,255,255,127,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255, +255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255, +255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,127,0,0,0, +0,0,0,192,0,224,0,0,0,0,0,0,0,0,0,0,0,128,15,112,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +255,0,255,255,127,0,3,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,0,0,0,0,15,255,3,0,0,0,0,0,0,240,0,0,0,0,0,0,0,0,0,16,192,0,0,255,255,3,23, +0,0,0,0,0,248,0,0,0,0,8,128,0,0,0,0,0,0,0,0,0,0,8,0,255,63,0,192,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,240,0,0,128,3,0,0,0,0,0,0,0,128,2,0,0,192,0,0,67,0,0,0,0,0, +0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,56,0, +0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,2,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,252,255,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48,255,255,255,3,255,255,255,255,255,255,247, +255,127,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,254,255,0,252,1,0,0,248,1,0, +0,248,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,127,0,48,135,255,255,255,255,255, +143,255,0,0,0,0,0,0,224,255,255,127,255,15,1,0,0,0,0,0,255,255,255,255,255,63, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255, +15,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +128,255,0,0,128,255,0,0,0,0,128,255,0,0,0,0,0,0,0,0,0,248,0,0,192,143,0,0,0, +128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48,255,255,252,255,255,255,255,255,0,0,0,0, +0,0,0,135,255,1,255,1,0,0,0,224,0,0,0,224,0,0,0,0,0,1,0,0,96,248,127,0,0,0,0, +0,0,0,0,254,0,0,0,255,0,0,0,255,0,0,0,30,0,254,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,252,0,0,0,0,0,0,0,0,0,0,0, +0,255,255,255,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,224,127,0,0,0,192,255,255,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,192,63,252,255,63,0,0,128,3,0,0,0,0,0,0,254,3,32,0,0,0,0,0,0,0, +0,0,0,0,0,24,0,15,0,0,0,0,0,56,0,0,0,0,0,0,0,0,0,225,63,0,232,254,255,31,0,0, +0,0,0,0,0,96,63,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0, +24,0,32,0,0,192,31,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68, +248,0,104,0,0,0,0,0,0,0,0,0,0,0,0,76,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,128,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,128,14,0,0,0,255, +31,0,0,0,0,0,0,0,0,192,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,8,0,252,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,252,7,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,24,128,255,0,0,0,0,0, +0,0,0,0,0,223,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,62,0,0,252,255,31,3,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,0,0,0,0,0,0,0,0,0,128,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,128,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255, +255,3, +128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,63,0,0,0,0,0,0,0,255,255,48,0,0,248, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, +255,255,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,176,15,0,0,0,0,0,0, +0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,63, +0,255,255,255,255,127,254,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,1,0,0,255,255,255,255,255,255,255,255, +63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,15,0,255,255,255,255,255,255, +255,255,255,255,127,0,255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,8,0,0,0,8,0,0,32,0,0,0,32,0,0,128, +0,0,0,128,0,0,0,2,0,0,0,2,0,0,8,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,15,0,248,254,255,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,127,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,240,0, +128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,255,127,0,0,0,0,0,0,0, +0,0,0,0,0,0,112,7,0,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,254,255,255,255,255,255,255,255,31,0,0,0,0,0,0,0,0,0,254,255, +255,255,255,255,255,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,255,255,255,255,255, +15,255,255,255,255,255,255,255,255,255,255,255,255,15,0,255,127,254,255,254, +255,254,255,255,255,63,0,255,31,255,255,255,255,0,0,0,252,0,0,0,28,0,0,0,252, +255,255,255,31,0,0,0,0,0,0,192,255,255,255,7,0,255,255,255,255,255,15,255,1,3, +0,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,63,0,255,31,255,7,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,15,0,255,255,255,255,255,255,255,255,255,255,255,1, +255,15,0,0,255,15,255,255,255,255,255,255,255,0,255,3,255,255,255,255,255,0, +255,255,255,63,0,0,0,0,0,0,0,0,0,0,255,239,255,255,255,255,255,255,255,255, +255,255,255,255,123,252,255,255,255,255,231,199,255,255,255,231,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,15,0,255,63,15,7,7,0,63,0, +0,0,0,0,0,0,0,0,0,0,0,0, diff --git a/src/orca-libc/src/ctype/toascii.c b/src/orca-libc/src/ctype/toascii.c new file mode 100644 index 00000000..f0e48e8e --- /dev/null +++ b/src/orca-libc/src/ctype/toascii.c @@ -0,0 +1,7 @@ +#include + +/* nonsense function that should NEVER be used! */ +int toascii(int c) +{ + return c & 0x7f; +} diff --git a/src/orca-libc/src/ctype/tolower.c b/src/orca-libc/src/ctype/tolower.c new file mode 100644 index 00000000..b56f3c50 --- /dev/null +++ b/src/orca-libc/src/ctype/tolower.c @@ -0,0 +1,7 @@ +#include + +int tolower(int c) +{ + if (isupper(c)) return c | 32; + return c; +} diff --git a/src/orca-libc/src/ctype/toupper.c b/src/orca-libc/src/ctype/toupper.c new file mode 100644 index 00000000..1799f030 --- /dev/null +++ b/src/orca-libc/src/ctype/toupper.c @@ -0,0 +1,7 @@ +#include + +int toupper(int c) +{ + if (islower(c)) return c & 0x5f; + return c; +} diff --git a/src/orca-libc/src/errno/__errno_location.c b/src/orca-libc/src/errno/__errno_location.c new file mode 100644 index 00000000..a21c2c01 --- /dev/null +++ b/src/orca-libc/src/errno/__errno_location.c @@ -0,0 +1,9 @@ +#include + +static int __errno_val = 0; +int *__errno_location(void) +{ + return &__errno_val; +} + +weak_alias(__errno_location, ___errno_location); diff --git a/src/orca-libc/src/errno/__strerror.h b/src/orca-libc/src/errno/__strerror.h new file mode 100644 index 00000000..0557131b --- /dev/null +++ b/src/orca-libc/src/errno/__strerror.h @@ -0,0 +1,137 @@ +/* The first entry is a catch-all for codes not enumerated here. + * This file is included multiple times to declare and define a structure + * with these messages, and then to define a lookup table translating + * error codes to offsets of corresponding fields in the structure. */ + +#ifdef __wasilibc_unmodified_upstream // Print "Success" for ESUCCESS. +E(0, "No error information") +#else +E(0, "Success") +#endif + +E(EILSEQ, "Illegal byte sequence") +E(EDOM, "Domain error") +E(ERANGE, "Result not representable") + +E(ENOTTY, "Not a tty") +E(EACCES, "Permission denied") +E(EPERM, "Operation not permitted") +E(ENOENT, "No such file or directory") +E(ESRCH, "No such process") +E(EEXIST, "File exists") + +E(EOVERFLOW, "Value too large for data type") +E(ENOSPC, "No space left on device") +E(ENOMEM, "Out of memory") + +E(EBUSY, "Resource busy") +E(EINTR, "Interrupted system call") +E(EAGAIN, "Resource temporarily unavailable") +E(ESPIPE, "Invalid seek") + +E(EXDEV, "Cross-device link") +E(EROFS, "Read-only file system") +E(ENOTEMPTY, "Directory not empty") + +E(ECONNRESET, "Connection reset by peer") +E(ETIMEDOUT, "Operation timed out") +E(ECONNREFUSED, "Connection refused") +#ifdef __wasilibc_unmodified_upstream // errno value not in WASI +E(EHOSTDOWN, "Host is down") +#endif +E(EHOSTUNREACH, "Host is unreachable") +E(EADDRINUSE, "Address in use") + +E(EPIPE, "Broken pipe") +E(EIO, "I/O error") +E(ENXIO, "No such device or address") +#ifdef __wasilibc_unmodified_upstream // errno value not in WASI +E(ENOTBLK, "Block device required") +#endif +E(ENODEV, "No such device") +E(ENOTDIR, "Not a directory") +E(EISDIR, "Is a directory") +E(ETXTBSY, "Text file busy") +E(ENOEXEC, "Exec format error") + +E(EINVAL, "Invalid argument") + +E(E2BIG, "Argument list too long") +E(ELOOP, "Symbolic link loop") +E(ENAMETOOLONG, "Filename too long") +E(ENFILE, "Too many open files in system") +E(EMFILE, "No file descriptors available") +E(EBADF, "Bad file descriptor") +E(ECHILD, "No child process") +E(EFAULT, "Bad address") +E(EFBIG, "File too large") +E(EMLINK, "Too many links") +E(ENOLCK, "No locks available") + +E(EDEADLK, "Resource deadlock would occur") +E(ENOTRECOVERABLE, "State not recoverable") +E(EOWNERDEAD, "Previous owner died") +E(ECANCELED, "Operation canceled") +E(ENOSYS, "Function not implemented") +E(ENOMSG, "No message of desired type") +E(EIDRM, "Identifier removed") +#ifdef __wasilibc_unmodified_upstream // errno value not in WASI +E(ENOSTR, "Device not a stream") +E(ENODATA, "No data available") +E(ETIME, "Device timeout") +E(ENOSR, "Out of streams resources") +#endif +E(ENOLINK, "Link has been severed") +E(EPROTO, "Protocol error") +E(EBADMSG, "Bad message") +#ifdef __wasilibc_unmodified_upstream // errno value not in WASI +E(EBADFD, "File descriptor in bad state") +#endif +E(ENOTSOCK, "Not a socket") +E(EDESTADDRREQ, "Destination address required") +E(EMSGSIZE, "Message too large") +E(EPROTOTYPE, "Protocol wrong type for socket") +E(ENOPROTOOPT, "Protocol not available") +E(EPROTONOSUPPORT,"Protocol not supported") +#ifdef __wasilibc_unmodified_upstream // errno value not in WASI +E(ESOCKTNOSUPPORT,"Socket type not supported") +#endif +E(ENOTSUP, "Not supported") +#ifdef __wasilibc_unmodified_upstream // errno value not in WASI +E(EPFNOSUPPORT, "Protocol family not supported") +#endif +E(EAFNOSUPPORT, "Address family not supported by protocol") +E(EADDRNOTAVAIL,"Address not available") +E(ENETDOWN, "Network is down") +E(ENETUNREACH, "Network unreachable") +E(ENETRESET, "Connection reset by network") +E(ECONNABORTED, "Connection aborted") +E(ENOBUFS, "No buffer space available") +E(EISCONN, "Socket is connected") +E(ENOTCONN, "Socket not connected") +#ifdef __wasilibc_unmodified_upstream // errno value not in WASI +E(ESHUTDOWN, "Cannot send after socket shutdown") +#endif +E(EALREADY, "Operation already in progress") +E(EINPROGRESS, "Operation in progress") +E(ESTALE, "Stale file handle") +#ifdef __wasilibc_unmodified_upstream // errno value not in WASI +E(EREMOTEIO, "Remote I/O error") +#endif +E(EDQUOT, "Quota exceeded") +#ifdef __wasilibc_unmodified_upstream // errno value not in WASI +E(ENOMEDIUM, "No medium found") +E(EMEDIUMTYPE, "Wrong medium type") +#endif +E(EMULTIHOP, "Multihop attempted") +#ifdef __wasilibc_unmodified_upstream // errno value not in WASI +E(ENOKEY, "Required key not available") +E(EKEYEXPIRED, "Key has expired") +E(EKEYREVOKED, "Key has been revoked") +E(EKEYREJECTED, "Key was rejected by service") +#endif +#ifdef __wasilibc_unmodified_upstream // errno value in WASI and not musl +#else +// WASI adds this errno code. +//E(ENOTCAPABLE, "Capabilities insufficient") +#endif diff --git a/src/orca-libc/src/errno/strerror.c b/src/orca-libc/src/errno/strerror.c new file mode 100644 index 00000000..48cc6c9b --- /dev/null +++ b/src/orca-libc/src/errno/strerror.c @@ -0,0 +1,39 @@ +#include +#include +#include + +/* mips has one error code outside of the 8-bit range due to a + * historical typo, so we just remap it. */ +#if EDQUOT==1133 +#define EDQUOT_ORIG 1133 +#undef EDQUOT +#define EDQUOT 109 +#endif + +static const struct errmsgstr_t { +#define E(n, s) char str##n[sizeof(s)]; +#include "__strerror.h" +#undef E +} errmsgstr = { +#define E(n, s) s, +#include "__strerror.h" +#undef E +}; + +static const unsigned short errmsgidx[] = { +#define E(n, s) [n] = offsetof(struct errmsgstr_t, str##n), +#include "__strerror.h" +#undef E +}; + +char *strerror(int e) +{ + const char *s; +#ifdef EDQUOT_ORIG + if (e==EDQUOT) e=0; + else if (e==EDQUOT_ORIG) e=EDQUOT; +#endif + if (e >= sizeof errmsgidx / sizeof *errmsgidx) e = 0; + s = (char *)&errmsgstr + errmsgidx[e]; + return (char *)s; +} diff --git a/src/orca-libc/src/exit/_Exit.c b/src/orca-libc/src/exit/_Exit.c new file mode 100644 index 00000000..0075b08d --- /dev/null +++ b/src/orca-libc/src/exit/_Exit.c @@ -0,0 +1,10 @@ +#include +#include"platform/platform.h" + +_Noreturn void ORCA_IMPORT(oc_bridge_exit)(int); + + +_Noreturn void _Exit(int ec) +{ + oc_bridge_exit(ec); +} diff --git a/src/libc-shim/include/stdarg.h b/src/orca-libc/src/exit/abort.c similarity index 54% rename from src/libc-shim/include/stdarg.h rename to src/orca-libc/src/exit/abort.c index 55cbe27f..df9c9550 100644 --- a/src/libc-shim/include/stdarg.h +++ b/src/orca-libc/src/exit/abort.c @@ -5,13 +5,9 @@ * See LICENSE.txt for licensing information * **************************************************************************/ -#ifndef __STDARG_H_ -#define __STDARG_H_ +#include "util/debug.h" -#define va_list __builtin_va_list -#define va_start __builtin_va_start -#define va_arg __builtin_va_arg -#define va_copy __builtin_va_copy -#define va_end __builtin_va_end - -#endif //__STDARG_H_ +_Noreturn void abort(void) +{ + OC_ABORT(); +} diff --git a/src/orca-libc/src/exit/atexit.c b/src/orca-libc/src/exit/atexit.c new file mode 100644 index 00000000..666859d2 --- /dev/null +++ b/src/orca-libc/src/exit/atexit.c @@ -0,0 +1,76 @@ +#include +#include +//#include "libc.h" +#include "lock.h" + +/* Ensure that at least 32 atexit handlers can be registered without malloc */ +#define COUNT 32 + +static struct fl +{ + struct fl *next; + void (*f[COUNT])(void *); + void *a[COUNT]; +} builtin, *head; + +static int slot; + +#if defined(_REENTRANT) +static volatile int lock[1]; +volatile int *const __atexit_lockptr = lock; +#endif + +void __funcs_on_exit() +{ + void (*func)(void *), *arg; + LOCK(lock); + for (; head; head=head->next, slot=COUNT) while(slot-->0) { + func = head->f[slot]; + arg = head->a[slot]; + UNLOCK(lock); + func(arg); + LOCK(lock); + } +} + +void __cxa_finalize(void *dso) +{ +} + +int __cxa_atexit(void (*func)(void *), void *arg, void *dso) +{ + LOCK(lock); + + /* Defer initialization of head so it can be in BSS */ + if (!head) head = &builtin; + + /* If the current function list is full, add a new one */ + if (slot==COUNT) { + struct fl *new_fl = calloc(sizeof(struct fl), 1); + if (!new_fl) { + UNLOCK(lock); + return -1; + } + new_fl->next = head; + head = new_fl; + slot = 0; + } + + /* Append function to the list. */ + head->f[slot] = func; + head->a[slot] = arg; + slot++; + + UNLOCK(lock); + return 0; +} + +static void call(void *p) +{ + ((void (*)(void))(uintptr_t)p)(); +} + +int atexit(void (*func)(void)) +{ + return __cxa_atexit(call, (void *)(uintptr_t)func, 0); +} diff --git a/src/orca-libc/src/exit/exit.c b/src/orca-libc/src/exit/exit.c new file mode 100644 index 00000000..032b86a8 --- /dev/null +++ b/src/orca-libc/src/exit/exit.c @@ -0,0 +1,28 @@ +#include +#include + +hidden void __funcs_on_exit(void); + +static void dummy() +{ +} + +/* atexit.c and __stdio_exit.c override these. the latter is linked + * as a consequence of linking either __toread.c or __towrite.c. */ +weak_alias(dummy, __funcs_on_exit); +weak_alias(dummy, __stdio_exit); + +// Split out the cleanup functions so that we can call them without calling +// _Exit if we don't need to. This allows _start to just return if main +// returns 0. +void __wasm_call_dtors(void) +{ + __funcs_on_exit(); + __stdio_exit(); +} + +_Noreturn void exit(int code) +{ + __wasm_call_dtors(); + _Exit(code); +} diff --git a/src/orca-libc/src/fenv/__flt_rounds.c b/src/orca-libc/src/fenv/__flt_rounds.c new file mode 100644 index 00000000..ec0b3689 --- /dev/null +++ b/src/orca-libc/src/fenv/__flt_rounds.c @@ -0,0 +1,19 @@ +#include +#include + +int __flt_rounds() +{ + switch (fegetround()) { +#ifdef FE_TOWARDZERO + case FE_TOWARDZERO: return 0; +#endif + case FE_TONEAREST: return 1; +#ifdef FE_UPWARD + case FE_UPWARD: return 2; +#endif +#ifdef FE_DOWNWARD + case FE_DOWNWARD: return 3; +#endif + } + return -1; +} diff --git a/src/orca-libc/src/fenv/fegetexceptflag.c b/src/orca-libc/src/fenv/fegetexceptflag.c new file mode 100644 index 00000000..bab0b44f --- /dev/null +++ b/src/orca-libc/src/fenv/fegetexceptflag.c @@ -0,0 +1,7 @@ +#include + +int fegetexceptflag(fexcept_t *fp, int mask) +{ + *fp = fetestexcept(mask); + return 0; +} diff --git a/src/orca-libc/src/fenv/feholdexcept.c b/src/orca-libc/src/fenv/feholdexcept.c new file mode 100644 index 00000000..73ff1fad --- /dev/null +++ b/src/orca-libc/src/fenv/feholdexcept.c @@ -0,0 +1,8 @@ +#include + +int feholdexcept(fenv_t *envp) +{ + fegetenv(envp); + feclearexcept(FE_ALL_EXCEPT); + return 0; +} diff --git a/src/orca-libc/src/fenv/fenv.c b/src/orca-libc/src/fenv/fenv.c new file mode 100644 index 00000000..5588dad9 --- /dev/null +++ b/src/orca-libc/src/fenv/fenv.c @@ -0,0 +1,38 @@ +#include + +/* Dummy functions for archs lacking fenv implementation */ + +int feclearexcept(int mask) +{ + return 0; +} + +int feraiseexcept(int mask) +{ + return 0; +} + +int fetestexcept(int mask) +{ + return 0; +} + +int fegetround(void) +{ + return FE_TONEAREST; +} + +int __fesetround(int r) +{ + return 0; +} + +int fegetenv(fenv_t *envp) +{ + return 0; +} + +int fesetenv(const fenv_t *envp) +{ + return 0; +} diff --git a/src/orca-libc/src/fenv/fesetexceptflag.c b/src/orca-libc/src/fenv/fesetexceptflag.c new file mode 100644 index 00000000..af5f102d --- /dev/null +++ b/src/orca-libc/src/fenv/fesetexceptflag.c @@ -0,0 +1,8 @@ +#include + +int fesetexceptflag(const fexcept_t *fp, int mask) +{ + feclearexcept(~*fp & mask); + feraiseexcept(*fp & mask); + return 0; +} diff --git a/src/orca-libc/src/fenv/fesetround.c b/src/orca-libc/src/fenv/fesetround.c new file mode 100644 index 00000000..4e2f164d --- /dev/null +++ b/src/orca-libc/src/fenv/fesetround.c @@ -0,0 +1,23 @@ +#include +#include + +/* __fesetround wrapper for arch independent argument check */ + +hidden int __fesetround(int); + +int fesetround(int r) +{ + if (r != FE_TONEAREST +#ifdef FE_DOWNWARD + && r != FE_DOWNWARD +#endif +#ifdef FE_UPWARD + && r != FE_UPWARD +#endif +#ifdef FE_TOWARDZERO + && r != FE_TOWARDZERO +#endif + ) + return -1; + return __fesetround(r); +} diff --git a/src/orca-libc/src/fenv/feupdateenv.c b/src/orca-libc/src/fenv/feupdateenv.c new file mode 100644 index 00000000..50cef8e5 --- /dev/null +++ b/src/orca-libc/src/fenv/feupdateenv.c @@ -0,0 +1,9 @@ +#include + +int feupdateenv(const fenv_t *envp) +{ + int ex = fetestexcept(FE_ALL_EXCEPT); + fesetenv(envp); + feraiseexcept(ex); + return 0; +} diff --git a/src/orca-libc/src/internal/atomic.h b/src/orca-libc/src/internal/atomic.h new file mode 100644 index 00000000..96c1552d --- /dev/null +++ b/src/orca-libc/src/internal/atomic.h @@ -0,0 +1,333 @@ +#ifndef _ATOMIC_H +#define _ATOMIC_H + +#include + +#include "atomic_arch.h" + +#ifdef a_ll + +#ifndef a_pre_llsc +#define a_pre_llsc() +#endif + +#ifndef a_post_llsc +#define a_post_llsc() +#endif + +#ifndef a_cas +#define a_cas a_cas +static inline int a_cas(volatile int *p, int t, int s) +{ + int old; + a_pre_llsc(); + do old = a_ll(p); + while (old==t && !a_sc(p, s)); + a_post_llsc(); + return old; +} +#endif + +#ifndef a_swap +#define a_swap a_swap +static inline int a_swap(volatile int *p, int v) +{ + int old; + a_pre_llsc(); + do old = a_ll(p); + while (!a_sc(p, v)); + a_post_llsc(); + return old; +} +#endif + +#ifndef a_fetch_add +#define a_fetch_add a_fetch_add +static inline int a_fetch_add(volatile int *p, int v) +{ + int old; + a_pre_llsc(); + do old = a_ll(p); + while (!a_sc(p, (unsigned)old + v)); + a_post_llsc(); + return old; +} +#endif + +#ifndef a_fetch_and +#define a_fetch_and a_fetch_and +static inline int a_fetch_and(volatile int *p, int v) +{ + int old; + a_pre_llsc(); + do old = a_ll(p); + while (!a_sc(p, old & v)); + a_post_llsc(); + return old; +} +#endif + +#ifndef a_fetch_or +#define a_fetch_or a_fetch_or +static inline int a_fetch_or(volatile int *p, int v) +{ + int old; + a_pre_llsc(); + do old = a_ll(p); + while (!a_sc(p, old | v)); + a_post_llsc(); + return old; +} +#endif + +#endif + +#ifdef a_ll_p + +#ifndef a_cas_p +#define a_cas_p a_cas_p +static inline void *a_cas_p(volatile void *p, void *t, void *s) +{ + void *old; + a_pre_llsc(); + do old = a_ll_p(p); + while (old==t && !a_sc_p(p, s)); + a_post_llsc(); + return old; +} +#endif + +#endif + +#ifndef a_cas +#error missing definition of a_cas +#endif + +#ifndef a_swap +#define a_swap a_swap +static inline int a_swap(volatile int *p, int v) +{ + int old; + do old = *p; + while (a_cas(p, old, v) != old); + return old; +} +#endif + +#ifndef a_fetch_add +#define a_fetch_add a_fetch_add +static inline int a_fetch_add(volatile int *p, int v) +{ + int old; + do old = *p; + while (a_cas(p, old, (unsigned)old+v) != old); + return old; +} +#endif + +#ifndef a_fetch_and +#define a_fetch_and a_fetch_and +static inline int a_fetch_and(volatile int *p, int v) +{ + int old; + do old = *p; + while (a_cas(p, old, old&v) != old); + return old; +} +#endif +#ifndef a_fetch_or +#define a_fetch_or a_fetch_or +static inline int a_fetch_or(volatile int *p, int v) +{ + int old; + do old = *p; + while (a_cas(p, old, old|v) != old); + return old; +} +#endif + +#ifndef a_and +#define a_and a_and +static inline void a_and(volatile int *p, int v) +{ + a_fetch_and(p, v); +} +#endif + +#ifndef a_or +#define a_or a_or +static inline void a_or(volatile int *p, int v) +{ + a_fetch_or(p, v); +} +#endif + +#ifndef a_inc +#define a_inc a_inc +static inline void a_inc(volatile int *p) +{ + a_fetch_add(p, 1); +} +#endif + +#ifndef a_dec +#define a_dec a_dec +static inline void a_dec(volatile int *p) +{ + a_fetch_add(p, -1); +} +#endif + +#ifndef a_store +#define a_store a_store +static inline void a_store(volatile int *p, int v) +{ +#ifdef a_barrier + a_barrier(); + *p = v; + a_barrier(); +#else + a_swap(p, v); +#endif +} +#endif + +#ifndef a_barrier +#define a_barrier a_barrier +static void a_barrier() +{ + volatile int tmp = 0; + a_cas(&tmp, 0, 0); +} +#endif + +#ifndef a_spin +#define a_spin a_barrier +#endif + +#ifndef a_and_64 +#define a_and_64 a_and_64 +static inline void a_and_64(volatile uint64_t *p, uint64_t v) +{ + union { uint64_t v; uint32_t r[2]; } u = { v }; + if (u.r[0]+1) a_and((int *)p, u.r[0]); + if (u.r[1]+1) a_and((int *)p+1, u.r[1]); +} +#endif + +#ifndef a_or_64 +#define a_or_64 a_or_64 +static inline void a_or_64(volatile uint64_t *p, uint64_t v) +{ + union { uint64_t v; uint32_t r[2]; } u = { v }; + if (u.r[0]) a_or((int *)p, u.r[0]); + if (u.r[1]) a_or((int *)p+1, u.r[1]); +} +#endif + +#ifndef a_cas_p +typedef char a_cas_p_undefined_but_pointer_not_32bit[-sizeof(char) == 0xffffffff ? 1 : -1]; +#define a_cas_p a_cas_p +static inline void *a_cas_p(volatile void *p, void *t, void *s) +{ + return (void *)a_cas((volatile int *)p, (int)t, (int)s); +} +#endif + +#ifndef a_or_l +#define a_or_l a_or_l +static inline void a_or_l(volatile void *p, long v) +{ + if (sizeof(long) == sizeof(int)) a_or(p, v); + else a_or_64(p, v); +} +#endif + +#ifndef a_crash +#define a_crash a_crash +static inline void a_crash() +{ + *(volatile char *)0=0; +} +#endif + +#ifndef a_ctz_32 +#define a_ctz_32 a_ctz_32 +static inline int a_ctz_32(uint32_t x) +{ +#ifdef a_clz_32 + return 31-a_clz_32(x&-x); +#else + static const char debruijn32[32] = { + 0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13, + 31, 22, 28, 18, 26, 10, 7, 12, 21, 17, 9, 6, 16, 5, 15, 14 + }; + return debruijn32[(x&-x)*0x076be629 >> 27]; +#endif +} +#endif + +#ifndef a_ctz_64 +#define a_ctz_64 a_ctz_64 +static inline int a_ctz_64(uint64_t x) +{ + static const char debruijn64[64] = { + 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, + 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, + 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, + 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12 + }; + if (sizeof(long) < 8) { + uint32_t y = x; + if (!y) { + y = x>>32; + return 32 + a_ctz_32(y); + } + return a_ctz_32(y); + } + return debruijn64[(x&-x)*0x022fdd63cc95386dull >> 58]; +} +#endif + +static inline int a_ctz_l(unsigned long x) +{ + return (sizeof(long) < 8) ? a_ctz_32(x) : a_ctz_64(x); +} + +#ifndef a_clz_64 +#define a_clz_64 a_clz_64 +static inline int a_clz_64(uint64_t x) +{ +#ifdef a_clz_32 + if (x>>32) + return a_clz_32(x>>32); + return a_clz_32(x) + 32; +#else + uint32_t y; + int r; + if (x>>32) y=x>>32, r=0; else y=x, r=32; + if (y>>16) y>>=16; else r |= 16; + if (y>>8) y>>=8; else r |= 8; + if (y>>4) y>>=4; else r |= 4; + if (y>>2) y>>=2; else r |= 2; + return r | !(y>>1); +#endif +} +#endif + +#ifndef a_clz_32 +#define a_clz_32 a_clz_32 +static inline int a_clz_32(uint32_t x) +{ + x >>= 1; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + x++; + return 31-a_ctz_32(x); +} +#endif + +#endif diff --git a/src/orca-libc/src/internal/atomic_arch.h b/src/orca-libc/src/internal/atomic_arch.h new file mode 100644 index 00000000..c24ce2d7 --- /dev/null +++ b/src/orca-libc/src/internal/atomic_arch.h @@ -0,0 +1,6 @@ +#define a_cas(p, t, s) (__sync_val_compare_and_swap((p), (t), (s))) +#define a_crash() (__builtin_trap()) +#define a_clz_32 __builtin_clz +#define a_clz_64 __builtin_clzll +#define a_ctz_32 __builtin_ctz +#define a_ctz_64 __builtin_ctzll diff --git a/src/orca-libc/src/internal/complex_impl.h b/src/orca-libc/src/internal/complex_impl.h new file mode 100644 index 00000000..51fb298a --- /dev/null +++ b/src/orca-libc/src/internal/complex_impl.h @@ -0,0 +1,22 @@ +#ifndef _COMPLEX_IMPL_H +#define _COMPLEX_IMPL_H + +#include +#include "libm.h" + +#undef __CMPLX +#undef CMPLX +#undef CMPLXF +#undef CMPLXL + +#define __CMPLX(x, y, t) \ + ((union { _Complex t __z; t __xy[2]; }){.__xy = {(x),(y)}}.__z) + +#define CMPLX(x, y) __CMPLX(x, y, double) +#define CMPLXF(x, y) __CMPLX(x, y, float) +#define CMPLXL(x, y) __CMPLX(x, y, long double) + +hidden double complex __ldexp_cexp(double complex,int); +hidden float complex __ldexp_cexpf(float complex,int); + +#endif diff --git a/src/orca-libc/src/internal/features.h b/src/orca-libc/src/internal/features.h new file mode 100644 index 00000000..ec1061f7 --- /dev/null +++ b/src/orca-libc/src/internal/features.h @@ -0,0 +1,11 @@ +#ifndef FEATURES_H +#define FEATURES_H + +#include "../../include/features.h" + +#define weak __attribute__((__weak__)) +#define hidden __attribute__((__visibility__("hidden"))) +# define weak_alias(old, new) \ + extern __typeof(old) new __attribute__((__weak__, __alias__(#old))) + +#endif diff --git a/src/orca-libc/src/internal/floatscan.c b/src/orca-libc/src/internal/floatscan.c new file mode 100644 index 00000000..b1b5b96f --- /dev/null +++ b/src/orca-libc/src/internal/floatscan.c @@ -0,0 +1,508 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "shgetc.h" +#include "floatscan.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 + +#define LD_B1B_DIG 2 +#define LD_B1B_MAX 9007199, 254740991 +#define KMAX 128 + +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 + +#define LD_B1B_DIG 3 +#define LD_B1B_MAX 18, 446744073, 709551615 +#define KMAX 2048 + +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 + +#define LD_B1B_DIG 4 +#define LD_B1B_MAX 10384593, 717069655, 257060992, 658440191 +#define KMAX 2048 + +#else +#error Unsupported long double representation +#endif + +#define MASK (KMAX-1) + +static long long scanexp(FILE *f, int pok) +{ + int c; + int x; + long long y; + int neg = 0; + + c = shgetc(f); + if (c=='+' || c=='-') { + neg = (c=='-'); + c = shgetc(f); + if (c-'0'>=10U && pok) shunget(f); + } + if (c-'0'>=10U) { + shunget(f); + return LLONG_MIN; + } + for (x=0; c-'0'<10U && x=0) { + shunget(f); + } + if (!gotdig) { + errno = EINVAL; + shlim(f, 0); + return 0; + } + + /* Handle zero specially to avoid nasty special cases later */ + if (!x[0]) return sign * 0.0; + + /* Optimize small integers (w/no exponent) and over/under-flow */ + if (lrp==dc && dc<10 && (bits>30 || x[0]>>bits==0)) + return sign * (long double)x[0]; + if (lrp > -emin/2) { + errno = ERANGE; + return sign * LDBL_MAX * LDBL_MAX; + } + if (lrp < emin-2*LDBL_MANT_DIG) { + errno = ERANGE; + return sign * LDBL_MIN * LDBL_MIN; + } + + /* Align incomplete final B1B digit */ + if (j) { + for (; j<9; j++) x[k]*=10; + k++; + j=0; + } + + a = 0; + z = k; + e2 = 0; + rp = lrp; + + /* Optimize small to mid-size integers (even in exp. notation) */ + if (lnz<9 && lnz<=rp && rp < 18) { + if (rp == 9) return sign * (long double)x[0]; + if (rp < 9) return sign * (long double)x[0] / p10s[8-rp]; + + int bitlim = bits-3*(int)(rp-9); + if (bitlim>30 || x[0]>>bitlim==0) + return sign * (long double)x[0] * p10s[rp-10]; + } + + /* Drop trailing zeros */ + for (; !x[z-1]; z--); + + /* Align radix point to B1B digit boundary */ + if (rp % 9) { + int rpm9 = rp>=0 ? rp%9 : rp%9+9; + int p10 = p10s[8-rpm9]; + uint32_t carry = 0; + for (k=a; k!=z; k++) { + uint32_t tmp = x[k] % p10; + x[k] = x[k]/p10 + carry; + carry = 1000000000/p10 * tmp; + if (k==a && !x[k]) { + a = (a+1 & MASK); + rp -= 9; + } + } + if (carry) x[z++] = carry; + rp += 9-rpm9; + } + + /* Upscale until desired number of bits are left of radix point */ + while (rp < 9*LD_B1B_DIG || (rp == 9*LD_B1B_DIG && x[a] 1000000000) { + carry = tmp / 1000000000; + x[k] = tmp % 1000000000; + } else { + carry = 0; + x[k] = tmp; + } + if (k==(z-1 & MASK) && k!=a && !x[k]) z = k; + if (k==a) break; + } + if (carry) { + rp += 9; + a = (a-1 & MASK); + if (a == z) { + z = (z-1 & MASK); + x[z-1 & MASK] |= x[z]; + } + x[a] = carry; + } + } + + /* Downscale until exactly number of bits are left of radix point */ + for (;;) { + uint32_t carry = 0; + int sh = 1; + for (i=0; i th[i]) break; + } + if (i==LD_B1B_DIG && rp==9*LD_B1B_DIG) break; + /* FIXME: find a way to compute optimal sh */ + if (rp > 9+9*LD_B1B_DIG) sh = 9; + e2 += sh; + for (k=a; k!=z; k=(k+1 & MASK)) { + uint32_t tmp = x[k] & (1<>sh) + carry; + carry = (1000000000>>sh) * tmp; + if (k==a && !x[k]) { + a = (a+1 & MASK); + i--; + rp -= 9; + } + } + if (carry) { + if ((z+1 & MASK) != a) { + x[z] = carry; + z = (z+1 & MASK); + } else x[z-1 & MASK] |= 1; + } + } + + /* Assemble desired bits into floating point variable */ + for (y=i=0; i LDBL_MANT_DIG+e2-emin) { + bits = LDBL_MANT_DIG+e2-emin; + if (bits<0) bits=0; + denormal = 1; + } + + /* Calculate bias term to force rounding, move out lower bits */ + if (bits < LDBL_MANT_DIG) { + bias = copysignl(scalbn(1, 2*LDBL_MANT_DIG-bits-1), y); + frac = fmodl(y, scalbn(1, LDBL_MANT_DIG-bits)); + y -= frac; + y += bias; + } + + /* Process tail of decimal input so it can affect rounding */ + if ((a+i & MASK) != z) { + uint32_t t = x[a+i & MASK]; + if (t < 500000000 && (t || (a+i+1 & MASK) != z)) + frac += 0.25*sign; + else if (t > 500000000) + frac += 0.75*sign; + else if (t == 500000000) { + if ((a+i+1 & MASK) == z) + frac += 0.5*sign; + else + frac += 0.75*sign; + } + if (LDBL_MANT_DIG-bits >= 2 && !fmodl(frac, 1)) + frac++; + } + + y += frac; + y -= bias; + + if ((e2+LDBL_MANT_DIG & INT_MAX) > emax-5) { + if (fabsl(y) >= 2/LDBL_EPSILON) { + if (denormal && bits==LDBL_MANT_DIG+e2-emin) + denormal = 0; + y *= 0.5; + e2++; + } + if (e2+LDBL_MANT_DIG>emax || (denormal && frac)) + errno = ERANGE; + } + + return scalbnl(y, e2); +} + +static long double hexfloat(FILE *f, int bits, int emin, int sign, int pok) +{ + uint32_t x = 0; + long double y = 0; + long double scale = 1; + long double bias = 0; + int gottail = 0, gotrad = 0, gotdig = 0; + long long rp = 0; + long long dc = 0; + long long e2 = 0; + int d; + int c; + + c = shgetc(f); + + /* Skip leading zeros */ + for (; c=='0'; c = shgetc(f)) gotdig = 1; + + if (c=='.') { + gotrad = 1; + c = shgetc(f); + /* Count zeros after the radix point before significand */ + for (rp=0; c=='0'; c = shgetc(f), rp--) gotdig = 1; + } + + for (; c-'0'<10U || (c|32)-'a'<6U || c=='.'; c = shgetc(f)) { + if (c=='.') { + if (gotrad) break; + rp = dc; + gotrad = 1; + } else { + gotdig = 1; + if (c > '9') d = (c|32)+10-'a'; + else d = c-'0'; + if (dc<8) { + x = x*16 + d; + } else if (dc < LDBL_MANT_DIG/4+1) { + y += d*(scale/=16); + } else if (d && !gottail) { + y += 0.5*scale; + gottail = 1; + } + dc++; + } + } + if (!gotdig) { + shunget(f); + if (pok) { + shunget(f); + if (gotrad) shunget(f); + } else { + shlim(f, 0); + } + return sign * 0.0; + } + if (!gotrad) rp = dc; + while (dc<8) x *= 16, dc++; + if ((c|32)=='p') { + e2 = scanexp(f, pok); + if (e2 == LLONG_MIN) { + if (pok) { + shunget(f); + } else { + shlim(f, 0); + return 0; + } + e2 = 0; + } + } else { + shunget(f); + } + e2 += 4*rp - 32; + + if (!x) return sign * 0.0; + if (e2 > -emin) { + errno = ERANGE; + return sign * LDBL_MAX * LDBL_MAX; + } + if (e2 < emin-2*LDBL_MANT_DIG) { + errno = ERANGE; + return sign * LDBL_MIN * LDBL_MIN; + } + + while (x < 0x80000000) { + if (y>=0.5) { + x += x + 1; + y += y - 1; + } else { + x += x; + y += y; + } + e2--; + } + + if (bits > 32+e2-emin) { + bits = 32+e2-emin; + if (bits<0) bits=0; + } + + if (bits < LDBL_MANT_DIG) + bias = copysignl(scalbn(1, 32+LDBL_MANT_DIG-bits-1), sign); + + if (bits<32 && y && !(x&1)) x++, y=0; + + y = bias + sign*(long double)x + sign*y; + y -= bias; + + if (!y) errno = ERANGE; + + return scalbnl(y, e2); +} + +long double __floatscan(FILE *f, int prec, int pok) +{ + int sign = 1; + size_t i; + int bits; + int emin; + int c; + + switch (prec) { + case 0: + bits = FLT_MANT_DIG; + emin = FLT_MIN_EXP-bits; + break; + case 1: + bits = DBL_MANT_DIG; + emin = DBL_MIN_EXP-bits; + break; + case 2: + bits = LDBL_MANT_DIG; + emin = LDBL_MIN_EXP-bits; + break; + default: + return 0; + } + + while (isspace((c=shgetc(f)))); + + if (c=='+' || c=='-') { + sign -= 2*(c=='-'); + c = shgetc(f); + } + + for (i=0; i<8 && (c|32)=="infinity"[i]; i++) + if (i<7) c = shgetc(f); + if (i==3 || i==8 || (i>3 && pok)) { + if (i!=8) { + shunget(f); + if (pok) for (; i>3; i--) shunget(f); + } + return sign * INFINITY; + } + if (!i) for (i=0; i<3 && (c|32)=="nan"[i]; i++) + if (i<2) c = shgetc(f); + if (i==3) { + if (shgetc(f) != '(') { + shunget(f); + return NAN; + } + for (i=1; ; i++) { + c = shgetc(f); + if (c-'0'<10U || c-'A'<26U || c-'a'<26U || c=='_') + continue; + if (c==')') return NAN; + shunget(f); + if (!pok) { + errno = EINVAL; + shlim(f, 0); + return 0; + } + while (i--) shunget(f); + return NAN; + } + return NAN; + } + + if (i) { + shunget(f); + errno = EINVAL; + shlim(f, 0); + return 0; + } + + if (c=='0') { + c = shgetc(f); + if ((c|32) == 'x') + return hexfloat(f, bits, emin, sign, pok); + shunget(f); + c = '0'; + } + + return decfloat(f, c, bits, emin, sign, pok); +} diff --git a/src/orca-libc/src/internal/floatscan.h b/src/orca-libc/src/internal/floatscan.h new file mode 100644 index 00000000..f2b1dcf4 --- /dev/null +++ b/src/orca-libc/src/internal/floatscan.h @@ -0,0 +1,8 @@ +#ifndef FLOATSCAN_H +#define FLOATSCAN_H + +#include + +hidden long double __floatscan(FILE *, int, int); + +#endif diff --git a/src/orca-libc/src/internal/fp_arch.h b/src/orca-libc/src/internal/fp_arch.h new file mode 100644 index 00000000..707d5127 --- /dev/null +++ b/src/orca-libc/src/internal/fp_arch.h @@ -0,0 +1,25 @@ +// WebAssembly has no floating-point exceptions or alternate rounding modes, +// so there's no need to prevent expressions from moving or force their +// evaluation. + +#define fp_barrierf fp_barrierf +static inline float fp_barrierf(float x) +{ + return x; +} + +#define fp_barrier fp_barrier +static inline double fp_barrier(double x) +{ + return x; +} + +#define fp_force_evalf fp_force_evalf +static inline void fp_force_evalf(float x) +{ +} + +#define fp_force_eval fp_force_eval +static inline void fp_force_eval(double x) +{ +} diff --git a/src/orca-libc/src/internal/intscan.c b/src/orca-libc/src/internal/intscan.c new file mode 100644 index 00000000..a4a5ae86 --- /dev/null +++ b/src/orca-libc/src/internal/intscan.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include "shgetc.h" + +/* Lookup table for digit values. -1==255>=36 -> invalid */ +static const unsigned char table[] = { -1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, +-1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, +25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1, +-1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, +25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +}; + +unsigned long long __intscan(FILE *f, unsigned base, int pok, unsigned long long lim) +{ + const unsigned char *val = table+1; + int c, neg=0; + unsigned x; + unsigned long long y; + if (base > 36 || base == 1) { + errno = EINVAL; + return 0; + } + while (isspace((c=shgetc(f)))); + if (c=='+' || c=='-') { + neg = -(c=='-'); + c = shgetc(f); + } + if ((base == 0 || base == 16) && c=='0') { + c = shgetc(f); + if ((c|32)=='x') { + c = shgetc(f); + if (val[c]>=16) { + shunget(f); + if (pok) shunget(f); + else shlim(f, 0); + return 0; + } + base = 16; + } else if (base == 0) { + base = 8; + } + } else { + if (base == 0) base = 10; + if (val[c] >= base) { + shunget(f); + shlim(f, 0); + errno = EINVAL; + return 0; + } + } + if (base == 10) { + for (x=0; c-'0'<10U && x<=UINT_MAX/10-1; c=shgetc(f)) + x = x*10 + (c-'0'); + for (y=x; c-'0'<10U && y<=ULLONG_MAX/10 && 10*y<=ULLONG_MAX-(c-'0'); c=shgetc(f)) + y = y*10 + (c-'0'); + if (c-'0'>=10U) goto done; + } else if (!(base & base-1)) { + int bs = "\0\1\2\4\7\3\6\5"[(0x17*base)>>5&7]; + for (x=0; val[c]>bs; c=shgetc(f)) + y = y<=lim) { + if (!(lim&1) && !neg) { + errno = ERANGE; + return lim-1; + } else if (y>lim) { + errno = ERANGE; + return lim; + } + } + return (y^neg)-neg; +} diff --git a/src/orca-libc/src/internal/intscan.h b/src/orca-libc/src/internal/intscan.h new file mode 100644 index 00000000..ccf9f112 --- /dev/null +++ b/src/orca-libc/src/internal/intscan.h @@ -0,0 +1,8 @@ +#ifndef INTSCAN_H +#define INTSCAN_H + +#include + +hidden unsigned long long __intscan(FILE *, unsigned, int, unsigned long long); + +#endif diff --git a/src/orca-libc/src/internal/libm.h b/src/orca-libc/src/internal/libm.h new file mode 100644 index 00000000..10a33e9c --- /dev/null +++ b/src/orca-libc/src/internal/libm.h @@ -0,0 +1,269 @@ +#ifndef _LIBM_H +#define _LIBM_H + +#include +#include +#include +#include +#include "fp_arch.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN +union ldshape { + long double f; + struct { + uint64_t m; + uint16_t se; + } i; +}; +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __BIG_ENDIAN +/* This is the m68k variant of 80-bit long double, and this definition only works + * on archs where the alignment requirement of uint64_t is <= 4. */ +union ldshape { + long double f; + struct { + uint16_t se; + uint16_t pad; + uint64_t m; + } i; +}; +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN +union ldshape { + long double f; + struct { + uint64_t lo; + uint32_t mid; + uint16_t top; + uint16_t se; + } i; + struct { + uint64_t lo; + uint64_t hi; + } i2; +}; +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __BIG_ENDIAN +union ldshape { + long double f; + struct { + uint16_t se; + uint16_t top; + uint32_t mid; + uint64_t lo; + } i; + struct { + uint64_t hi; + uint64_t lo; + } i2; +}; +#else +#error Unsupported long double representation +#endif + +/* Support non-nearest rounding mode. */ +#define WANT_ROUNDING 0 // Wasm doesn't have alternate rounding modes + +/* Support signaling NaNs. */ +#define WANT_SNAN 0 + +#if WANT_SNAN +#error SNaN is unsupported +#else +#define issignalingf_inline(x) 0 +#define issignaling_inline(x) 0 +#endif + +#ifndef TOINT_INTRINSICS +#define TOINT_INTRINSICS 0 +#endif + +#if TOINT_INTRINSICS +/* Round x to nearest int in all rounding modes, ties have to be rounded + consistently with converttoint so the results match. If the result + would be outside of [-2^31, 2^31-1] then the semantics is unspecified. */ +static double_t roundtoint(double_t); + +/* Convert x to nearest int in all rounding modes, ties have to be rounded + consistently with roundtoint. If the result is not representible in an + int32_t then the semantics is unspecified. */ +static int32_t converttoint(double_t); +#endif + +/* Helps static branch prediction so hot path can be better optimized. */ +#ifdef __GNUC__ +#define predict_true(x) __builtin_expect(!!(x), 1) +#define predict_false(x) __builtin_expect(x, 0) +#else +#define predict_true(x) (x) +#define predict_false(x) (x) +#endif + +/* Evaluate an expression as the specified type. With standard excess + precision handling a type cast or assignment is enough (with + -ffloat-store an assignment is required, in old compilers argument + passing and return statement may not drop excess precision). */ + +static inline float eval_as_float(float x) +{ + float y = x; + return y; +} + +static inline double eval_as_double(double x) +{ + double y = x; + return y; +} + +/* fp_barrier returns its input, but limits code transformations + as if it had a side-effect (e.g. observable io) and returned + an arbitrary value. */ + +#ifndef fp_barrierf +#define fp_barrierf fp_barrierf +static inline float fp_barrierf(float x) +{ + volatile float y = x; + return y; +} +#endif + +#ifndef fp_barrier +#define fp_barrier fp_barrier +static inline double fp_barrier(double x) +{ + volatile double y = x; + return y; +} +#endif + +#ifndef fp_barrierl +#define fp_barrierl fp_barrierl +static inline long double fp_barrierl(long double x) +{ + volatile long double y = x; + return y; +} +#endif + +/* fp_force_eval ensures that the input value is computed when that's + otherwise unused. To prevent the constant folding of the input + expression, an additional fp_barrier may be needed or a compilation + mode that does so (e.g. -frounding-math in gcc). Then it can be + used to evaluate an expression for its fenv side-effects only. */ + +#ifndef fp_force_evalf +#define fp_force_evalf fp_force_evalf +static inline void fp_force_evalf(float x) +{ + volatile float y; + y = x; +} +#endif + +#ifndef fp_force_eval +#define fp_force_eval fp_force_eval +static inline void fp_force_eval(double x) +{ + volatile double y; + y = x; +} +#endif + +#ifndef fp_force_evall +#define fp_force_evall fp_force_evall +static inline void fp_force_evall(long double x) +{ + volatile long double y; + y = x; +} +#endif + +/* WebAssembly doesn't have floating-point status flags, so there's no reason + * to force evaluations. */ +#define FORCE_EVAL(x) ((void)(x)) + +#define asuint(f) ((union{float _f; uint32_t _i;}){f})._i +#define asfloat(i) ((union{uint32_t _i; float _f;}){i})._f +#define asuint64(f) ((union{double _f; uint64_t _i;}){f})._i +#define asdouble(i) ((union{uint64_t _i; double _f;}){i})._f + +#define EXTRACT_WORDS(hi,lo,d) \ +do { \ + uint64_t __u = asuint64(d); \ + (hi) = __u >> 32; \ + (lo) = (uint32_t)__u; \ +} while (0) + +#define GET_HIGH_WORD(hi,d) \ +do { \ + (hi) = asuint64(d) >> 32; \ +} while (0) + +#define GET_LOW_WORD(lo,d) \ +do { \ + (lo) = (uint32_t)asuint64(d); \ +} while (0) + +#define INSERT_WORDS(d,hi,lo) \ +do { \ + (d) = asdouble(((uint64_t)(hi)<<32) | (uint32_t)(lo)); \ +} while (0) + +#define SET_HIGH_WORD(d,hi) \ + INSERT_WORDS(d, hi, (uint32_t)asuint64(d)) + +#define SET_LOW_WORD(d,lo) \ + INSERT_WORDS(d, asuint64(d)>>32, lo) + +#define GET_FLOAT_WORD(w,d) \ +do { \ + (w) = asuint(d); \ +} while (0) + +#define SET_FLOAT_WORD(d,w) \ +do { \ + (d) = asfloat(w); \ +} while (0) + +hidden int __rem_pio2_large(double*,double*,int,int,int); + +hidden int __rem_pio2(double,double*); +hidden double __sin(double,double,int); +hidden double __cos(double,double); +hidden double __tan(double,double,int); +hidden double __expo2(double); // Wasm doesn't have alternate rounding modes + +hidden int __rem_pio2f(float,double*); +hidden float __sindf(double); +hidden float __cosdf(double); +hidden float __tandf(double,int); +hidden float __expo2f(float); // Wasm doesn't have alternate rounding modes + +hidden int __rem_pio2l(long double, long double *); +hidden long double __sinl(long double, long double, int); +hidden long double __cosl(long double, long double); +hidden long double __tanl(long double, long double, int); + +hidden long double __polevll(long double, const long double *, int); +hidden long double __p1evll(long double, const long double *, int); + +extern int __signgam; +hidden double __lgamma_r(double, int *); +hidden float __lgammaf_r(float, int *); + +/* error handling functions */ +hidden float __math_xflowf(uint32_t, float); +hidden float __math_uflowf(uint32_t); +hidden float __math_oflowf(uint32_t); +hidden float __math_divzerof(uint32_t); +hidden float __math_invalidf(float); +hidden double __math_xflow(uint32_t, double); +hidden double __math_uflow(uint32_t); +hidden double __math_oflow(uint32_t); +hidden double __math_divzero(uint32_t); +hidden double __math_invalid(double); +#if LDBL_MANT_DIG != DBL_MANT_DIG +hidden long double __math_invalidl(long double); +#endif + +#endif diff --git a/src/orca-libc/src/internal/lock.h b/src/orca-libc/src/internal/lock.h new file mode 100644 index 00000000..98ff5fab --- /dev/null +++ b/src/orca-libc/src/internal/lock.h @@ -0,0 +1,8 @@ +#ifndef LOCK_H +#define LOCK_H + +// No locking needed. +#define LOCK(x) ((void)0) +#define UNLOCK(x) ((void)0) + +#endif diff --git a/src/orca-libc/src/internal/sh/__shcall.c b/src/orca-libc/src/internal/sh/__shcall.c new file mode 100644 index 00000000..4e073e8f --- /dev/null +++ b/src/orca-libc/src/internal/sh/__shcall.c @@ -0,0 +1,6 @@ +#include + +hidden int __shcall(void *arg, int (*func)(void *)) +{ + return func(arg); +} diff --git a/src/orca-libc/src/internal/shgetc.c b/src/orca-libc/src/internal/shgetc.c new file mode 100644 index 00000000..7455d2f0 --- /dev/null +++ b/src/orca-libc/src/internal/shgetc.c @@ -0,0 +1,37 @@ +#include "shgetc.h" + +/* The shcnt field stores the number of bytes read so far, offset by + * the value of buf-rpos at the last function call (__shlim or __shgetc), + * so that between calls the inline shcnt macro can add rpos-buf to get + * the actual count. */ + +void __shlim(FILE *f, off_t lim) +{ + f->shlim = lim; + f->shcnt = f->buf - f->rpos; + /* If lim is nonzero, rend must be a valid pointer. */ + if (lim && f->rend - f->rpos > lim) + f->shend = f->rpos + lim; + else + f->shend = f->rend; +} + +int __shgetc(FILE *f) +{ + int c; + off_t cnt = shcnt(f); + if (f->shlim && cnt >= f->shlim || (c=__uflow(f)) < 0) { + f->shcnt = f->buf - f->rpos + cnt; + f->shend = f->rpos; + f->shlim = -1; + return EOF; + } + cnt++; + if (f->shlim && f->rend - f->rpos > f->shlim - cnt) + f->shend = f->rpos + (f->shlim - cnt); + else + f->shend = f->rend; + f->shcnt = f->buf - f->rpos + cnt; + if (f->rpos <= f->buf) f->rpos[-1] = c; + return c; +} diff --git a/src/orca-libc/src/internal/shgetc.h b/src/orca-libc/src/internal/shgetc.h new file mode 100644 index 00000000..9435381a --- /dev/null +++ b/src/orca-libc/src/internal/shgetc.h @@ -0,0 +1,32 @@ +#include "stdio_impl.h" + +/* Scan helper "stdio" functions for use by scanf-family and strto*-family + * functions. These accept either a valid stdio FILE, or a minimal pseudo + * FILE whose buffer pointers point into a null-terminated string. In the + * latter case, the sh_fromstring macro should be used to setup the FILE; + * the rest of the structure can be left uninitialized. + * + * To begin using these functions, shlim must first be called on the FILE + * to set a field width limit, or 0 for no limit. For string pseudo-FILEs, + * a nonzero limit is not valid and produces undefined behavior. After that, + * shgetc, shunget, and shcnt are valid as long as no other stdio functions + * are called on the stream. + * + * When used with a real FILE object, shunget has only one byte of pushback + * available. Further shunget (up to a limit of the stdio UNGET buffer size) + * will adjust the position but will not restore the data to be read again. + * This functionality is needed for the wcsto*-family functions, where it's + * okay because the FILE will be discarded immediately anyway. When used + * with string pseudo-FILEs, shunget has unlimited pushback, back to the + * beginning of the string. */ + +hidden void __shlim(FILE *, off_t); +hidden int __shgetc(FILE *); + +#define shcnt(f) ((f)->shcnt + ((f)->rpos - (f)->buf)) +#define shlim(f, lim) __shlim((f), (lim)) +#define shgetc(f) (((f)->rpos != (f)->shend) ? *(f)->rpos++ : __shgetc(f)) +#define shunget(f) ((f)->shlim>=0 ? (void)(f)->rpos-- : (void)0) + +#define sh_fromstring(f, s) \ + ((f)->buf = (f)->rpos = (void *)(s), (f)->rend = (void*)-1) diff --git a/src/orca-libc/src/internal/stdio_impl.h b/src/orca-libc/src/internal/stdio_impl.h new file mode 100644 index 00000000..38bc48b3 --- /dev/null +++ b/src/orca-libc/src/internal/stdio_impl.h @@ -0,0 +1,129 @@ +#ifndef _STDIO_IMPL_H +#define _STDIO_IMPL_H + +#include + +#define UNGET 8 + +#if defined(_REENTRANT) + #define FFINALLOCK(f) ((f)->lock >= 0 ? __lockfile((f)) : 0) + #define FLOCK(f) int __need_unlock = ((f)->lock >= 0 ? __lockfile((f)) : 0) + #define FUNLOCK(f) \ + do \ + { \ + if(__need_unlock) \ + __unlockfile((f)); \ + } \ + while(0) +#else + // No locking needed. + #define FFINALLOCK(f) ((void)(f)) + #define FLOCK(f) ((void)(f)) + #define FUNLOCK(f) ((void)(f)) +#endif + +#define F_PERM 1 +#define F_NORD 4 +#define F_NOWR 8 +#define F_EOF 16 +#define F_ERR 32 +#define F_SVB 64 +#define F_APP 128 + +struct _IO_FILE +{ + long long unsigned orca_file; + unsigned flags; + unsigned char *rpos, *rend; + int (*close)(FILE*); + unsigned char *wend, *wpos; + + unsigned char* wbase; + size_t (*read)(FILE*, unsigned char*, size_t); + size_t (*write)(FILE*, const unsigned char*, size_t); + off_t (*seek)(FILE*, off_t, int); + unsigned char* buf; + size_t buf_size; + FILE *prev, *next; + +#if defined(_REENTRANT) + long lockcount; +#endif + int mode; +#if defined(_REENTRANT) + volatile int lock; +#endif + int lbf; + void* cookie; + off_t off; + char* getln_buf; + + unsigned char* shend; + off_t shlim, shcnt; +#if defined(_REENTRANT) + FILE *prev_locked, *next_locked; +#endif + struct __locale_struct* locale; +}; + +extern hidden FILE* volatile __stdin_used; +extern hidden FILE* volatile __stdout_used; +extern hidden FILE* volatile __stderr_used; + +#if defined(_REENTRANT) +hidden int __lockfile(FILE*); +hidden void __unlockfile(FILE*); +#endif + +hidden size_t __file_read_err_shim(FILE* stream, unsigned char* buffer, size_t size); +hidden size_t __file_write_err_shim(FILE* stream, const unsigned char* buffer, size_t size); +hidden off_t __file_seek_err_shim(FILE* stream, off_t offset, int origin); +hidden int __file_close_err_shim(FILE* stream); + +hidden int __toread(FILE*); +hidden int __towrite(FILE*); + +hidden void __stdio_exit(void); +hidden void __stdio_exit_needed(void); + +int __overflow(FILE*, int), __uflow(FILE*); + +hidden int __fseeko(FILE*, off_t, int); +hidden int __fseeko_unlocked(FILE*, off_t, int); +hidden off_t __ftello(FILE*); +hidden off_t __ftello_unlocked(FILE*); +hidden size_t __fwritex(const unsigned char*, size_t, FILE*); +hidden int __putc_unlocked(int, FILE*); + +hidden FILE* __fdopen(long long unsigned, const char*); +hidden int __fmodeflags(const char*); + +hidden FILE* __ofl_add(FILE* f); +hidden FILE** __ofl_lock(void); +hidden void __ofl_unlock(void); + +struct __pthread; +hidden void __register_locked_file(FILE*, struct __pthread*); +hidden void __unlist_locked_file(FILE*); +hidden void __do_orphaned_stdio_locks(void); + +#define MAYBE_WAITERS 0x40000000 + +hidden void __getopt_msg(const char*, const char*, const char*, size_t); + +#define getc_unlocked(f) \ + (((f)->rpos != (f)->rend) ? *(f)->rpos++ : __uflow((f))) + +#define putc_unlocked(c, f) \ + ((((unsigned char)(c) != (f)->lbf && (f)->wpos != (f)->wend)) \ + ? *(f)->wpos++ = (unsigned char)(c) \ + : __overflow((f), (unsigned char)(c))) + +/* Caller-allocated FILE * operations */ +hidden FILE* __fopen_rb_ca(const char*, FILE*, unsigned char*, size_t); +hidden int __fclose_ca(FILE*); + +// Functions not exposed to orca but used with dummy FILE structs +hidden int vsscanf(const char* restrict s, const char* restrict fmt, va_list ap); +hidden int vfscanf(FILE* restrict f, const char* restrict fmt, va_list ap); +#endif diff --git a/src/orca-libc/src/internal/string.h b/src/orca-libc/src/internal/string.h new file mode 100644 index 00000000..2133b5c1 --- /dev/null +++ b/src/orca-libc/src/internal/string.h @@ -0,0 +1,11 @@ +#ifndef STRING_H +#define STRING_H + +#include "../../include/string.h" + +hidden void *__memrchr(const void *, int, size_t); +hidden char *__stpcpy(char *, const char *); +hidden char *__stpncpy(char *, const char *, size_t); +hidden char *__strchrnul(const char *, int); + +#endif diff --git a/src/platform/orca_malloc.c b/src/orca-libc/src/malloc/orca_dlmalloc.c similarity index 99% rename from src/platform/orca_malloc.c rename to src/orca-libc/src/malloc/orca_dlmalloc.c index abc32583..f9aea015 100644 --- a/src/platform/orca_malloc.c +++ b/src/orca-libc/src/malloc/orca_dlmalloc.c @@ -6,6 +6,7 @@ * **************************************************************************/ #include +#include #include // Orca-specific defines @@ -13,7 +14,9 @@ #define LACKS_UNISTD_H #define LACKS_SYS_PARAM_H -extern void* oc_mem_grow(u64 size); +__attribute__((import_name("oc_mem_grow"))) +void* oc_mem_grow(uint64_t size); + #define MORECORE oc_mem_grow #define MORECORE_CONTIGUOUS 0 /* diff --git a/src/libc-shim/src/__cos.c b/src/orca-libc/src/math/__cos.c similarity index 79% rename from src/libc-shim/src/__cos.c rename to src/orca-libc/src/math/__cos.c index 424b34b9..46cefb38 100644 --- a/src/libc-shim/src/__cos.c +++ b/src/orca-libc/src/math/__cos.c @@ -51,21 +51,21 @@ #include "libm.h" static const double - C1 = 4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */ - C2 = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */ - C3 = 2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */ - C4 = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */ - C5 = 2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */ - C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ +C1 = 4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */ +C2 = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */ +C3 = 2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */ +C4 = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */ +C5 = 2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */ +C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ double __cos(double x, double y) { - double_t hz, z, r, w; + double_t hz,z,r,w; - z = x * x; - w = z * z; - r = z * (C1 + z * (C2 + z * C3)) + w * w * (C4 + z * (C5 + z * C6)); - hz = 0.5 * z; - w = 1.0 - hz; - return w + (((1.0 - w) - hz) + (z * r - x * y)); + z = x*x; + w = z*z; + r = z*(C1+z*(C2+z*C3)) + w*w*(C4+z*(C5+z*C6)); + hz = 0.5*z; + w = 1.0-hz; + return w + (((1.0-w)-hz) + (z*r-x*y)); } diff --git a/src/libc-shim/src/__cosdf.c b/src/orca-libc/src/math/__cosdf.c similarity index 60% rename from src/libc-shim/src/__cosdf.c rename to src/orca-libc/src/math/__cosdf.c index 5f19c26f..2124989b 100644 --- a/src/libc-shim/src/__cosdf.c +++ b/src/orca-libc/src/math/__cosdf.c @@ -18,18 +18,18 @@ /* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ static const double - C0 = -0x1ffffffd0c5e81.0p-54, /* -0.499999997251031003120 */ - C1 = 0x155553e1053a42.0p-57, /* 0.0416666233237390631894 */ - C2 = -0x16c087e80f1e27.0p-62, /* -0.00138867637746099294692 */ - C3 = 0x199342e0ee5069.0p-68; /* 0.0000243904487962774090654 */ +C0 = -0x1ffffffd0c5e81.0p-54, /* -0.499999997251031003120 */ +C1 = 0x155553e1053a42.0p-57, /* 0.0416666233237390631894 */ +C2 = -0x16c087e80f1e27.0p-62, /* -0.00138867637746099294692 */ +C3 = 0x199342e0ee5069.0p-68; /* 0.0000243904487962774090654 */ float __cosdf(double x) { - double_t r, w, z; + double_t r, w, z; - /* Try to optimize for parallel evaluation as in __tandf.c. */ - z = x * x; - w = z * z; - r = C2 + z * C3; - return ((1.0 + z * C0) + w * C1) + (w * z) * r; + /* Try to optimize for parallel evaluation as in __tandf.c. */ + z = x*x; + w = z*z; + r = C2+z*C3; + return ((1.0+z*C0) + w*C1) + (w*z)*r; } diff --git a/src/orca-libc/src/math/__cosl.c b/src/orca-libc/src/math/__cosl.c new file mode 100644 index 00000000..fa522ddd --- /dev/null +++ b/src/orca-libc/src/math/__cosl.c @@ -0,0 +1,96 @@ +/* origin: FreeBSD /usr/src/lib/msun/ld80/k_cosl.c */ +/* origin: FreeBSD /usr/src/lib/msun/ld128/k_cosl.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + + +#include "libm.h" + +#if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#if LDBL_MANT_DIG == 64 +/* + * ld80 version of __cos.c. See __cos.c for most comments. + */ +/* + * Domain [-0.7854, 0.7854], range ~[-2.43e-23, 2.425e-23]: + * |cos(x) - c(x)| < 2**-75.1 + * + * The coefficients of c(x) were generated by a pari-gp script using + * a Remez algorithm that searches for the best higher coefficients + * after rounding leading coefficients to a specified precision. + * + * Simpler methods like Chebyshev or basic Remez barely suffice for + * cos() in 64-bit precision, because we want the coefficient of x^2 + * to be precisely -0.5 so that multiplying by it is exact, and plain + * rounding of the coefficients of a good polynomial approximation only + * gives this up to about 64-bit precision. Plain rounding also gives + * a mediocre approximation for the coefficient of x^4, but a rounding + * error of 0.5 ulps for this coefficient would only contribute ~0.01 + * ulps to the final error, so this is unimportant. Rounding errors in + * higher coefficients are even less important. + * + * In fact, coefficients above the x^4 one only need to have 53-bit + * precision, and this is more efficient. We get this optimization + * almost for free from the complications needed to search for the best + * higher coefficients. + */ +static const long double +C1 = 0.0416666666666666666136L; /* 0xaaaaaaaaaaaaaa9b.0p-68 */ +static const double +C2 = -0.0013888888888888874, /* -0x16c16c16c16c10.0p-62 */ +C3 = 0.000024801587301571716, /* 0x1a01a01a018e22.0p-68 */ +C4 = -0.00000027557319215507120, /* -0x127e4fb7602f22.0p-74 */ +C5 = 0.0000000020876754400407278, /* 0x11eed8caaeccf1.0p-81 */ +C6 = -1.1470297442401303e-11, /* -0x19393412bd1529.0p-89 */ +C7 = 4.7383039476436467e-14; /* 0x1aac9d9af5c43e.0p-97 */ +#define POLY(z) (z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*(C6+z*C7))))))) +#elif LDBL_MANT_DIG == 113 +/* + * ld128 version of __cos.c. See __cos.c for most comments. + */ +/* + * Domain [-0.7854, 0.7854], range ~[-1.80e-37, 1.79e-37]: + * |cos(x) - c(x))| < 2**-122.0 + * + * 113-bit precision requires more care than 64-bit precision, since + * simple methods give a minimax polynomial with coefficient for x^2 + * that is 1 ulp below 0.5, but we want it to be precisely 0.5. See + * above for more details. + */ +static const long double +C1 = 0.04166666666666666666666666666666658424671L, +C2 = -0.001388888888888888888888888888863490893732L, +C3 = 0.00002480158730158730158730158600795304914210L, +C4 = -0.2755731922398589065255474947078934284324e-6L, +C5 = 0.2087675698786809897659225313136400793948e-8L, +C6 = -0.1147074559772972315817149986812031204775e-10L, +C7 = 0.4779477332386808976875457937252120293400e-13L; +static const double +C8 = -0.1561920696721507929516718307820958119868e-15, +C9 = 0.4110317413744594971475941557607804508039e-18, +C10 = -0.8896592467191938803288521958313920156409e-21, +C11 = 0.1601061435794535138244346256065192782581e-23; +#define POLY(z) (z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*(C6+z*(C7+ \ + z*(C8+z*(C9+z*(C10+z*C11))))))))))) +#endif + +long double __cosl(long double x, long double y) +{ + long double hz,z,r,w; + + z = x*x; + r = POLY(z); + hz = 0.5*z; + w = 1.0-hz; + return w + (((1.0-w)-hz) + (z*r-x*y)); +} +#endif diff --git a/src/orca-libc/src/math/__expo2.c b/src/orca-libc/src/math/__expo2.c new file mode 100644 index 00000000..4ff17df4 --- /dev/null +++ b/src/orca-libc/src/math/__expo2.c @@ -0,0 +1,25 @@ +#include "libm.h" + +/* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */ +static const int k = 2043; +static const double kln2 = 0x1.62066151add8bp+10; + +/* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */ +#ifdef __wasilibc_unmodified_upstream // Wasm doesn't have alternate rounding modes +double __expo2(double x, double sign) +#else +double __expo2(double x) +#endif +{ + double scale; + + /* note that k is odd and scale*scale overflows */ + INSERT_WORDS(scale, (uint32_t)(0x3ff + k/2) << 20, 0); + /* exp(x - k ln2) * 2**(k-1) */ +#ifdef __wasilibc_unmodified_upstream // Wasm doesn't have alternate rounding modes + /* in directed rounding correct sign before rounding or overflow is important */ + return exp(x - kln2) * (sign * scale) * scale; +#else + return exp(x - kln2) * scale * scale; +#endif +} diff --git a/src/orca-libc/src/math/__expo2f.c b/src/orca-libc/src/math/__expo2f.c new file mode 100644 index 00000000..acbaeb4c --- /dev/null +++ b/src/orca-libc/src/math/__expo2f.c @@ -0,0 +1,25 @@ +#include "libm.h" + +/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ +static const int k = 235; +static const float kln2 = 0x1.45c778p+7f; + +/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ +#ifdef __wasilibc_unmodified_upstream // Wasm doesn't have alternate rounding modes +float __expo2f(float x, float sign) +#else +float __expo2f(float x) +#endif +{ + float scale; + + /* note that k is odd and scale*scale overflows */ + SET_FLOAT_WORD(scale, (uint32_t)(0x7f + k/2) << 23); + /* exp(x - k ln2) * 2**(k-1) */ +#ifdef __wasilibc_unmodified_upstream // Wasm doesn't have alternate rounding modes + /* in directed rounding correct sign before rounding or overflow is important */ + return expf(x - kln2) * (sign * scale) * scale; +#else + return expf(x - kln2) * scale * scale; +#endif +} diff --git a/src/orca-libc/src/math/__fpclassify.c b/src/orca-libc/src/math/__fpclassify.c new file mode 100644 index 00000000..f7c0e2df --- /dev/null +++ b/src/orca-libc/src/math/__fpclassify.c @@ -0,0 +1,11 @@ +#include +#include + +int __fpclassify(double x) +{ + union {double f; uint64_t i;} u = {x}; + int e = u.i>>52 & 0x7ff; + if (!e) return u.i<<1 ? FP_SUBNORMAL : FP_ZERO; + if (e==0x7ff) return u.i<<12 ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} diff --git a/src/orca-libc/src/math/__fpclassifyf.c b/src/orca-libc/src/math/__fpclassifyf.c new file mode 100644 index 00000000..fd00eb1b --- /dev/null +++ b/src/orca-libc/src/math/__fpclassifyf.c @@ -0,0 +1,11 @@ +#include +#include + +int __fpclassifyf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = u.i>>23 & 0xff; + if (!e) return u.i<<1 ? FP_SUBNORMAL : FP_ZERO; + if (e==0xff) return u.i<<9 ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} diff --git a/src/orca-libc/src/math/__fpclassifyl.c b/src/orca-libc/src/math/__fpclassifyl.c new file mode 100644 index 00000000..e41781b6 --- /dev/null +++ b/src/orca-libc/src/math/__fpclassifyl.c @@ -0,0 +1,42 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +int __fpclassifyl(long double x) +{ + return __fpclassify(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +int __fpclassifyl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + int msb = u.i.m>>63; + if (!e && !msb) + return u.i.m ? FP_SUBNORMAL : FP_ZERO; + if (e == 0x7fff) { + /* The x86 variant of 80-bit extended precision only admits + * one representation of each infinity, with the mantissa msb + * necessarily set. The version with it clear is invalid/nan. + * The m68k variant, however, allows either, and tooling uses + * the version with it clear. */ + if (__BYTE_ORDER == __LITTLE_ENDIAN && !msb) + return FP_NAN; + return u.i.m << 1 ? FP_NAN : FP_INFINITE; + } + if (!msb) + return FP_NAN; + return FP_NORMAL; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +int __fpclassifyl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + u.i.se = 0; + if (!e) + return u.i2.lo | u.i2.hi ? FP_SUBNORMAL : FP_ZERO; + if (e == 0x7fff) + return u.i2.lo | u.i2.hi ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} +#endif diff --git a/src/orca-libc/src/math/__invtrigl.c b/src/orca-libc/src/math/__invtrigl.c new file mode 100644 index 00000000..48f83aaf --- /dev/null +++ b/src/orca-libc/src/math/__invtrigl.c @@ -0,0 +1,63 @@ +#include +#include "__invtrigl.h" + +#if LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +static const long double +pS0 = 1.66666666666666666631e-01L, +pS1 = -4.16313987993683104320e-01L, +pS2 = 3.69068046323246813704e-01L, +pS3 = -1.36213932016738603108e-01L, +pS4 = 1.78324189708471965733e-02L, +pS5 = -2.19216428382605211588e-04L, +pS6 = -7.10526623669075243183e-06L, +qS1 = -2.94788392796209867269e+00L, +qS2 = 3.27309890266528636716e+00L, +qS3 = -1.68285799854822427013e+00L, +qS4 = 3.90699412641738801874e-01L, +qS5 = -3.14365703596053263322e-02L; + +const long double pio2_hi = 1.57079632679489661926L; +const long double pio2_lo = -2.50827880633416601173e-20L; + +/* used in asinl() and acosl() */ +/* R(x^2) is a rational approximation of (asin(x)-x)/x^3 with Remez algorithm */ +long double __invtrigl_R(long double z) +{ + long double p, q; + p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*(pS5+z*pS6)))))); + q = 1.0+z*(qS1+z*(qS2+z*(qS3+z*(qS4+z*qS5)))); + return p/q; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +static const long double +pS0 = 1.66666666666666666666666666666700314e-01L, +pS1 = -7.32816946414566252574527475428622708e-01L, +pS2 = 1.34215708714992334609030036562143589e+00L, +pS3 = -1.32483151677116409805070261790752040e+00L, +pS4 = 7.61206183613632558824485341162121989e-01L, +pS5 = -2.56165783329023486777386833928147375e-01L, +pS6 = 4.80718586374448793411019434585413855e-02L, +pS7 = -4.42523267167024279410230886239774718e-03L, +pS8 = 1.44551535183911458253205638280410064e-04L, +pS9 = -2.10558957916600254061591040482706179e-07L, +qS1 = -4.84690167848739751544716485245697428e+00L, +qS2 = 9.96619113536172610135016921140206980e+00L, +qS3 = -1.13177895428973036660836798461641458e+01L, +qS4 = 7.74004374389488266169304117714658761e+00L, +qS5 = -3.25871986053534084709023539900339905e+00L, +qS6 = 8.27830318881232209752469022352928864e-01L, +qS7 = -1.18768052702942805423330715206348004e-01L, +qS8 = 8.32600764660522313269101537926539470e-03L, +qS9 = -1.99407384882605586705979504567947007e-04L; + +const long double pio2_hi = 1.57079632679489661923132169163975140L; +const long double pio2_lo = 4.33590506506189051239852201302167613e-35L; + +long double __invtrigl_R(long double z) +{ + long double p, q; + p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*(pS5+z*(pS6+z*(pS7+z*(pS8+z*pS9))))))))); + q = 1.0+z*(qS1+z*(qS2+z*(qS3+z*(qS4+z*(qS5+z*(qS6+z*(qS7+z*(qS8+z*qS9)))))))); + return p/q; +} +#endif diff --git a/src/orca-libc/src/math/__invtrigl.h b/src/orca-libc/src/math/__invtrigl.h new file mode 100644 index 00000000..bee79317 --- /dev/null +++ b/src/orca-libc/src/math/__invtrigl.h @@ -0,0 +1,8 @@ +#include + +/* shared by acosl, asinl and atan2l */ +#define pio2_hi __pio2_hi +#define pio2_lo __pio2_lo +hidden extern const long double pio2_hi, pio2_lo; + +hidden long double __invtrigl_R(long double z); diff --git a/src/orca-libc/src/math/__math_divzero.c b/src/orca-libc/src/math/__math_divzero.c new file mode 100644 index 00000000..59d21350 --- /dev/null +++ b/src/orca-libc/src/math/__math_divzero.c @@ -0,0 +1,6 @@ +#include "libm.h" + +double __math_divzero(uint32_t sign) +{ + return fp_barrier(sign ? -1.0 : 1.0) / 0.0; +} diff --git a/src/orca-libc/src/math/__math_divzerof.c b/src/orca-libc/src/math/__math_divzerof.c new file mode 100644 index 00000000..ce046f3e --- /dev/null +++ b/src/orca-libc/src/math/__math_divzerof.c @@ -0,0 +1,6 @@ +#include "libm.h" + +float __math_divzerof(uint32_t sign) +{ + return fp_barrierf(sign ? -1.0f : 1.0f) / 0.0f; +} diff --git a/src/libc-shim/src/__math_invalid.c b/src/orca-libc/src/math/__math_invalid.c similarity index 64% rename from src/libc-shim/src/__math_invalid.c rename to src/orca-libc/src/math/__math_invalid.c index fa42cd9f..17740490 100644 --- a/src/libc-shim/src/__math_invalid.c +++ b/src/orca-libc/src/math/__math_invalid.c @@ -2,5 +2,5 @@ double __math_invalid(double x) { - return (x - x) / (x - x); + return (x - x) / (x - x); } diff --git a/src/libc-shim/src/__math_invalidf.c b/src/orca-libc/src/math/__math_invalidf.c similarity index 64% rename from src/libc-shim/src/__math_invalidf.c rename to src/orca-libc/src/math/__math_invalidf.c index 7fc9cb5e..357d4b12 100644 --- a/src/libc-shim/src/__math_invalidf.c +++ b/src/orca-libc/src/math/__math_invalidf.c @@ -2,5 +2,5 @@ float __math_invalidf(float x) { - return (x - x) / (x - x); + return (x - x) / (x - x); } diff --git a/src/orca-libc/src/math/__math_invalidl.c b/src/orca-libc/src/math/__math_invalidl.c new file mode 100644 index 00000000..1fca99de --- /dev/null +++ b/src/orca-libc/src/math/__math_invalidl.c @@ -0,0 +1,9 @@ +#include +#include "libm.h" + +#if LDBL_MANT_DIG != DBL_MANT_DIG +long double __math_invalidl(long double x) +{ + return (x - x) / (x - x); +} +#endif diff --git a/src/libc-shim/src/__math_oflow.c b/src/orca-libc/src/math/__math_oflow.c similarity index 59% rename from src/libc-shim/src/__math_oflow.c rename to src/orca-libc/src/math/__math_oflow.c index a197e797..c85dbf98 100644 --- a/src/libc-shim/src/__math_oflow.c +++ b/src/orca-libc/src/math/__math_oflow.c @@ -2,5 +2,5 @@ double __math_oflow(uint32_t sign) { - return __math_xflow(sign, 0x1p769); + return __math_xflow(sign, 0x1p769); } diff --git a/src/libc-shim/src/__math_oflowf.c b/src/orca-libc/src/math/__math_oflowf.c similarity index 100% rename from src/libc-shim/src/__math_oflowf.c rename to src/orca-libc/src/math/__math_oflowf.c diff --git a/src/libc-shim/src/__math_uflow.c b/src/orca-libc/src/math/__math_uflow.c similarity index 58% rename from src/libc-shim/src/__math_uflow.c rename to src/orca-libc/src/math/__math_uflow.c index 7e4c0c26..b90594ae 100644 --- a/src/libc-shim/src/__math_uflow.c +++ b/src/orca-libc/src/math/__math_uflow.c @@ -2,5 +2,5 @@ double __math_uflow(uint32_t sign) { - return __math_xflow(sign, 0x1p-767); + return __math_xflow(sign, 0x1p-767); } diff --git a/src/libc-shim/src/__math_uflowf.c b/src/orca-libc/src/math/__math_uflowf.c similarity index 100% rename from src/libc-shim/src/__math_uflowf.c rename to src/orca-libc/src/math/__math_uflowf.c diff --git a/src/orca-libc/src/math/__math_xflow.c b/src/orca-libc/src/math/__math_xflow.c new file mode 100644 index 00000000..744203c4 --- /dev/null +++ b/src/orca-libc/src/math/__math_xflow.c @@ -0,0 +1,6 @@ +#include "libm.h" + +double __math_xflow(uint32_t sign, double y) +{ + return eval_as_double(fp_barrier(sign ? -y : y) * y); +} diff --git a/src/orca-libc/src/math/__math_xflowf.c b/src/orca-libc/src/math/__math_xflowf.c new file mode 100644 index 00000000..f2c84784 --- /dev/null +++ b/src/orca-libc/src/math/__math_xflowf.c @@ -0,0 +1,6 @@ +#include "libm.h" + +float __math_xflowf(uint32_t sign, float y) +{ + return eval_as_float(fp_barrierf(sign ? -y : y) * y); +} diff --git a/src/orca-libc/src/math/__polevll.c b/src/orca-libc/src/math/__polevll.c new file mode 100644 index 00000000..ce1a8404 --- /dev/null +++ b/src/orca-libc/src/math/__polevll.c @@ -0,0 +1,93 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/polevll.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Evaluate polynomial + * + * + * SYNOPSIS: + * + * int N; + * long double x, y, coef[N+1], polevl[]; + * + * y = polevll( x, coef, N ); + * + * + * DESCRIPTION: + * + * Evaluates polynomial of degree N: + * + * 2 N + * y = C + C x + C x +...+ C x + * 0 1 2 N + * + * Coefficients are stored in reverse order: + * + * coef[0] = C , ..., coef[N] = C . + * N 0 + * + * The function p1evll() assumes that coef[N] = 1.0 and is + * omitted from the array. Its calling arguments are + * otherwise the same as polevll(). + * + * + * SPEED: + * + * In the interest of speed, there are no checks for out + * of bounds arithmetic. This routine is used by most of + * the functions in the library. Depending on available + * equipment features, the user may wish to rewrite the + * program in microcode or assembly language. + * + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +#else +/* + * Polynomial evaluator: + * P[0] x^n + P[1] x^(n-1) + ... + P[n] + */ +long double __polevll(long double x, const long double *P, int n) +{ + long double y; + + y = *P++; + do { + y = y * x + *P++; + } while (--n); + + return y; +} + +/* + * Polynomial evaluator: + * x^n + P[0] x^(n-1) + P[1] x^(n-2) + ... + P[n] + */ +long double __p1evll(long double x, const long double *P, int n) +{ + long double y; + + n -= 1; + y = x + *P++; + do { + y = y * x + *P++; + } while (--n); + + return y; +} +#endif diff --git a/src/orca-libc/src/math/__rem_pio2.c b/src/orca-libc/src/math/__rem_pio2.c new file mode 100644 index 00000000..326cda75 --- /dev/null +++ b/src/orca-libc/src/math/__rem_pio2.c @@ -0,0 +1,194 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * Optimized by Bruce D. Evans. + */ +/* __rem_pio2(x,y) + * + * return the remainder of x rem pi/2 in y[0]+y[1] + * use __rem_pio2_large() for large x + */ + +#include "libm.h" + +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif + +/* + * invpio2: 53 bits of 2/pi + * pio2_1: first 33 bit of pi/2 + * pio2_1t: pi/2 - pio2_1 + * pio2_2: second 33 bit of pi/2 + * pio2_2t: pi/2 - (pio2_1+pio2_2) + * pio2_3: third 33 bit of pi/2 + * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3) + */ +static const double +toint = 1.5/EPS, +#ifdef __wasilibc_unmodified_upstream // Wasm doesn't have alternate rounding modes +pio4 = 0x1.921fb54442d18p-1, +#endif +invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ +pio2_1 = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */ +pio2_1t = 6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */ +pio2_2 = 6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */ +pio2_2t = 2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */ +pio2_3 = 2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */ +pio2_3t = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ + +/* caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ +int __rem_pio2(double x, double *y) +{ + union {double f; uint64_t i;} u = {x}; + double_t z,w,t,r,fn; + double tx[3],ty[2]; + uint32_t ix; + int sign, n, ex, ey, i; + + sign = u.i>>63; + ix = u.i>>32 & 0x7fffffff; + if (ix <= 0x400f6a7a) { /* |x| ~<= 5pi/4 */ + if ((ix & 0xfffff) == 0x921fb) /* |x| ~= pi/2 or 2pi/2 */ + goto medium; /* cancellation -- use medium case */ + if (ix <= 0x4002d97c) { /* |x| ~<= 3pi/4 */ + if (!sign) { + z = x - pio2_1; /* one round good to 85 bits */ + y[0] = z - pio2_1t; + y[1] = (z-y[0]) - pio2_1t; + return 1; + } else { + z = x + pio2_1; + y[0] = z + pio2_1t; + y[1] = (z-y[0]) + pio2_1t; + return -1; + } + } else { + if (!sign) { + z = x - 2*pio2_1; + y[0] = z - 2*pio2_1t; + y[1] = (z-y[0]) - 2*pio2_1t; + return 2; + } else { + z = x + 2*pio2_1; + y[0] = z + 2*pio2_1t; + y[1] = (z-y[0]) + 2*pio2_1t; + return -2; + } + } + } + if (ix <= 0x401c463b) { /* |x| ~<= 9pi/4 */ + if (ix <= 0x4015fdbc) { /* |x| ~<= 7pi/4 */ + if (ix == 0x4012d97c) /* |x| ~= 3pi/2 */ + goto medium; + if (!sign) { + z = x - 3*pio2_1; + y[0] = z - 3*pio2_1t; + y[1] = (z-y[0]) - 3*pio2_1t; + return 3; + } else { + z = x + 3*pio2_1; + y[0] = z + 3*pio2_1t; + y[1] = (z-y[0]) + 3*pio2_1t; + return -3; + } + } else { + if (ix == 0x401921fb) /* |x| ~= 4pi/2 */ + goto medium; + if (!sign) { + z = x - 4*pio2_1; + y[0] = z - 4*pio2_1t; + y[1] = (z-y[0]) - 4*pio2_1t; + return 4; + } else { + z = x + 4*pio2_1; + y[0] = z + 4*pio2_1t; + y[1] = (z-y[0]) + 4*pio2_1t; + return -4; + } + } + } + if (ix < 0x413921fb) { /* |x| ~< 2^20*(pi/2), medium size */ +medium: + /* rint(x/(pi/2)) */ + fn = (double_t)x*invpio2 + toint - toint; + n = (int32_t)fn; + r = x - fn*pio2_1; + w = fn*pio2_1t; /* 1st round, good to 85 bits */ +#ifdef __wasilibc_unmodified_upstream // Wasm doesn't have alternate rounding modes + /* Matters with directed rounding. */ + if (predict_false(r - w < -pio4)) { + n--; + fn--; + r = x - fn*pio2_1; + w = fn*pio2_1t; + } else if (predict_false(r - w > pio4)) { + n++; + fn++; + r = x - fn*pio2_1; + w = fn*pio2_1t; + } +#endif + y[0] = r - w; + u.f = y[0]; + ey = u.i>>52 & 0x7ff; + ex = ix>>20; + if (ex - ey > 16) { /* 2nd round, good to 118 bits */ + t = r; + w = fn*pio2_2; + r = t - w; + w = fn*pio2_2t - ((t-r)-w); + y[0] = r - w; + u.f = y[0]; + ey = u.i>>52 & 0x7ff; + if (ex - ey > 49) { /* 3rd round, good to 151 bits, covers all cases */ + t = r; + w = fn*pio2_3; + r = t - w; + w = fn*pio2_3t - ((t-r)-w); + y[0] = r - w; + } + } + y[1] = (r - y[0]) - w; + return n; + } + /* + * all other (large) arguments + */ + if (ix >= 0x7ff00000) { /* x is inf or NaN */ + y[0] = y[1] = x - x; + return 0; + } + /* set z = scalbn(|x|,-ilogb(x)+23) */ + u.f = x; + u.i &= (uint64_t)-1>>12; + u.i |= (uint64_t)(0x3ff + 23)<<52; + z = u.f; + for (i=0; i < 2; i++) { + tx[i] = (double)(int32_t)z; + z = (z-tx[i])*0x1p24; + } + tx[i] = z; + /* skip zero terms, first term is non-zero */ + while (tx[i] == 0.0) + i--; + n = __rem_pio2_large(tx,ty,(int)(ix>>20)-(0x3ff+23),i+1,1); + if (sign) { + y[0] = -ty[0]; + y[1] = -ty[1]; + return -n; + } + y[0] = ty[0]; + y[1] = ty[1]; + return n; +} diff --git a/src/orca-libc/src/math/__rem_pio2_large.c b/src/orca-libc/src/math/__rem_pio2_large.c new file mode 100644 index 00000000..958f28c2 --- /dev/null +++ b/src/orca-libc/src/math/__rem_pio2_large.c @@ -0,0 +1,442 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_rem_pio2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * __rem_pio2_large(x,y,e0,nx,prec) + * double x[],y[]; int e0,nx,prec; + * + * __rem_pio2_large return the last three digits of N with + * y = x - N*pi/2 + * so that |y| < pi/2. + * + * The method is to compute the integer (mod 8) and fraction parts of + * (2/pi)*x without doing the full multiplication. In general we + * skip the part of the product that are known to be a huge integer ( + * more accurately, = 0 mod 8 ). Thus the number of operations are + * independent of the exponent of the input. + * + * (2/pi) is represented by an array of 24-bit integers in ipio2[]. + * + * Input parameters: + * x[] The input value (must be positive) is broken into nx + * pieces of 24-bit integers in double precision format. + * x[i] will be the i-th 24 bit of x. The scaled exponent + * of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 + * match x's up to 24 bits. + * + * Example of breaking a double positive z into x[0]+x[1]+x[2]: + * e0 = ilogb(z)-23 + * z = scalbn(z,-e0) + * for i = 0,1,2 + * x[i] = floor(z) + * z = (z-x[i])*2**24 + * + * + * y[] ouput result in an array of double precision numbers. + * The dimension of y[] is: + * 24-bit precision 1 + * 53-bit precision 2 + * 64-bit precision 2 + * 113-bit precision 3 + * The actual value is the sum of them. Thus for 113-bit + * precison, one may have to do something like: + * + * long double t,w,r_head, r_tail; + * t = (long double)y[2] + (long double)y[1]; + * w = (long double)y[0]; + * r_head = t+w; + * r_tail = w - (r_head - t); + * + * e0 The exponent of x[0]. Must be <= 16360 or you need to + * expand the ipio2 table. + * + * nx dimension of x[] + * + * prec an integer indicating the precision: + * 0 24 bits (single) + * 1 53 bits (double) + * 2 64 bits (extended) + * 3 113 bits (quad) + * + * External function: + * double scalbn(), floor(); + * + * + * Here is the description of some local variables: + * + * jk jk+1 is the initial number of terms of ipio2[] needed + * in the computation. The minimum and recommended value + * for jk is 3,4,4,6 for single, double, extended, and quad. + * jk+1 must be 2 larger than you might expect so that our + * recomputation test works. (Up to 24 bits in the integer + * part (the 24 bits of it that we compute) and 23 bits in + * the fraction part may be lost to cancelation before we + * recompute.) + * + * jz local integer variable indicating the number of + * terms of ipio2[] used. + * + * jx nx - 1 + * + * jv index for pointing to the suitable ipio2[] for the + * computation. In general, we want + * ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 + * is an integer. Thus + * e0-3-24*jv >= 0 or (e0-3)/24 >= jv + * Hence jv = max(0,(e0-3)/24). + * + * jp jp+1 is the number of terms in PIo2[] needed, jp = jk. + * + * q[] double array with integral value, representing the + * 24-bits chunk of the product of x and 2/pi. + * + * q0 the corresponding exponent of q[0]. Note that the + * exponent for q[i] would be q0-24*i. + * + * PIo2[] double precision array, obtained by cutting pi/2 + * into 24 bits chunks. + * + * f[] ipio2[] in floating point + * + * iq[] integer array by breaking up q[] in 24-bits chunk. + * + * fq[] final product of x*(2/pi) in fq[0],..,fq[jk] + * + * ih integer. If >0 it indicates q[] is >= 0.5, hence + * it also indicates the *sign* of the result. + * + */ +/* + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "libm.h" + +static const int init_jk[] = {3,4,4,6}; /* initial value for jk */ + +/* + * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi + * + * integer array, contains the (24*i)-th to (24*i+23)-th + * bit of 2/pi after binary point. The corresponding + * floating value is + * + * ipio2[i] * 2^(-24(i+1)). + * + * NB: This table must have at least (e0-3)/24 + jk terms. + * For quad precision (e0 <= 16360, jk = 6), this is 686. + */ +static const int32_t ipio2[] = { +0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, +0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, +0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, +0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, +0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, +0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, +0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, +0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, +0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, +0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, +0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, + +#if LDBL_MAX_EXP > 1024 +0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, +0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, +0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35, +0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, +0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, +0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4, +0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, +0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, +0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19, +0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, +0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, +0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6, +0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, +0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, +0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3, +0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, +0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, +0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612, +0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, +0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, +0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B, +0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, +0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, +0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB, +0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, +0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, +0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F, +0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, +0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, +0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B, +0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, +0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, +0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3, +0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, +0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, +0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F, +0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, +0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, +0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51, +0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, +0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, +0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6, +0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, +0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, +0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328, +0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, +0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, +0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B, +0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, +0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, +0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F, +0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, +0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, +0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4, +0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, +0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, +0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30, +0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, +0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, +0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1, +0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, +0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, +0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08, +0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, +0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, +0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4, +0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, +0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, +0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0, +0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, +0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, +0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC, +0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, +0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, +0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7, +0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, +0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, +0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4, +0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, +0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, +0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2, +0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, +0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, +0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569, +0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, +0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, +0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D, +0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, +0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, +0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569, +0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, +0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, +0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41, +0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, +0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, +0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110, +0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, +0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, +0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A, +0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, +0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, +0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616, +0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, +0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0, +#endif +}; + +static const double PIo2[] = { + 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ + 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ + 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ + 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ + 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ + 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ + 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ + 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ +}; + +int __rem_pio2_large(double *x, double *y, int e0, int nx, int prec) +{ + int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih; + double z,fw,f[20],fq[20],q[20]; + + /* initialize jk*/ + jk = init_jk[prec]; + jp = jk; + + /* determine jx,jv,q0, note that 3>q0 */ + jx = nx-1; + jv = (e0-3)/24; if(jv<0) jv=0; + q0 = e0-24*(jv+1); + + /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ + j = jv-jx; m = jx+jk; + for (i=0; i<=m; i++,j++) + f[i] = j<0 ? 0.0 : (double)ipio2[j]; + + /* compute q[0],q[1],...q[jk] */ + for (i=0; i<=jk; i++) { + for (j=0,fw=0.0; j<=jx; j++) + fw += x[j]*f[jx+i-j]; + q[i] = fw; + } + + jz = jk; +recompute: + /* distill q[] into iq[] reversingly */ + for (i=0,j=jz,z=q[jz]; j>0; i++,j--) { + fw = (double)(int32_t)(0x1p-24*z); + iq[i] = (int32_t)(z - 0x1p24*fw); + z = q[j-1]+fw; + } + + /* compute n */ + z = scalbn(z,q0); /* actual value of z */ + z -= 8.0*floor(z*0.125); /* trim off integer >= 8 */ + n = (int32_t)z; + z -= (double)n; + ih = 0; + if (q0 > 0) { /* need iq[jz-1] to determine n */ + i = iq[jz-1]>>(24-q0); n += i; + iq[jz-1] -= i<<(24-q0); + ih = iq[jz-1]>>(23-q0); + } + else if (q0 == 0) ih = iq[jz-1]>>23; + else if (z >= 0.5) ih = 2; + + if (ih > 0) { /* q > 0.5 */ + n += 1; carry = 0; + for (i=0; i 0) { /* rare case: chance is 1 in 12 */ + switch(q0) { + case 1: + iq[jz-1] &= 0x7fffff; break; + case 2: + iq[jz-1] &= 0x3fffff; break; + } + } + if (ih == 2) { + z = 1.0 - z; + if (carry != 0) + z -= scalbn(1.0,q0); + } + } + + /* check if recomputation is needed */ + if (z == 0.0) { + j = 0; + for (i=jz-1; i>=jk; i--) j |= iq[i]; + if (j == 0) { /* need recomputation */ + for (k=1; iq[jk-k]==0; k++); /* k = no. of terms needed */ + + for (i=jz+1; i<=jz+k; i++) { /* add q[jz+1] to q[jz+k] */ + f[jx+i] = (double)ipio2[jv+i]; + for (j=0,fw=0.0; j<=jx; j++) + fw += x[j]*f[jx+i-j]; + q[i] = fw; + } + jz += k; + goto recompute; + } + } + + /* chop off zero terms */ + if (z == 0.0) { + jz -= 1; + q0 -= 24; + while (iq[jz] == 0) { + jz--; + q0 -= 24; + } + } else { /* break z into 24-bit if necessary */ + z = scalbn(z,-q0); + if (z >= 0x1p24) { + fw = (double)(int32_t)(0x1p-24*z); + iq[jz] = (int32_t)(z - 0x1p24*fw); + jz += 1; + q0 += 24; + iq[jz] = (int32_t)fw; + } else + iq[jz] = (int32_t)z; + } + + /* convert integer "bit" chunk to floating-point value */ + fw = scalbn(1.0,q0); + for (i=jz; i>=0; i--) { + q[i] = fw*(double)iq[i]; + fw *= 0x1p-24; + } + + /* compute PIo2[0,...,jp]*q[jz,...,0] */ + for(i=jz; i>=0; i--) { + for (fw=0.0,k=0; k<=jp && k<=jz-i; k++) + fw += PIo2[k]*q[i+k]; + fq[jz-i] = fw; + } + + /* compress fq[] into y[] */ + switch(prec) { + case 0: + fw = 0.0; + for (i=jz; i>=0; i--) + fw += fq[i]; + y[0] = ih==0 ? fw : -fw; + break; + case 1: + case 2: + fw = 0.0; + for (i=jz; i>=0; i--) + fw += fq[i]; + // TODO: drop excess precision here once double_t is used + fw = (double)fw; + y[0] = ih==0 ? fw : -fw; + fw = fq[0]-fw; + for (i=1; i<=jz; i++) + fw += fq[i]; + y[1] = ih==0 ? fw : -fw; + break; + case 3: /* painful */ + for (i=jz; i>0; i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (i=jz; i>1; i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (fw=0.0,i=jz; i>=2; i--) + fw += fq[i]; + if (ih==0) { + y[0] = fq[0]; y[1] = fq[1]; y[2] = fw; + } else { + y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw; + } + } + return n&7; +} diff --git a/src/orca-libc/src/math/__rem_pio2f.c b/src/orca-libc/src/math/__rem_pio2f.c new file mode 100644 index 00000000..034ed810 --- /dev/null +++ b/src/orca-libc/src/math/__rem_pio2f.c @@ -0,0 +1,90 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* __rem_pio2f(x,y) + * + * return the remainder of x rem pi/2 in *y + * use double precision for everything except passing x + * use __rem_pio2_large() for large x + */ + +#include "libm.h" + +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif + +/* + * invpio2: 53 bits of 2/pi + * pio2_1: first 25 bits of pi/2 + * pio2_1t: pi/2 - pio2_1 + */ +static const double +toint = 1.5/EPS, +#ifdef __wasilibc_unmodified_upstream // Wasm doesn't have alternate rounding modes +pio4 = 0x1.921fb6p-1, +#endif +invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ +pio2_1 = 1.57079631090164184570e+00, /* 0x3FF921FB, 0x50000000 */ +pio2_1t = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ + +int __rem_pio2f(float x, double *y) +{ + union {float f; uint32_t i;} u = {x}; + double tx[1],ty[1]; + double_t fn; + uint32_t ix; + int n, sign, e0; + + ix = u.i & 0x7fffffff; + /* 25+53 bit pi is good enough for medium size */ + if (ix < 0x4dc90fdb) { /* |x| ~< 2^28*(pi/2), medium size */ + /* Use a specialized rint() to get fn. */ + fn = (double_t)x*invpio2 + toint - toint; + n = (int32_t)fn; + *y = x - fn*pio2_1 - fn*pio2_1t; +#ifdef __wasilibc_unmodified_upstream // Wasm doesn't have alternate rounding modes + /* Matters with directed rounding. */ + if (predict_false(*y < -pio4)) { + n--; + fn--; + *y = x - fn*pio2_1 - fn*pio2_1t; + } else if (predict_false(*y > pio4)) { + n++; + fn++; + *y = x - fn*pio2_1 - fn*pio2_1t; + } +#endif + return n; + } + if(ix>=0x7f800000) { /* x is inf or NaN */ + *y = x-x; + return 0; + } + /* scale x into [2^23, 2^24-1] */ + sign = u.i>>31; + e0 = (ix>>23) - (0x7f+23); /* e0 = ilogb(|x|)-23, positive */ + u.i = ix - (e0<<23); + tx[0] = u.f; + n = __rem_pio2_large(tx,ty,e0,1,0); + if (sign) { + *y = -ty[0]; + return -n; + } + *y = ty[0]; + return n; +} diff --git a/src/orca-libc/src/math/__rem_pio2l.c b/src/orca-libc/src/math/__rem_pio2l.c new file mode 100644 index 00000000..e73a86bf --- /dev/null +++ b/src/orca-libc/src/math/__rem_pio2l.c @@ -0,0 +1,159 @@ +/* origin: FreeBSD /usr/src/lib/msun/ld80/e_rem_pio2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * Optimized by Bruce D. Evans. + */ +#include "libm.h" +#if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +/* ld80 and ld128 version of __rem_pio2(x,y) + * + * return the remainder of x rem pi/2 in y[0]+y[1] + * use __rem_pio2_large() for large x + */ + +static const long double toint = 1.5/LDBL_EPSILON; + +#if LDBL_MANT_DIG == 64 +/* u ~< 0x1p25*pi/2 */ +#define SMALL(u) (((u.i.se & 0x7fffU)<<16 | u.i.m>>48) < ((0x3fff + 25)<<16 | 0x921f>>1 | 0x8000)) +#define QUOBITS(x) ((uint32_t)(int32_t)x & 0x7fffffff) +#define ROUND1 22 +#define ROUND2 61 +#define NX 3 +#define NY 2 +/* + * invpio2: 64 bits of 2/pi + * pio2_1: first 39 bits of pi/2 + * pio2_1t: pi/2 - pio2_1 + * pio2_2: second 39 bits of pi/2 + * pio2_2t: pi/2 - (pio2_1+pio2_2) + * pio2_3: third 39 bits of pi/2 + * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3) + */ +static const double +pio2_1 = 1.57079632679597125389e+00, /* 0x3FF921FB, 0x54444000 */ +pio2_2 = -1.07463465549783099519e-12, /* -0x12e7b967674000.0p-92 */ +pio2_3 = 6.36831716351370313614e-25; /* 0x18a2e037074000.0p-133 */ +static const long double +pio4 = 0x1.921fb54442d1846ap-1L, +invpio2 = 6.36619772367581343076e-01L, /* 0xa2f9836e4e44152a.0p-64 */ +pio2_1t = -1.07463465549719416346e-12L, /* -0x973dcb3b399d747f.0p-103 */ +pio2_2t = 6.36831716351095013979e-25L, /* 0xc51701b839a25205.0p-144 */ +pio2_3t = -2.75299651904407171810e-37L; /* -0xbb5bf6c7ddd660ce.0p-185 */ +#elif LDBL_MANT_DIG == 113 +/* u ~< 0x1p45*pi/2 */ +#define SMALL(u) (((u.i.se & 0x7fffU)<<16 | u.i.top) < ((0x3fff + 45)<<16 | 0x921f)) +#define QUOBITS(x) ((uint32_t)(int64_t)x & 0x7fffffff) +#define ROUND1 51 +#define ROUND2 119 +#define NX 5 +#define NY 3 +static const long double +#ifdef __wasilibc_unmodified_upstream // Wasm doesn't have alternate rounding modes +pio4 = 0x1.921fb54442d18469898cc51701b8p-1L, +#endif +invpio2 = 6.3661977236758134307553505349005747e-01L, /* 0x145f306dc9c882a53f84eafa3ea6a.0p-113 */ +pio2_1 = 1.5707963267948966192292994253909555e+00L, /* 0x1921fb54442d18469800000000000.0p-112 */ +pio2_1t = 2.0222662487959507323996846200947577e-21L, /* 0x13198a2e03707344a4093822299f3.0p-181 */ +pio2_2 = 2.0222662487959507323994779168837751e-21L, /* 0x13198a2e03707344a400000000000.0p-181 */ +pio2_2t = 2.0670321098263988236496903051604844e-43L, /* 0x127044533e63a0105df531d89cd91.0p-254 */ +pio2_3 = 2.0670321098263988236499468110329591e-43L, /* 0x127044533e63a0105e00000000000.0p-254 */ +pio2_3t = -2.5650587247459238361625433492959285e-65L; /* -0x159c4ec64ddaeb5f78671cbfb2210.0p-327 */ +#endif + +int __rem_pio2l(long double x, long double *y) +{ + union ldshape u,uz; + long double z,w,t,r,fn; + double tx[NX],ty[NY]; + int ex,ey,n,i; + + u.f = x; + ex = u.i.se & 0x7fff; + if (SMALL(u)) { + /* rint(x/(pi/2)) */ + fn = x*invpio2 + toint - toint; + n = QUOBITS(fn); + r = x-fn*pio2_1; + w = fn*pio2_1t; /* 1st round good to 102/180 bits (ld80/ld128) */ +#ifdef __wasilibc_unmodified_upstream // Wasm doesn't have alternate rounding modes + /* Matters with directed rounding. */ + if (predict_false(r - w < -pio4)) { + n--; + fn--; + r = x - fn*pio2_1; + w = fn*pio2_1t; + } else if (predict_false(r - w > pio4)) { + n++; + fn++; + r = x - fn*pio2_1; + w = fn*pio2_1t; + } +#endif + y[0] = r-w; + u.f = y[0]; + ey = u.i.se & 0x7fff; + if (ex - ey > ROUND1) { /* 2nd iteration needed, good to 141/248 (ld80/ld128) */ + t = r; + w = fn*pio2_2; + r = t-w; + w = fn*pio2_2t-((t-r)-w); + y[0] = r-w; + u.f = y[0]; + ey = u.i.se & 0x7fff; + if (ex - ey > ROUND2) { /* 3rd iteration, good to 180/316 bits */ + t = r; /* will cover all possible cases (not verified for ld128) */ + w = fn*pio2_3; + r = t-w; + w = fn*pio2_3t-((t-r)-w); + y[0] = r-w; + } + } + y[1] = (r - y[0]) - w; + return n; + } + /* + * all other (large) arguments + */ + if (ex == 0x7fff) { /* x is inf or NaN */ + y[0] = y[1] = x - x; + return 0; + } + /* set z = scalbn(|x|,-ilogb(x)+23) */ + uz.f = x; + uz.i.se = 0x3fff + 23; + z = uz.f; + for (i=0; i < NX - 1; i++) { + tx[i] = (double)(int32_t)z; + z = (z-tx[i])*0x1p24; + } + tx[i] = z; + while (tx[i] == 0) + i--; + n = __rem_pio2_large(tx, ty, ex-0x3fff-23, i+1, NY); + w = ty[1]; + if (NY == 3) + w += ty[2]; + r = ty[0] + w; + /* TODO: for ld128 this does not follow the recommendation of the + comments of __rem_pio2_large which seem wrong if |ty[0]| > |ty[1]+ty[2]| */ + w -= r - ty[0]; + if (u.i.se >> 15) { + y[0] = -r; + y[1] = -w; + return -n; + } + y[0] = r; + y[1] = w; + return n; +} +#endif diff --git a/src/orca-libc/src/math/__signbit.c b/src/orca-libc/src/math/__signbit.c new file mode 100644 index 00000000..e700b6b7 --- /dev/null +++ b/src/orca-libc/src/math/__signbit.c @@ -0,0 +1,13 @@ +#include "libm.h" + +// FIXME: macro in math.h +int __signbit(double x) +{ + union { + double d; + uint64_t i; + } y = { x }; + return y.i>>63; +} + + diff --git a/src/orca-libc/src/math/__signbitf.c b/src/orca-libc/src/math/__signbitf.c new file mode 100644 index 00000000..40ad3cfd --- /dev/null +++ b/src/orca-libc/src/math/__signbitf.c @@ -0,0 +1,11 @@ +#include "libm.h" + +// FIXME: macro in math.h +int __signbitf(float x) +{ + union { + float f; + uint32_t i; + } y = { x }; + return y.i>>31; +} diff --git a/src/orca-libc/src/math/__signbitl.c b/src/orca-libc/src/math/__signbitl.c new file mode 100644 index 00000000..63b3dc5a --- /dev/null +++ b/src/orca-libc/src/math/__signbitl.c @@ -0,0 +1,14 @@ +#include "libm.h" + +#if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +int __signbitl(long double x) +{ + union ldshape u = {x}; + return u.i.se >> 15; +} +#elif LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +int __signbitl(long double x) +{ + return __signbit(x); +} +#endif diff --git a/src/libc-shim/src/__sin.c b/src/orca-libc/src/math/__sin.c similarity index 73% rename from src/libc-shim/src/__sin.c rename to src/orca-libc/src/math/__sin.c index c0b24e81..40309496 100644 --- a/src/libc-shim/src/__sin.c +++ b/src/orca-libc/src/math/__sin.c @@ -42,23 +42,23 @@ #include "libm.h" static const double - S1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */ - S2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */ - S3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */ - S4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */ - S5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */ - S6 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ +S1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */ +S2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */ +S3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */ +S4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */ +S5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */ +S6 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ double __sin(double x, double y, int iy) { - double_t z, r, v, w; + double_t z,r,v,w; - z = x * x; - w = z * z; - r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6); - v = z * x; - if(iy == 0) - return x + v * (S1 + z * r); - else - return x - ((z * (0.5 * y - v * r) - y) - v * S1); + z = x*x; + w = z*z; + r = S2 + z*(S3 + z*S4) + z*w*(S5 + z*S6); + v = z*x; + if (iy == 0) + return x + v*(S1 + z*r); + else + return x - ((z*(0.5*y - v*r) - y) - v*S1); } diff --git a/src/libc-shim/src/__sindf.c b/src/orca-libc/src/math/__sindf.c similarity index 59% rename from src/libc-shim/src/__sindf.c rename to src/orca-libc/src/math/__sindf.c index 95fb7e6c..8fec2a3f 100644 --- a/src/libc-shim/src/__sindf.c +++ b/src/orca-libc/src/math/__sindf.c @@ -18,19 +18,19 @@ /* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ static const double - S1 = -0x15555554cbac77.0p-55, /* -0.166666666416265235595 */ - S2 = 0x111110896efbb2.0p-59, /* 0.0083333293858894631756 */ - S3 = -0x1a00f9e2cae774.0p-65, /* -0.000198393348360966317347 */ - S4 = 0x16cd878c3b46a7.0p-71; /* 0.0000027183114939898219064 */ +S1 = -0x15555554cbac77.0p-55, /* -0.166666666416265235595 */ +S2 = 0x111110896efbb2.0p-59, /* 0.0083333293858894631756 */ +S3 = -0x1a00f9e2cae774.0p-65, /* -0.000198393348360966317347 */ +S4 = 0x16cd878c3b46a7.0p-71; /* 0.0000027183114939898219064 */ float __sindf(double x) { - double_t r, s, w, z; + double_t r, s, w, z; - /* Try to optimize for parallel evaluation as in __tandf.c. */ - z = x * x; - w = z * z; - r = S3 + z * S4; - s = z * x; - return (x + s * (S1 + z * S2)) + s * w * r; + /* Try to optimize for parallel evaluation as in __tandf.c. */ + z = x*x; + w = z*z; + r = S3 + z*S4; + s = z*x; + return (x + s*(S1 + z*S2)) + s*w*r; } diff --git a/src/orca-libc/src/math/__sinl.c b/src/orca-libc/src/math/__sinl.c new file mode 100644 index 00000000..2525bbe8 --- /dev/null +++ b/src/orca-libc/src/math/__sinl.c @@ -0,0 +1,78 @@ +/* origin: FreeBSD /usr/src/lib/msun/ld80/k_sinl.c */ +/* origin: FreeBSD /usr/src/lib/msun/ld128/k_sinl.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +#if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#if LDBL_MANT_DIG == 64 +/* + * ld80 version of __sin.c. See __sin.c for most comments. + */ +/* + * Domain [-0.7854, 0.7854], range ~[-1.89e-22, 1.915e-22] + * |sin(x)/x - s(x)| < 2**-72.1 + * + * See __cosl.c for more details about the polynomial. + */ +static const long double +S1 = -0.166666666666666666671L; /* -0xaaaaaaaaaaaaaaab.0p-66 */ +static const double +S2 = 0.0083333333333333332, /* 0x11111111111111.0p-59 */ +S3 = -0.00019841269841269427, /* -0x1a01a01a019f81.0p-65 */ +S4 = 0.0000027557319223597490, /* 0x171de3a55560f7.0p-71 */ +S5 = -0.000000025052108218074604, /* -0x1ae64564f16cad.0p-78 */ +S6 = 1.6059006598854211e-10, /* 0x161242b90243b5.0p-85 */ +S7 = -7.6429779983024564e-13, /* -0x1ae42ebd1b2e00.0p-93 */ +S8 = 2.6174587166648325e-15; /* 0x179372ea0b3f64.0p-101 */ +#define POLY(z) (S2+z*(S3+z*(S4+z*(S5+z*(S6+z*(S7+z*S8)))))) +#elif LDBL_MANT_DIG == 113 +/* + * ld128 version of __sin.c. See __sin.c for most comments. + */ +/* + * Domain [-0.7854, 0.7854], range ~[-1.53e-37, 1.659e-37] + * |sin(x)/x - s(x)| < 2**-122.1 + * + * See __cosl.c for more details about the polynomial. + */ +static const long double +S1 = -0.16666666666666666666666666666666666606732416116558L, +S2 = 0.0083333333333333333333333333333331135404851288270047L, +S3 = -0.00019841269841269841269841269839935785325638310428717L, +S4 = 0.27557319223985890652557316053039946268333231205686e-5L, +S5 = -0.25052108385441718775048214826384312253862930064745e-7L, +S6 = 0.16059043836821614596571832194524392581082444805729e-9L, +S7 = -0.76471637318198151807063387954939213287488216303768e-12L, +S8 = 0.28114572543451292625024967174638477283187397621303e-14L; +static const double +S9 = -0.82206352458348947812512122163446202498005154296863e-17, +S10 = 0.19572940011906109418080609928334380560135358385256e-19, +S11 = -0.38680813379701966970673724299207480965452616911420e-22, +S12 = 0.64038150078671872796678569586315881020659912139412e-25; +#define POLY(z) (S2+z*(S3+z*(S4+z*(S5+z*(S6+z*(S7+z*(S8+ \ + z*(S9+z*(S10+z*(S11+z*S12)))))))))) +#endif + +long double __sinl(long double x, long double y, int iy) +{ + long double z,r,v; + + z = x*x; + v = z*x; + r = POLY(z); + if (iy == 0) + return x+v*(S1+z*r); + return x-((z*(0.5*y-v*r)-y)-v*S1); +} +#endif diff --git a/src/libc-shim/src/__tan.c b/src/orca-libc/src/math/__tan.c similarity index 100% rename from src/libc-shim/src/__tan.c rename to src/orca-libc/src/math/__tan.c diff --git a/src/libc-shim/src/__tandf.c b/src/orca-libc/src/math/__tandf.c similarity index 100% rename from src/libc-shim/src/__tandf.c rename to src/orca-libc/src/math/__tandf.c diff --git a/src/orca-libc/src/math/__tanl.c b/src/orca-libc/src/math/__tanl.c new file mode 100644 index 00000000..54abc3da --- /dev/null +++ b/src/orca-libc/src/math/__tanl.c @@ -0,0 +1,143 @@ +/* origin: FreeBSD /usr/src/lib/msun/ld80/k_tanl.c */ +/* origin: FreeBSD /usr/src/lib/msun/ld128/k_tanl.c */ +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +#if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#if LDBL_MANT_DIG == 64 +/* + * ld80 version of __tan.c. See __tan.c for most comments. + */ +/* + * Domain [-0.67434, 0.67434], range ~[-2.25e-22, 1.921e-22] + * |tan(x)/x - t(x)| < 2**-71.9 + * + * See __cosl.c for more details about the polynomial. + */ +static const long double +T3 = 0.333333333333333333180L, /* 0xaaaaaaaaaaaaaaa5.0p-65 */ +T5 = 0.133333333333333372290L, /* 0x88888888888893c3.0p-66 */ +T7 = 0.0539682539682504975744L, /* 0xdd0dd0dd0dc13ba2.0p-68 */ +pio4 = 0.785398163397448309628L, /* 0xc90fdaa22168c235.0p-64 */ +pio4lo = -1.25413940316708300586e-20L; /* -0xece675d1fc8f8cbb.0p-130 */ +static const double +T9 = 0.021869488536312216, /* 0x1664f4882cc1c2.0p-58 */ +T11 = 0.0088632355256619590, /* 0x1226e355c17612.0p-59 */ +T13 = 0.0035921281113786528, /* 0x1d6d3d185d7ff8.0p-61 */ +T15 = 0.0014558334756312418, /* 0x17da354aa3f96b.0p-62 */ +T17 = 0.00059003538700862256, /* 0x13559358685b83.0p-63 */ +T19 = 0.00023907843576635544, /* 0x1f56242026b5be.0p-65 */ +T21 = 0.000097154625656538905, /* 0x1977efc26806f4.0p-66 */ +T23 = 0.000038440165747303162, /* 0x14275a09b3ceac.0p-67 */ +T25 = 0.000018082171885432524, /* 0x12f5e563e5487e.0p-68 */ +T27 = 0.0000024196006108814377, /* 0x144c0d80cc6896.0p-71 */ +T29 = 0.0000078293456938132840, /* 0x106b59141a6cb3.0p-69 */ +T31 = -0.0000032609076735050182, /* -0x1b5abef3ba4b59.0p-71 */ +T33 = 0.0000023261313142559411; /* 0x13835436c0c87f.0p-71 */ +#define RPOLY(w) (T5 + w * (T9 + w * (T13 + w * (T17 + w * (T21 + \ + w * (T25 + w * (T29 + w * T33))))))) +#define VPOLY(w) (T7 + w * (T11 + w * (T15 + w * (T19 + w * (T23 + \ + w * (T27 + w * T31)))))) +#elif LDBL_MANT_DIG == 113 +/* + * ld128 version of __tan.c. See __tan.c for most comments. + */ +/* + * Domain [-0.67434, 0.67434], range ~[-3.37e-36, 1.982e-37] + * |tan(x)/x - t(x)| < 2**-117.8 (XXX should be ~1e-37) + * + * See __cosl.c for more details about the polynomial. + */ +static const long double +T3 = 0x1.5555555555555555555555555553p-2L, +T5 = 0x1.1111111111111111111111111eb5p-3L, +T7 = 0x1.ba1ba1ba1ba1ba1ba1ba1b694cd6p-5L, +T9 = 0x1.664f4882c10f9f32d6bbe09d8bcdp-6L, +T11 = 0x1.226e355e6c23c8f5b4f5762322eep-7L, +T13 = 0x1.d6d3d0e157ddfb5fed8e84e27b37p-9L, +T15 = 0x1.7da36452b75e2b5fce9ee7c2c92ep-10L, +T17 = 0x1.355824803674477dfcf726649efep-11L, +T19 = 0x1.f57d7734d1656e0aceb716f614c2p-13L, +T21 = 0x1.967e18afcb180ed942dfdc518d6cp-14L, +T23 = 0x1.497d8eea21e95bc7e2aa79b9f2cdp-15L, +T25 = 0x1.0b132d39f055c81be49eff7afd50p-16L, +T27 = 0x1.b0f72d33eff7bfa2fbc1059d90b6p-18L, +T29 = 0x1.5ef2daf21d1113df38d0fbc00267p-19L, +T31 = 0x1.1c77d6eac0234988cdaa04c96626p-20L, +T33 = 0x1.cd2a5a292b180e0bdd701057dfe3p-22L, +T35 = 0x1.75c7357d0298c01a31d0a6f7d518p-23L, +T37 = 0x1.2f3190f4718a9a520f98f50081fcp-24L, +pio4 = 0x1.921fb54442d18469898cc51701b8p-1L, +pio4lo = 0x1.cd129024e088a67cc74020bbea60p-116L; +static const double +T39 = 0.000000028443389121318352, /* 0x1e8a7592977938.0p-78 */ +T41 = 0.000000011981013102001973, /* 0x19baa1b1223219.0p-79 */ +T43 = 0.0000000038303578044958070, /* 0x107385dfb24529.0p-80 */ +T45 = 0.0000000034664378216909893, /* 0x1dc6c702a05262.0p-81 */ +T47 = -0.0000000015090641701997785, /* -0x19ecef3569ebb6.0p-82 */ +T49 = 0.0000000029449552300483952, /* 0x194c0668da786a.0p-81 */ +T51 = -0.0000000022006995706097711, /* -0x12e763b8845268.0p-81 */ +T53 = 0.0000000015468200913196612, /* 0x1a92fc98c29554.0p-82 */ +T55 = -0.00000000061311613386849674, /* -0x151106cbc779a9.0p-83 */ +T57 = 1.4912469681508012e-10; /* 0x147edbdba6f43a.0p-85 */ +#define RPOLY(w) (T5 + w * (T9 + w * (T13 + w * (T17 + w * (T21 + \ + w * (T25 + w * (T29 + w * (T33 + w * (T37 + w * (T41 + \ + w * (T45 + w * (T49 + w * (T53 + w * T57))))))))))))) +#define VPOLY(w) (T7 + w * (T11 + w * (T15 + w * (T19 + w * (T23 + \ + w * (T27 + w * (T31 + w * (T35 + w * (T39 + w * (T43 + \ + w * (T47 + w * (T51 + w * T55)))))))))))) +#endif + +long double __tanl(long double x, long double y, int odd) { + long double z, r, v, w, s, a, t; + int big, sign; + + big = fabsl(x) >= 0.67434; + if (big) { + sign = 0; + if (x < 0) { + sign = 1; + x = -x; + y = -y; + } + x = (pio4 - x) + (pio4lo - y); + y = 0.0; + } + z = x * x; + w = z * z; + r = RPOLY(w); + v = z * VPOLY(w); + s = z * x; + r = y + z * (s * (r + v) + y) + T3 * s; + w = x + r; + if (big) { + s = 1 - 2*odd; + v = s - 2.0 * (x + (r - w * w / (w + s))); + return sign ? -v : v; + } + if (!odd) + return w; + /* + * if allow error up to 2 ulp, simply return + * -1.0 / (x+r) here + */ + /* compute -1.0 / (x+r) accurately */ + z = w; + z = z + 0x1p32 - 0x1p32; + v = r - (z - x); /* z+v = r+x */ + t = a = -1.0 / w; /* a = -1.0/w */ + t = t + 0x1p32 - 0x1p32; + s = 1.0 + t * z; + return t + a * (s + t * v); +} +#endif diff --git a/src/orca-libc/src/math/acos.c b/src/orca-libc/src/math/acos.c new file mode 100644 index 00000000..ea9c87bf --- /dev/null +++ b/src/orca-libc/src/math/acos.c @@ -0,0 +1,101 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_acos.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* acos(x) + * Method : + * acos(x) = pi/2 - asin(x) + * acos(-x) = pi/2 + asin(x) + * For |x|<=0.5 + * acos(x) = pi/2 - (x + x*x^2*R(x^2)) (see asin.c) + * For x>0.5 + * acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2))) + * = 2asin(sqrt((1-x)/2)) + * = 2s + 2s*z*R(z) ...z=(1-x)/2, s=sqrt(z) + * = 2f + (2c + 2s*z*R(z)) + * where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term + * for f so that f+c ~ sqrt(z). + * For x<-0.5 + * acos(x) = pi - 2asin(sqrt((1-|x|)/2)) + * = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z) + * + * Special cases: + * if x is NaN, return x itself; + * if |x|>1, return NaN with invalid signal. + * + * Function needed: sqrt + */ + +#include "libm.h" + +static const double +pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */ +pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */ +pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */ +pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */ +pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */ +pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */ +pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */ +pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */ +qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */ +qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */ +qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */ +qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +static double R(double z) +{ + double_t p, q; + p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5))))); + q = 1.0+z*(qS1+z*(qS2+z*(qS3+z*qS4))); + return p/q; +} + +double acos(double x) +{ + double z,w,s,c,df; + uint32_t hx,ix; + + GET_HIGH_WORD(hx, x); + ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if (ix >= 0x3ff00000) { + uint32_t lx; + + GET_LOW_WORD(lx,x); + if ((ix-0x3ff00000 | lx) == 0) { + /* acos(1)=0, acos(-1)=pi */ + if (hx >> 31) + return 2*pio2_hi + 0x1p-120f; + return 0; + } + return 0/(x-x); + } + /* |x| < 0.5 */ + if (ix < 0x3fe00000) { + if (ix <= 0x3c600000) /* |x| < 2**-57 */ + return pio2_hi + 0x1p-120f; + return pio2_hi - (x - (pio2_lo-x*R(x*x))); + } + /* x < -0.5 */ + if (hx >> 31) { + z = (1.0+x)*0.5; + s = sqrt(z); + w = R(z)*s-pio2_lo; + return 2*(pio2_hi - (s+w)); + } + /* x > 0.5 */ + z = (1.0-x)*0.5; + s = sqrt(z); + df = s; + SET_LOW_WORD(df,0); + c = (z-df*df)/(s+df); + w = R(z)*s+c; + return 2*(df+w); +} diff --git a/src/libc-shim/src/acosf.c b/src/orca-libc/src/math/acosf.c similarity index 100% rename from src/libc-shim/src/acosf.c rename to src/orca-libc/src/math/acosf.c diff --git a/src/orca-libc/src/math/acosh.c b/src/orca-libc/src/math/acosh.c new file mode 100644 index 00000000..badbf908 --- /dev/null +++ b/src/orca-libc/src/math/acosh.c @@ -0,0 +1,24 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD==2 +#undef sqrt +#define sqrt sqrtl +#endif + +/* acosh(x) = log(x + sqrt(x*x-1)) */ +double acosh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + unsigned e = u.i >> 52 & 0x7ff; + + /* x < 1 domain error is handled in the called functions */ + + if (e < 0x3ff + 1) + /* |x| < 2, up to 2ulp error in [1,1.125] */ + return log1p(x-1 + sqrt((x-1)*(x-1)+2*(x-1))); + if (e < 0x3ff + 26) + /* |x| < 0x1p26 */ + return log(2*x - 1/(x+sqrt(x*x-1))); + /* |x| >= 0x1p26 or nan */ + return log(x) + 0.693147180559945309417232121458176568; +} diff --git a/src/orca-libc/src/math/acoshf.c b/src/orca-libc/src/math/acoshf.c new file mode 100644 index 00000000..b773d48e --- /dev/null +++ b/src/orca-libc/src/math/acoshf.c @@ -0,0 +1,26 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD==2 +#undef sqrtf +#define sqrtf sqrtl +#elif FLT_EVAL_METHOD==1 +#undef sqrtf +#define sqrtf sqrt +#endif + +/* acosh(x) = log(x + sqrt(x*x-1)) */ +float acoshf(float x) +{ + union {float f; uint32_t i;} u = {x}; + uint32_t a = u.i & 0x7fffffff; + + if (a < 0x3f800000+(1<<23)) + /* |x| < 2, invalid if x < 1 */ + /* up to 2ulp error in [1,1.125] */ + return log1pf(x-1 + sqrtf((x-1)*(x-1)+2*(x-1))); + if (u.i < 0x3f800000+(12<<23)) + /* 2 <= x < 0x1p12 */ + return logf(2*x - 1/(x+sqrtf(x*x-1))); + /* x >= 0x1p12 or x <= -2 or nan */ + return logf(x) + 0.693147180559945309417232121458176568f; +} diff --git a/src/orca-libc/src/math/acoshl.c b/src/orca-libc/src/math/acoshl.c new file mode 100644 index 00000000..8d4b43f6 --- /dev/null +++ b/src/orca-libc/src/math/acoshl.c @@ -0,0 +1,29 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double acoshl(long double x) +{ + return acosh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* acosh(x) = log(x + sqrt(x*x-1)) */ +long double acoshl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + + if (e < 0x3fff + 1) + /* |x| < 2, invalid if x < 1 or nan */ + return log1pl(x-1 + sqrtl((x-1)*(x-1)+2*(x-1))); + if (e < 0x3fff + 32) + /* |x| < 0x1p32 */ + return logl(2*x - 1/(x+sqrtl(x*x-1))); + return logl(x) + 0.693147180559945309417232121458176568L; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double acoshl(long double x) +{ + return acosh(x); +} +#endif diff --git a/src/orca-libc/src/math/acosl.c b/src/orca-libc/src/math/acosl.c new file mode 100644 index 00000000..c03bdf02 --- /dev/null +++ b/src/orca-libc/src/math/acosl.c @@ -0,0 +1,67 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_acosl.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in acos.c. + * Converted to long double by David Schultz . + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double acosl(long double x) +{ + return acos(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#include "__invtrigl.h" +#if LDBL_MANT_DIG == 64 +#define CLEARBOTTOM(u) (u.i.m &= -1ULL << 32) +#elif LDBL_MANT_DIG == 113 +#define CLEARBOTTOM(u) (u.i.lo = 0) +#endif + +long double acosl(long double x) +{ + union ldshape u = {x}; + long double z, s, c, f; + uint16_t e = u.i.se & 0x7fff; + + /* |x| >= 1 or nan */ + if (e >= 0x3fff) { + if (x == 1) + return 0; + if (x == -1) + return 2*pio2_hi + 0x1p-120f; + return 0/(x-x); + } + /* |x| < 0.5 */ + if (e < 0x3fff - 1) { + if (e < 0x3fff - LDBL_MANT_DIG - 1) + return pio2_hi + 0x1p-120f; + return pio2_hi - (__invtrigl_R(x*x)*x - pio2_lo + x); + } + /* x < -0.5 */ + if (u.i.se >> 15) { + z = (1 + x)*0.5; + s = sqrtl(z); + return 2*(pio2_hi - (__invtrigl_R(z)*s - pio2_lo + s)); + } + /* x > 0.5 */ + z = (1 - x)*0.5; + s = sqrtl(z); + u.f = s; + CLEARBOTTOM(u); + f = u.f; + c = (z - f*f)/(s + f); + return 2*(__invtrigl_R(z)*s + c + f); +} +#endif diff --git a/src/libc-shim/src/asin.c b/src/orca-libc/src/math/asin.c similarity index 100% rename from src/libc-shim/src/asin.c rename to src/orca-libc/src/math/asin.c diff --git a/src/libc-shim/src/asinf.c b/src/orca-libc/src/math/asinf.c similarity index 100% rename from src/libc-shim/src/asinf.c rename to src/orca-libc/src/math/asinf.c diff --git a/src/orca-libc/src/math/asinh.c b/src/orca-libc/src/math/asinh.c new file mode 100644 index 00000000..0829f228 --- /dev/null +++ b/src/orca-libc/src/math/asinh.c @@ -0,0 +1,28 @@ +#include "libm.h" + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +double asinh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + unsigned e = u.i >> 52 & 0x7ff; + unsigned s = u.i >> 63; + + /* |x| */ + u.i &= (uint64_t)-1/2; + x = u.f; + + if (e >= 0x3ff + 26) { + /* |x| >= 0x1p26 or inf or nan */ + x = log(x) + 0.693147180559945309417232121458176568; + } else if (e >= 0x3ff + 1) { + /* |x| >= 2 */ + x = log(2*x + 1/(sqrt(x*x+1)+x)); + } else if (e >= 0x3ff - 26) { + /* |x| >= 0x1p-26, up to 1.6ulp error in [0.125,0.5] */ + x = log1p(x + x*x/(sqrt(x*x+1)+1)); + } else { + /* |x| < 0x1p-26, raise inexact if x != 0 */ + FORCE_EVAL(x + 0x1p120f); + } + return s ? -x : x; +} diff --git a/src/orca-libc/src/math/asinhf.c b/src/orca-libc/src/math/asinhf.c new file mode 100644 index 00000000..fc9f0911 --- /dev/null +++ b/src/orca-libc/src/math/asinhf.c @@ -0,0 +1,28 @@ +#include "libm.h" + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +float asinhf(float x) +{ + union {float f; uint32_t i;} u = {.f = x}; + uint32_t i = u.i & 0x7fffffff; + unsigned s = u.i >> 31; + + /* |x| */ + u.i = i; + x = u.f; + + if (i >= 0x3f800000 + (12<<23)) { + /* |x| >= 0x1p12 or inf or nan */ + x = logf(x) + 0.693147180559945309417232121458176568f; + } else if (i >= 0x3f800000 + (1<<23)) { + /* |x| >= 2 */ + x = logf(2*x + 1/(sqrtf(x*x+1)+x)); + } else if (i >= 0x3f800000 - (12<<23)) { + /* |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5] */ + x = log1pf(x + x*x/(sqrtf(x*x+1)+1)); + } else { + /* |x| < 0x1p-12, raise inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + } + return s ? -x : x; +} diff --git a/src/orca-libc/src/math/asinhl.c b/src/orca-libc/src/math/asinhl.c new file mode 100644 index 00000000..8635f52e --- /dev/null +++ b/src/orca-libc/src/math/asinhl.c @@ -0,0 +1,41 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double asinhl(long double x) +{ + return asinh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +long double asinhl(long double x) +{ + union ldshape u = {x}; + unsigned e = u.i.se & 0x7fff; + unsigned s = u.i.se >> 15; + + /* |x| */ + u.i.se = e; + x = u.f; + + if (e >= 0x3fff + 32) { + /* |x| >= 0x1p32 or inf or nan */ + x = logl(x) + 0.693147180559945309417232121458176568L; + } else if (e >= 0x3fff + 1) { + /* |x| >= 2 */ + x = logl(2*x + 1/(sqrtl(x*x+1)+x)); + } else if (e >= 0x3fff - 32) { + /* |x| >= 0x1p-32 */ + x = log1pl(x + x*x/(sqrtl(x*x+1)+1)); + } else { + /* |x| < 0x1p-32, raise inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + } + return s ? -x : x; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double asinhl(long double x) +{ + return asinh(x); +} +#endif diff --git a/src/orca-libc/src/math/asinl.c b/src/orca-libc/src/math/asinl.c new file mode 100644 index 00000000..347c5356 --- /dev/null +++ b/src/orca-libc/src/math/asinl.c @@ -0,0 +1,71 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_asinl.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in asin.c. + * Converted to long double by David Schultz . + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double asinl(long double x) +{ + return asin(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#include "__invtrigl.h" +#if LDBL_MANT_DIG == 64 +#define CLOSETO1(u) (u.i.m>>56 >= 0xf7) +#define CLEARBOTTOM(u) (u.i.m &= -1ULL << 32) +#elif LDBL_MANT_DIG == 113 +#define CLOSETO1(u) (u.i.top >= 0xee00) +#define CLEARBOTTOM(u) (u.i.lo = 0) +#endif + +long double asinl(long double x) +{ + union ldshape u = {x}; + long double z, r, s; + uint16_t e = u.i.se & 0x7fff; + int sign = u.i.se >> 15; + + if (e >= 0x3fff) { /* |x| >= 1 or nan */ + /* asin(+-1)=+-pi/2 with inexact */ + if (x == 1 || x == -1) + return x*pio2_hi + 0x1p-120f; + return 0/(x-x); + } + if (e < 0x3fff - 1) { /* |x| < 0.5 */ + if (e < 0x3fff - (LDBL_MANT_DIG+1)/2) { + /* return x with inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + return x; + } + return x + x*__invtrigl_R(x*x); + } + /* 1 > |x| >= 0.5 */ + z = (1.0 - fabsl(x))*0.5; + s = sqrtl(z); + r = __invtrigl_R(z); + if (CLOSETO1(u)) { + x = pio2_hi - (2*(s+s*r)-pio2_lo); + } else { + long double f, c; + u.f = s; + CLEARBOTTOM(u); + f = u.f; + c = (z - f*f)/(s + f); + x = 0.5*pio2_hi-(2*s*r - (pio2_lo-2*c) - (0.5*pio2_hi-2*f)); + } + return sign ? -x : x; +} +#endif diff --git a/src/libc-shim/src/atan.c b/src/orca-libc/src/math/atan.c similarity index 100% rename from src/libc-shim/src/atan.c rename to src/orca-libc/src/math/atan.c diff --git a/src/libc-shim/src/atan2.c b/src/orca-libc/src/math/atan2.c similarity index 100% rename from src/libc-shim/src/atan2.c rename to src/orca-libc/src/math/atan2.c diff --git a/src/libc-shim/src/atan2f.c b/src/orca-libc/src/math/atan2f.c similarity index 100% rename from src/libc-shim/src/atan2f.c rename to src/orca-libc/src/math/atan2f.c diff --git a/src/orca-libc/src/math/atan2l.c b/src/orca-libc/src/math/atan2l.c new file mode 100644 index 00000000..f0937a97 --- /dev/null +++ b/src/orca-libc/src/math/atan2l.c @@ -0,0 +1,85 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2l.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* + * See comments in atan2.c. + * Converted to long double by David Schultz . + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double atan2l(long double y, long double x) +{ + return atan2(y, x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#include "__invtrigl.h" + +long double atan2l(long double y, long double x) +{ + union ldshape ux, uy; + long double z; + int m, ex, ey; + + if (isnan(x) || isnan(y)) + return x+y; + if (x == 1) + return atanl(y); + ux.f = x; + uy.f = y; + ex = ux.i.se & 0x7fff; + ey = uy.i.se & 0x7fff; + m = 2*(ux.i.se>>15) | uy.i.se>>15; + if (y == 0) { + switch(m) { + case 0: + case 1: return y; /* atan(+-0,+anything)=+-0 */ + case 2: return 2*pio2_hi; /* atan(+0,-anything) = pi */ + case 3: return -2*pio2_hi; /* atan(-0,-anything) =-pi */ + } + } + if (x == 0) + return m&1 ? -pio2_hi : pio2_hi; + if (ex == 0x7fff) { + if (ey == 0x7fff) { + switch(m) { + case 0: return pio2_hi/2; /* atan(+INF,+INF) */ + case 1: return -pio2_hi/2; /* atan(-INF,+INF) */ + case 2: return 1.5*pio2_hi; /* atan(+INF,-INF) */ + case 3: return -1.5*pio2_hi; /* atan(-INF,-INF) */ + } + } else { + switch(m) { + case 0: return 0.0; /* atan(+...,+INF) */ + case 1: return -0.0; /* atan(-...,+INF) */ + case 2: return 2*pio2_hi; /* atan(+...,-INF) */ + case 3: return -2*pio2_hi; /* atan(-...,-INF) */ + } + } + } + if (ex+120 < ey || ey == 0x7fff) + return m&1 ? -pio2_hi : pio2_hi; + /* z = atan(|y/x|) without spurious underflow */ + if ((m&2) && ey+120 < ex) /* |y/x| < 0x1p-120, x<0 */ + z = 0.0; + else + z = atanl(fabsl(y/x)); + switch (m) { + case 0: return z; /* atan(+,+) */ + case 1: return -z; /* atan(-,+) */ + case 2: return 2*pio2_hi-(z-2*pio2_lo); /* atan(+,-) */ + default: /* case 3 */ + return (z-2*pio2_lo)-2*pio2_hi; /* atan(-,-) */ + } +} +#endif diff --git a/src/libc-shim/src/atanf.c b/src/orca-libc/src/math/atanf.c similarity index 100% rename from src/libc-shim/src/atanf.c rename to src/orca-libc/src/math/atanf.c diff --git a/src/orca-libc/src/math/atanh.c b/src/orca-libc/src/math/atanh.c new file mode 100644 index 00000000..63a035d7 --- /dev/null +++ b/src/orca-libc/src/math/atanh.c @@ -0,0 +1,29 @@ +#include "libm.h" + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +double atanh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + unsigned e = u.i >> 52 & 0x7ff; + unsigned s = u.i >> 63; + double_t y; + + /* |x| */ + u.i &= (uint64_t)-1/2; + y = u.f; + + if (e < 0x3ff - 1) { + if (e < 0x3ff - 32) { + /* handle underflow */ + if (e == 0) + FORCE_EVAL((float)y); + } else { + /* |x| < 0.5, up to 1.7ulp error */ + y = 0.5*log1p(2*y + 2*y*y/(1-y)); + } + } else { + /* avoid overflow */ + y = 0.5*log1p(2*(y/(1-y))); + } + return s ? -y : y; +} diff --git a/src/orca-libc/src/math/atanhf.c b/src/orca-libc/src/math/atanhf.c new file mode 100644 index 00000000..65f07c0f --- /dev/null +++ b/src/orca-libc/src/math/atanhf.c @@ -0,0 +1,28 @@ +#include "libm.h" + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +float atanhf(float x) +{ + union {float f; uint32_t i;} u = {.f = x}; + unsigned s = u.i >> 31; + float_t y; + + /* |x| */ + u.i &= 0x7fffffff; + y = u.f; + + if (u.i < 0x3f800000 - (1<<23)) { + if (u.i < 0x3f800000 - (32<<23)) { + /* handle underflow */ + if (u.i < (1<<23)) + FORCE_EVAL((float)(y*y)); + } else { + /* |x| < 0.5, up to 1.7ulp error */ + y = 0.5f*log1pf(2*y + 2*y*y/(1-y)); + } + } else { + /* avoid overflow */ + y = 0.5f*log1pf(2*(y/(1-y))); + } + return s ? -y : y; +} diff --git a/src/orca-libc/src/math/atanhl.c b/src/orca-libc/src/math/atanhl.c new file mode 100644 index 00000000..87cd1cdb --- /dev/null +++ b/src/orca-libc/src/math/atanhl.c @@ -0,0 +1,35 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double atanhl(long double x) +{ + return atanh(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +long double atanhl(long double x) +{ + union ldshape u = {x}; + unsigned e = u.i.se & 0x7fff; + unsigned s = u.i.se >> 15; + + /* |x| */ + u.i.se = e; + x = u.f; + + if (e < 0x3ff - 1) { + if (e < 0x3ff - LDBL_MANT_DIG/2) { + /* handle underflow */ + if (e == 0) + FORCE_EVAL((float)x); + } else { + /* |x| < 0.5, up to 1.7ulp error */ + x = 0.5*log1pl(2*x + 2*x*x/(1-x)); + } + } else { + /* avoid overflow */ + x = 0.5*log1pl(2*(x/(1-x))); + } + return s ? -x : x; +} +#endif diff --git a/src/orca-libc/src/math/atanl.c b/src/orca-libc/src/math/atanl.c new file mode 100644 index 00000000..c3b0c926 --- /dev/null +++ b/src/orca-libc/src/math/atanl.c @@ -0,0 +1,184 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_atanl.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in atan.c. + * Converted to long double by David Schultz . + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double atanl(long double x) +{ + return atan(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +#if LDBL_MANT_DIG == 64 +#define EXPMAN(u) ((u.i.se & 0x7fff)<<8 | (u.i.m>>55 & 0xff)) + +static const long double atanhi[] = { + 4.63647609000806116202e-01L, + 7.85398163397448309628e-01L, + 9.82793723247329067960e-01L, + 1.57079632679489661926e+00L, +}; + +static const long double atanlo[] = { + 1.18469937025062860669e-20L, + -1.25413940316708300586e-20L, + 2.55232234165405176172e-20L, + -2.50827880633416601173e-20L, +}; + +static const long double aT[] = { + 3.33333333333333333017e-01L, + -1.99999999999999632011e-01L, + 1.42857142857046531280e-01L, + -1.11111111100562372733e-01L, + 9.09090902935647302252e-02L, + -7.69230552476207730353e-02L, + 6.66661718042406260546e-02L, + -5.88158892835030888692e-02L, + 5.25499891539726639379e-02L, + -4.70119845393155721494e-02L, + 4.03539201366454414072e-02L, + -2.91303858419364158725e-02L, + 1.24822046299269234080e-02L, +}; + +static long double T_even(long double x) +{ + return aT[0] + x * (aT[2] + x * (aT[4] + x * (aT[6] + + x * (aT[8] + x * (aT[10] + x * aT[12]))))); +} + +static long double T_odd(long double x) +{ + return aT[1] + x * (aT[3] + x * (aT[5] + x * (aT[7] + + x * (aT[9] + x * aT[11])))); +} +#elif LDBL_MANT_DIG == 113 +#define EXPMAN(u) ((u.i.se & 0x7fff)<<8 | u.i.top>>8) + +static const long double atanhi[] = { + 4.63647609000806116214256231461214397e-01L, + 7.85398163397448309615660845819875699e-01L, + 9.82793723247329067985710611014666038e-01L, + 1.57079632679489661923132169163975140e+00L, +}; + +static const long double atanlo[] = { + 4.89509642257333492668618435220297706e-36L, + 2.16795253253094525619926100651083806e-35L, + -2.31288434538183565909319952098066272e-35L, + 4.33590506506189051239852201302167613e-35L, +}; + +static const long double aT[] = { + 3.33333333333333333333333333333333125e-01L, + -1.99999999999999999999999999999180430e-01L, + 1.42857142857142857142857142125269827e-01L, + -1.11111111111111111111110834490810169e-01L, + 9.09090909090909090908522355708623681e-02L, + -7.69230769230769230696553844935357021e-02L, + 6.66666666666666660390096773046256096e-02L, + -5.88235294117646671706582985209643694e-02L, + 5.26315789473666478515847092020327506e-02L, + -4.76190476189855517021024424991436144e-02L, + 4.34782608678695085948531993458097026e-02L, + -3.99999999632663469330634215991142368e-02L, + 3.70370363987423702891250829918659723e-02L, + -3.44827496515048090726669907612335954e-02L, + 3.22579620681420149871973710852268528e-02L, + -3.03020767654269261041647570626778067e-02L, + 2.85641979882534783223403715930946138e-02L, + -2.69824879726738568189929461383741323e-02L, + 2.54194698498808542954187110873675769e-02L, + -2.35083879708189059926183138130183215e-02L, + 2.04832358998165364349957325067131428e-02L, + -1.54489555488544397858507248612362957e-02L, + 8.64492360989278761493037861575248038e-03L, + -2.58521121597609872727919154569765469e-03L, +}; + +static long double T_even(long double x) +{ + return (aT[0] + x * (aT[2] + x * (aT[4] + x * (aT[6] + x * (aT[8] + + x * (aT[10] + x * (aT[12] + x * (aT[14] + x * (aT[16] + + x * (aT[18] + x * (aT[20] + x * aT[22]))))))))))); +} + +static long double T_odd(long double x) +{ + return (aT[1] + x * (aT[3] + x * (aT[5] + x * (aT[7] + x * (aT[9] + + x * (aT[11] + x * (aT[13] + x * (aT[15] + x * (aT[17] + + x * (aT[19] + x * (aT[21] + x * aT[23]))))))))))); +} +#endif + +long double atanl(long double x) +{ + union ldshape u = {x}; + long double w, s1, s2, z; + int id; + unsigned e = u.i.se & 0x7fff; + unsigned sign = u.i.se >> 15; + unsigned expman; + + if (e >= 0x3fff + LDBL_MANT_DIG + 1) { /* if |x| is large, atan(x)~=pi/2 */ + if (isnan(x)) + return x; + return sign ? -atanhi[3] : atanhi[3]; + } + /* Extract the exponent and the first few bits of the mantissa. */ + expman = EXPMAN(u); + if (expman < ((0x3fff - 2) << 8) + 0xc0) { /* |x| < 0.4375 */ + if (e < 0x3fff - (LDBL_MANT_DIG+1)/2) { /* if |x| is small, atanl(x)~=x */ + /* raise underflow if subnormal */ + if (e == 0) + FORCE_EVAL((float)x); + return x; + } + id = -1; + } else { + x = fabsl(x); + if (expman < (0x3fff << 8) + 0x30) { /* |x| < 1.1875 */ + if (expman < ((0x3fff - 1) << 8) + 0x60) { /* 7/16 <= |x| < 11/16 */ + id = 0; + x = (2.0*x-1.0)/(2.0+x); + } else { /* 11/16 <= |x| < 19/16 */ + id = 1; + x = (x-1.0)/(x+1.0); + } + } else { + if (expman < ((0x3fff + 1) << 8) + 0x38) { /* |x| < 2.4375 */ + id = 2; + x = (x-1.5)/(1.0+1.5*x); + } else { /* 2.4375 <= |x| */ + id = 3; + x = -1.0/x; + } + } + } + /* end of argument reduction */ + z = x*x; + w = z*z; + /* break sum aT[i]z**(i+1) into odd and even poly */ + s1 = z*T_even(w); + s2 = w*T_odd(w); + if (id < 0) + return x - x*(s1+s2); + z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x); + return sign ? -z : z; +} +#endif diff --git a/src/libc-shim/src/cbrt.c b/src/orca-libc/src/math/cbrt.c similarity index 100% rename from src/libc-shim/src/cbrt.c rename to src/orca-libc/src/math/cbrt.c diff --git a/src/libc-shim/src/cbrtf.c b/src/orca-libc/src/math/cbrtf.c similarity index 100% rename from src/libc-shim/src/cbrtf.c rename to src/orca-libc/src/math/cbrtf.c diff --git a/src/orca-libc/src/math/cbrtl.c b/src/orca-libc/src/math/cbrtl.c new file mode 100644 index 00000000..ceff9136 --- /dev/null +++ b/src/orca-libc/src/math/cbrtl.c @@ -0,0 +1,124 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrtl.c */ +/*- + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2009-2011, Bruce D. Evans, Steven G. Kargl, David Schultz. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * The argument reduction and testing for exceptional cases was + * written by Steven G. Kargl with input from Bruce D. Evans + * and David A. Schultz. + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double cbrtl(long double x) +{ + return cbrt(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +static const unsigned B1 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */ + +long double cbrtl(long double x) +{ + union ldshape u = {x}, v; + union {float f; uint32_t i;} uft; + long double r, s, t, w; + double_t dr, dt, dx; + float_t ft; + int e = u.i.se & 0x7fff; + int sign = u.i.se & 0x8000; + + /* + * If x = +-Inf, then cbrt(x) = +-Inf. + * If x = NaN, then cbrt(x) = NaN. + */ + if (e == 0x7fff) + return x + x; + if (e == 0) { + /* Adjust subnormal numbers. */ + u.f *= 0x1p120; + e = u.i.se & 0x7fff; + /* If x = +-0, then cbrt(x) = +-0. */ + if (e == 0) + return x; + e -= 120; + } + e -= 0x3fff; + u.i.se = 0x3fff; + x = u.f; + switch (e % 3) { + case 1: + case -2: + x *= 2; + e--; + break; + case 2: + case -1: + x *= 4; + e -= 2; + break; + } + v.f = 1.0; + v.i.se = sign | (0x3fff + e/3); + + /* + * The following is the guts of s_cbrtf, with the handling of + * special values removed and extra care for accuracy not taken, + * but with most of the extra accuracy not discarded. + */ + + /* ~5-bit estimate: */ + uft.f = x; + uft.i = (uft.i & 0x7fffffff)/3 + B1; + ft = uft.f; + + /* ~16-bit estimate: */ + dx = x; + dt = ft; + dr = dt * dt * dt; + dt = dt * (dx + dx + dr) / (dx + dr + dr); + + /* ~47-bit estimate: */ + dr = dt * dt * dt; + dt = dt * (dx + dx + dr) / (dx + dr + dr); + +#if LDBL_MANT_DIG == 64 + /* + * dt is cbrtl(x) to ~47 bits (after x has been reduced to 1 <= x < 8). + * Round it away from zero to 32 bits (32 so that t*t is exact, and + * away from zero for technical reasons). + */ + t = dt + (0x1.0p32L + 0x1.0p-31L) - 0x1.0p32; +#elif LDBL_MANT_DIG == 113 + /* + * Round dt away from zero to 47 bits. Since we don't trust the 47, + * add 2 47-bit ulps instead of 1 to round up. Rounding is slow and + * might be avoidable in this case, since on most machines dt will + * have been evaluated in 53-bit precision and the technical reasons + * for rounding up might not apply to either case in cbrtl() since + * dt is much more accurate than needed. + */ + t = dt + 0x2.0p-46 + 0x1.0p60L - 0x1.0p60; +#endif + + /* + * Final step Newton iteration to 64 or 113 bits with + * error < 0.667 ulps + */ + s = t*t; /* t*t is exact */ + r = x/s; /* error <= 0.5 ulps; |r| < |t| */ + w = t+t; /* t+t is exact */ + r = (r-t)/(w+r); /* r-t is exact; w+r ~= 3*t */ + t = t+t*r; /* error <= 0.5 + 0.5/3 + epsilon */ + + t *= v.f; + return t; +} +#endif diff --git a/src/orca-libc/src/math/ceil.c b/src/orca-libc/src/math/ceil.c new file mode 100644 index 00000000..b13e6f2d --- /dev/null +++ b/src/orca-libc/src/math/ceil.c @@ -0,0 +1,31 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const double_t toint = 1/EPS; + +double ceil(double x) +{ + union {double f; uint64_t i;} u = {x}; + int e = u.i >> 52 & 0x7ff; + double_t y; + + if (e >= 0x3ff+52 || x == 0) + return x; + /* y = int(x) - x, where int(x) is an integer neighbor of x */ + if (u.i >> 63) + y = x - toint + toint - x; + else + y = x + toint - toint - x; + /* special case because of non-nearest rounding modes */ + if (e <= 0x3ff-1) { + FORCE_EVAL(y); + return u.i >> 63 ? -0.0 : 1; + } + if (y < 0) + return x + y + 1; + return x + y; +} diff --git a/src/orca-libc/src/math/ceilf.c b/src/orca-libc/src/math/ceilf.c new file mode 100644 index 00000000..869835f3 --- /dev/null +++ b/src/orca-libc/src/math/ceilf.c @@ -0,0 +1,27 @@ +#include "libm.h" + +float ceilf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = (int)(u.i >> 23 & 0xff) - 0x7f; + uint32_t m; + + if (e >= 23) + return x; + if (e >= 0) { + m = 0x007fffff >> e; + if ((u.i & m) == 0) + return x; + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31 == 0) + u.i += m; + u.i &= ~m; + } else { + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31) + u.f = -0.0; + else if (u.i << 1) + u.f = 1.0; + } + return u.f; +} diff --git a/src/orca-libc/src/math/ceill.c b/src/orca-libc/src/math/ceill.c new file mode 100644 index 00000000..60a83020 --- /dev/null +++ b/src/orca-libc/src/math/ceill.c @@ -0,0 +1,34 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double ceill(long double x) +{ + return ceil(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +static const long double toint = 1/LDBL_EPSILON; + +long double ceill(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + long double y; + + if (e >= 0x3fff+LDBL_MANT_DIG-1 || x == 0) + return x; + /* y = int(x) - x, where int(x) is an integer neighbor of x */ + if (u.i.se >> 15) + y = x - toint + toint - x; + else + y = x + toint - toint - x; + /* special case because of non-nearest rounding modes */ + if (e <= 0x3fff-1) { + FORCE_EVAL(y); + return u.i.se >> 15 ? -0.0 : 1; + } + if (y < 0) + return x + y + 1; + return x + y; +} +#endif diff --git a/src/orca-libc/src/math/copysign.c b/src/orca-libc/src/math/copysign.c new file mode 100644 index 00000000..b09331b6 --- /dev/null +++ b/src/orca-libc/src/math/copysign.c @@ -0,0 +1,8 @@ +#include "libm.h" + +double copysign(double x, double y) { + union {double f; uint64_t i;} ux={x}, uy={y}; + ux.i &= -1ULL/2; + ux.i |= uy.i & 1ULL<<63; + return ux.f; +} diff --git a/src/orca-libc/src/math/copysignf.c b/src/orca-libc/src/math/copysignf.c new file mode 100644 index 00000000..0af6ae9b --- /dev/null +++ b/src/orca-libc/src/math/copysignf.c @@ -0,0 +1,10 @@ +#include +#include + +float copysignf(float x, float y) +{ + union {float f; uint32_t i;} ux={x}, uy={y}; + ux.i &= 0x7fffffff; + ux.i |= uy.i & 0x80000000; + return ux.f; +} diff --git a/src/orca-libc/src/math/copysignl.c b/src/orca-libc/src/math/copysignl.c new file mode 100644 index 00000000..9dd933cf --- /dev/null +++ b/src/orca-libc/src/math/copysignl.c @@ -0,0 +1,16 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double copysignl(long double x, long double y) +{ + return copysign(x, y); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double copysignl(long double x, long double y) +{ + union ldshape ux = {x}, uy = {y}; + ux.i.se &= 0x7fff; + ux.i.se |= uy.i.se & 0x8000; + return ux.f; +} +#endif diff --git a/src/libc-shim/src/cos.c b/src/orca-libc/src/math/cos.c similarity index 67% rename from src/libc-shim/src/cos.c rename to src/orca-libc/src/math/cos.c index 040883c5..ee97f68b 100644 --- a/src/libc-shim/src/cos.c +++ b/src/orca-libc/src/math/cos.c @@ -44,40 +44,34 @@ double cos(double x) { - double y[2]; - uint32_t ix; - unsigned n; + double y[2]; + uint32_t ix; + unsigned n; - GET_HIGH_WORD(ix, x); - ix &= 0x7fffffff; + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; - /* |x| ~< pi/4 */ - if(ix <= 0x3fe921fb) - { - if(ix < 0x3e46a09e) - { /* |x| < 2**-27 * sqrt(2) */ - /* raise inexact if x!=0 */ - FORCE_EVAL(x + 0x1p120f); - return 1.0; - } - return __cos(x, 0); - } + /* |x| ~< pi/4 */ + if (ix <= 0x3fe921fb) { + if (ix < 0x3e46a09e) { /* |x| < 2**-27 * sqrt(2) */ + /* raise inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + return 1.0; + } + return __cos(x, 0); + } - /* cos(Inf or NaN) is NaN */ - if(ix >= 0x7ff00000) - return x - x; + /* cos(Inf or NaN) is NaN */ + if (ix >= 0x7ff00000) + return x-x; - /* argument reduction */ - n = __rem_pio2(x, y); - switch(n & 3) - { - case 0: - return __cos(y[0], y[1]); - case 1: - return -__sin(y[0], y[1], 1); - case 2: - return -__cos(y[0], y[1]); - default: - return __sin(y[0], y[1], 1); - } + /* argument reduction */ + n = __rem_pio2(x, y); + switch (n&3) { + case 0: return __cos(y[0], y[1]); + case 1: return -__sin(y[0], y[1], 1); + case 2: return -__cos(y[0], y[1]); + default: + return __sin(y[0], y[1], 1); + } } diff --git a/src/orca-libc/src/math/cosf.c b/src/orca-libc/src/math/cosf.c new file mode 100644 index 00000000..23f3e5bf --- /dev/null +++ b/src/orca-libc/src/math/cosf.c @@ -0,0 +1,78 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +/* Small multiples of pi/2 rounded to double precision. */ +static const double +c1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ +c2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ +c3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ +c4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + +float cosf(float x) +{ + double y; + uint32_t ix; + unsigned n, sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + + if (ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if (ix < 0x39800000) { /* |x| < 2**-12 */ + /* raise inexact if x != 0 */ + FORCE_EVAL(x + 0x1p120f); + return 1.0f; + } + return __cosdf(x); + } + if (ix <= 0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if (ix > 0x4016cbe3) /* |x| ~> 3*pi/4 */ + return -__cosdf(sign ? x+c2pio2 : x-c2pio2); + else { + if (sign) + return __sindf(x + c1pio2); + else + return __sindf(c1pio2 - x); + } + } + if (ix <= 0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if (ix > 0x40afeddf) /* |x| ~> 7*pi/4 */ + return __cosdf(sign ? x+c4pio2 : x-c4pio2); + else { + if (sign) + return __sindf(-x - c3pio2); + else + return __sindf(x - c3pio2); + } + } + + /* cos(Inf or NaN) is NaN */ + if (ix >= 0x7f800000) + return x-x; + + /* general argument reduction needed */ + n = __rem_pio2f(x,&y); + switch (n&3) { + case 0: return __cosdf(y); + case 1: return __sindf(-y); + case 2: return -__cosdf(y); + default: + return __sindf(y); + } +} diff --git a/src/orca-libc/src/math/cosh.c b/src/orca-libc/src/math/cosh.c new file mode 100644 index 00000000..2cdf0023 --- /dev/null +++ b/src/orca-libc/src/math/cosh.c @@ -0,0 +1,44 @@ +#include "libm.h" + +/* cosh(x) = (exp(x) + 1/exp(x))/2 + * = 1 + 0.5*(exp(x)-1)*(exp(x)-1)/exp(x) + * = 1 + x*x/2 + o(x^4) + */ +double cosh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + uint32_t w; + double t; + + /* |x| */ + u.i &= (uint64_t)-1/2; + x = u.f; + w = u.i >> 32; + + /* |x| < log(2) */ + if (w < 0x3fe62e42) { + if (w < 0x3ff00000 - (26<<20)) { + /* raise inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + return 1; + } + t = expm1(x); + return 1 + t*t/(2*(1+t)); + } + + /* |x| < log(DBL_MAX) */ + if (w < 0x40862e42) { + t = exp(x); + /* note: if x>log(0x1p26) then the 1/t is not needed */ + return 0.5*(t + 1/t); + } + + /* |x| > log(DBL_MAX) or nan */ + /* note: the result is stored to handle overflow */ +#ifdef __wasilibc_unmodified_upstream // Wasm doesn't have alternate rounding modes + t = __expo2(x, 1.0); +#else + t = __expo2(x); +#endif + return t; +} diff --git a/src/orca-libc/src/math/coshf.c b/src/orca-libc/src/math/coshf.c new file mode 100644 index 00000000..b946c0b0 --- /dev/null +++ b/src/orca-libc/src/math/coshf.c @@ -0,0 +1,37 @@ +#include "libm.h" + +float coshf(float x) +{ + union {float f; uint32_t i;} u = {.f = x}; + uint32_t w; + float t; + + /* |x| */ + u.i &= 0x7fffffff; + x = u.f; + w = u.i; + + /* |x| < log(2) */ + if (w < 0x3f317217) { + if (w < 0x3f800000 - (12<<23)) { + FORCE_EVAL(x + 0x1p120f); + return 1; + } + t = expm1f(x); + return 1 + t*t/(2*(1+t)); + } + + /* |x| < log(FLT_MAX) */ + if (w < 0x42b17217) { + t = expf(x); + return 0.5f*(t + 1/t); + } + + /* |x| > log(FLT_MAX) or nan */ +#ifdef __wasilibc_unmodified_upstream // Wasm doesn't have alternate rounding modes + t = __expo2f(x, 1.0f); +#else + t = __expo2f(x); +#endif + return t; +} diff --git a/src/orca-libc/src/math/coshl.c b/src/orca-libc/src/math/coshl.c new file mode 100644 index 00000000..06a56fe3 --- /dev/null +++ b/src/orca-libc/src/math/coshl.c @@ -0,0 +1,47 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double coshl(long double x) +{ + return cosh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +long double coshl(long double x) +{ + union ldshape u = {x}; + unsigned ex = u.i.se & 0x7fff; + uint32_t w; + long double t; + + /* |x| */ + u.i.se = ex; + x = u.f; + w = u.i.m >> 32; + + /* |x| < log(2) */ + if (ex < 0x3fff-1 || (ex == 0x3fff-1 && w < 0xb17217f7)) { + if (ex < 0x3fff-32) { + FORCE_EVAL(x + 0x1p120f); + return 1; + } + t = expm1l(x); + return 1 + t*t/(2*(1+t)); + } + + /* |x| < log(LDBL_MAX) */ + if (ex < 0x3fff+13 || (ex == 0x3fff+13 && w < 0xb17217f7)) { + t = expl(x); + return 0.5*(t + 1/t); + } + + /* |x| > log(LDBL_MAX) or nan */ + t = expl(0.5*x); + return 0.5*t*t; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double coshl(long double x) +{ + return cosh(x); +} +#endif diff --git a/src/orca-libc/src/math/cosl.c b/src/orca-libc/src/math/cosl.c new file mode 100644 index 00000000..79c41c77 --- /dev/null +++ b/src/orca-libc/src/math/cosl.c @@ -0,0 +1,39 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double cosl(long double x) { + return cos(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double cosl(long double x) +{ + union ldshape u = {x}; + unsigned n; + long double y[2], hi, lo; + + u.i.se &= 0x7fff; + if (u.i.se == 0x7fff) + return x - x; + x = u.f; + if (x < M_PI_4) { + if (u.i.se < 0x3fff - LDBL_MANT_DIG) + /* raise inexact if x!=0 */ + return 1.0 + x; + return __cosl(x, 0); + } + n = __rem_pio2l(x, y); + hi = y[0]; + lo = y[1]; + switch (n & 3) { + case 0: + return __cosl(hi, lo); + case 1: + return -__sinl(hi, lo, 1); + case 2: + return -__cosl(hi, lo); + case 3: + default: + return __sinl(hi, lo, 1); + } +} +#endif diff --git a/src/orca-libc/src/math/erf.c b/src/orca-libc/src/math/erf.c new file mode 100644 index 00000000..2f30a298 --- /dev/null +++ b/src/orca-libc/src/math/erf.c @@ -0,0 +1,273 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_erf.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* double erf(double x) + * double erfc(double x) + * x + * 2 |\ + * erf(x) = --------- | exp(-t*t)dt + * sqrt(pi) \| + * 0 + * + * erfc(x) = 1-erf(x) + * Note that + * erf(-x) = -erf(x) + * erfc(-x) = 2 - erfc(x) + * + * Method: + * 1. For |x| in [0, 0.84375] + * erf(x) = x + x*R(x^2) + * erfc(x) = 1 - erf(x) if x in [-.84375,0.25] + * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375] + * where R = P/Q where P is an odd poly of degree 8 and + * Q is an odd poly of degree 10. + * -57.90 + * | R - (erf(x)-x)/x | <= 2 + * + * + * Remark. The formula is derived by noting + * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) + * and that + * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 + * is close to one. The interval is chosen because the fix + * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is + * near 0.6174), and by some experiment, 0.84375 is chosen to + * guarantee the error is less than one ulp for erf. + * + * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and + * c = 0.84506291151 rounded to single (24 bits) + * erf(x) = sign(x) * (c + P1(s)/Q1(s)) + * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0 + * 1+(c+P1(s)/Q1(s)) if x < 0 + * |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06 + * Remark: here we use the taylor series expansion at x=1. + * erf(1+s) = erf(1) + s*Poly(s) + * = 0.845.. + P1(s)/Q1(s) + * That is, we use rational approximation to approximate + * erf(1+s) - (c = (single)0.84506291151) + * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] + * where + * P1(s) = degree 6 poly in s + * Q1(s) = degree 6 poly in s + * + * 3. For x in [1.25,1/0.35(~2.857143)], + * erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1) + * erf(x) = 1 - erfc(x) + * where + * R1(z) = degree 7 poly in z, (z=1/x^2) + * S1(z) = degree 8 poly in z + * + * 4. For x in [1/0.35,28] + * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 + * = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6 x >= 28 + * erf(x) = sign(x) *(1 - tiny) (raise inexact) + * erfc(x) = tiny*tiny (raise underflow) if x > 0 + * = 2 - tiny if x<0 + * + * 7. Special case: + * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, + * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, + * erfc/erf(NaN) is NaN + */ + +#include "libm.h" + +static const double +erx = 8.45062911510467529297e-01, /* 0x3FEB0AC1, 0x60000000 */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +efx8 = 1.02703333676410069053e+00, /* 0x3FF06EBA, 0x8214DB69 */ +pp0 = 1.28379167095512558561e-01, /* 0x3FC06EBA, 0x8214DB68 */ +pp1 = -3.25042107247001499370e-01, /* 0xBFD4CD7D, 0x691CB913 */ +pp2 = -2.84817495755985104766e-02, /* 0xBF9D2A51, 0xDBD7194F */ +pp3 = -5.77027029648944159157e-03, /* 0xBF77A291, 0x236668E4 */ +pp4 = -2.37630166566501626084e-05, /* 0xBEF8EAD6, 0x120016AC */ +qq1 = 3.97917223959155352819e-01, /* 0x3FD97779, 0xCDDADC09 */ +qq2 = 6.50222499887672944485e-02, /* 0x3FB0A54C, 0x5536CEBA */ +qq3 = 5.08130628187576562776e-03, /* 0x3F74D022, 0xC4D36B0F */ +qq4 = 1.32494738004321644526e-04, /* 0x3F215DC9, 0x221C1A10 */ +qq5 = -3.96022827877536812320e-06, /* 0xBED09C43, 0x42A26120 */ +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +pa0 = -2.36211856075265944077e-03, /* 0xBF6359B8, 0xBEF77538 */ +pa1 = 4.14856118683748331666e-01, /* 0x3FDA8D00, 0xAD92B34D */ +pa2 = -3.72207876035701323847e-01, /* 0xBFD7D240, 0xFBB8C3F1 */ +pa3 = 3.18346619901161753674e-01, /* 0x3FD45FCA, 0x805120E4 */ +pa4 = -1.10894694282396677476e-01, /* 0xBFBC6398, 0x3D3E28EC */ +pa5 = 3.54783043256182359371e-02, /* 0x3FA22A36, 0x599795EB */ +pa6 = -2.16637559486879084300e-03, /* 0xBF61BF38, 0x0A96073F */ +qa1 = 1.06420880400844228286e-01, /* 0x3FBB3E66, 0x18EEE323 */ +qa2 = 5.40397917702171048937e-01, /* 0x3FE14AF0, 0x92EB6F33 */ +qa3 = 7.18286544141962662868e-02, /* 0x3FB2635C, 0xD99FE9A7 */ +qa4 = 1.26171219808761642112e-01, /* 0x3FC02660, 0xE763351F */ +qa5 = 1.36370839120290507362e-02, /* 0x3F8BEDC2, 0x6B51DD1C */ +qa6 = 1.19844998467991074170e-02, /* 0x3F888B54, 0x5735151D */ +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +ra0 = -9.86494403484714822705e-03, /* 0xBF843412, 0x600D6435 */ +ra1 = -6.93858572707181764372e-01, /* 0xBFE63416, 0xE4BA7360 */ +ra2 = -1.05586262253232909814e+01, /* 0xC0251E04, 0x41B0E726 */ +ra3 = -6.23753324503260060396e+01, /* 0xC04F300A, 0xE4CBA38D */ +ra4 = -1.62396669462573470355e+02, /* 0xC0644CB1, 0x84282266 */ +ra5 = -1.84605092906711035994e+02, /* 0xC067135C, 0xEBCCABB2 */ +ra6 = -8.12874355063065934246e+01, /* 0xC0545265, 0x57E4D2F2 */ +ra7 = -9.81432934416914548592e+00, /* 0xC023A0EF, 0xC69AC25C */ +sa1 = 1.96512716674392571292e+01, /* 0x4033A6B9, 0xBD707687 */ +sa2 = 1.37657754143519042600e+02, /* 0x4061350C, 0x526AE721 */ +sa3 = 4.34565877475229228821e+02, /* 0x407B290D, 0xD58A1A71 */ +sa4 = 6.45387271733267880336e+02, /* 0x40842B19, 0x21EC2868 */ +sa5 = 4.29008140027567833386e+02, /* 0x407AD021, 0x57700314 */ +sa6 = 1.08635005541779435134e+02, /* 0x405B28A3, 0xEE48AE2C */ +sa7 = 6.57024977031928170135e+00, /* 0x401A47EF, 0x8E484A93 */ +sa8 = -6.04244152148580987438e-02, /* 0xBFAEEFF2, 0xEE749A62 */ +/* + * Coefficients for approximation to erfc in [1/.35,28] + */ +rb0 = -9.86494292470009928597e-03, /* 0xBF843412, 0x39E86F4A */ +rb1 = -7.99283237680523006574e-01, /* 0xBFE993BA, 0x70C285DE */ +rb2 = -1.77579549177547519889e+01, /* 0xC031C209, 0x555F995A */ +rb3 = -1.60636384855821916062e+02, /* 0xC064145D, 0x43C5ED98 */ +rb4 = -6.37566443368389627722e+02, /* 0xC083EC88, 0x1375F228 */ +rb5 = -1.02509513161107724954e+03, /* 0xC0900461, 0x6A2E5992 */ +rb6 = -4.83519191608651397019e+02, /* 0xC07E384E, 0x9BDC383F */ +sb1 = 3.03380607434824582924e+01, /* 0x403E568B, 0x261D5190 */ +sb2 = 3.25792512996573918826e+02, /* 0x40745CAE, 0x221B9F0A */ +sb3 = 1.53672958608443695994e+03, /* 0x409802EB, 0x189D5118 */ +sb4 = 3.19985821950859553908e+03, /* 0x40A8FFB7, 0x688C246A */ +sb5 = 2.55305040643316442583e+03, /* 0x40A3F219, 0xCEDF3BE6 */ +sb6 = 4.74528541206955367215e+02, /* 0x407DA874, 0xE79FE763 */ +sb7 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */ + +static double erfc1(double x) +{ + double_t s,P,Q; + + s = fabs(x) - 1; + P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6))))); + Q = 1+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6))))); + return 1 - erx - P/Q; +} + +static double erfc2(uint32_t ix, double x) +{ + double_t s,R,S; + double z; + + if (ix < 0x3ff40000) /* |x| < 1.25 */ + return erfc1(x); + + x = fabs(x); + s = 1/(x*x); + if (ix < 0x4006db6d) { /* |x| < 1/.35 ~ 2.85714 */ + R = ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*( + ra5+s*(ra6+s*ra7)))))); + S = 1.0+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*( + sa5+s*(sa6+s*(sa7+s*sa8))))))); + } else { /* |x| > 1/.35 */ + R = rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*( + rb5+s*rb6))))); + S = 1.0+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*( + sb5+s*(sb6+s*sb7)))))); + } + z = x; + SET_LOW_WORD(z,0); + return exp(-z*z-0.5625)*exp((z-x)*(z+x)+R/S)/x; +} + +double erf(double x) +{ + double r,s,z,y; + uint32_t ix; + int sign; + + GET_HIGH_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix >= 0x7ff00000) { + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1-2*sign + 1/x; + } + if (ix < 0x3feb0000) { /* |x| < 0.84375 */ + if (ix < 0x3e300000) { /* |x| < 2**-28 */ + /* avoid underflow */ + return 0.125*(8*x + efx8*x); + } + z = x*x; + r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); + s = 1.0+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); + y = r/s; + return x + x*y; + } + if (ix < 0x40180000) /* 0.84375 <= |x| < 6 */ + y = 1 - erfc2(ix,x); + else + y = 1 - 0x1p-1022; + return sign ? -y : y; +} + +double erfc(double x) +{ + double r,s,z,y; + uint32_t ix; + int sign; + + GET_HIGH_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix >= 0x7ff00000) { + /* erfc(nan)=nan, erfc(+-inf)=0,2 */ + return 2*sign + 1/x; + } + if (ix < 0x3feb0000) { /* |x| < 0.84375 */ + if (ix < 0x3c700000) /* |x| < 2**-56 */ + return 1.0 - x; + z = x*x; + r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); + s = 1.0+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); + y = r/s; + if (sign || ix < 0x3fd00000) { /* x < 1/4 */ + return 1.0 - (x+x*y); + } + return 0.5 - (x - 0.5 + x*y); + } + if (ix < 0x403c0000) { /* 0.84375 <= |x| < 28 */ + return sign ? 2 - erfc2(ix,x) : erfc2(ix,x); + } + return sign ? 2 - 0x1p-1022 : 0x1p-1022*0x1p-1022; +} diff --git a/src/orca-libc/src/math/erff.c b/src/orca-libc/src/math/erff.c new file mode 100644 index 00000000..ed5f3975 --- /dev/null +++ b/src/orca-libc/src/math/erff.c @@ -0,0 +1,183 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_erff.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float +erx = 8.4506291151e-01, /* 0x3f58560b */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +efx8 = 1.0270333290e+00, /* 0x3f8375d4 */ +pp0 = 1.2837916613e-01, /* 0x3e0375d4 */ +pp1 = -3.2504209876e-01, /* 0xbea66beb */ +pp2 = -2.8481749818e-02, /* 0xbce9528f */ +pp3 = -5.7702702470e-03, /* 0xbbbd1489 */ +pp4 = -2.3763017452e-05, /* 0xb7c756b1 */ +qq1 = 3.9791721106e-01, /* 0x3ecbbbce */ +qq2 = 6.5022252500e-02, /* 0x3d852a63 */ +qq3 = 5.0813062117e-03, /* 0x3ba68116 */ +qq4 = 1.3249473704e-04, /* 0x390aee49 */ +qq5 = -3.9602282413e-06, /* 0xb684e21a */ +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +pa0 = -2.3621185683e-03, /* 0xbb1acdc6 */ +pa1 = 4.1485610604e-01, /* 0x3ed46805 */ +pa2 = -3.7220788002e-01, /* 0xbebe9208 */ +pa3 = 3.1834661961e-01, /* 0x3ea2fe54 */ +pa4 = -1.1089469492e-01, /* 0xbde31cc2 */ +pa5 = 3.5478305072e-02, /* 0x3d1151b3 */ +pa6 = -2.1663755178e-03, /* 0xbb0df9c0 */ +qa1 = 1.0642088205e-01, /* 0x3dd9f331 */ +qa2 = 5.4039794207e-01, /* 0x3f0a5785 */ +qa3 = 7.1828655899e-02, /* 0x3d931ae7 */ +qa4 = 1.2617121637e-01, /* 0x3e013307 */ +qa5 = 1.3637083583e-02, /* 0x3c5f6e13 */ +qa6 = 1.1984500103e-02, /* 0x3c445aa3 */ +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +ra0 = -9.8649440333e-03, /* 0xbc21a093 */ +ra1 = -6.9385856390e-01, /* 0xbf31a0b7 */ +ra2 = -1.0558626175e+01, /* 0xc128f022 */ +ra3 = -6.2375331879e+01, /* 0xc2798057 */ +ra4 = -1.6239666748e+02, /* 0xc322658c */ +ra5 = -1.8460508728e+02, /* 0xc3389ae7 */ +ra6 = -8.1287437439e+01, /* 0xc2a2932b */ +ra7 = -9.8143291473e+00, /* 0xc11d077e */ +sa1 = 1.9651271820e+01, /* 0x419d35ce */ +sa2 = 1.3765776062e+02, /* 0x4309a863 */ +sa3 = 4.3456588745e+02, /* 0x43d9486f */ +sa4 = 6.4538726807e+02, /* 0x442158c9 */ +sa5 = 4.2900814819e+02, /* 0x43d6810b */ +sa6 = 1.0863500214e+02, /* 0x42d9451f */ +sa7 = 6.5702495575e+00, /* 0x40d23f7c */ +sa8 = -6.0424413532e-02, /* 0xbd777f97 */ +/* + * Coefficients for approximation to erfc in [1/.35,28] + */ +rb0 = -9.8649431020e-03, /* 0xbc21a092 */ +rb1 = -7.9928326607e-01, /* 0xbf4c9dd4 */ +rb2 = -1.7757955551e+01, /* 0xc18e104b */ +rb3 = -1.6063638306e+02, /* 0xc320a2ea */ +rb4 = -6.3756646729e+02, /* 0xc41f6441 */ +rb5 = -1.0250950928e+03, /* 0xc480230b */ +rb6 = -4.8351919556e+02, /* 0xc3f1c275 */ +sb1 = 3.0338060379e+01, /* 0x41f2b459 */ +sb2 = 3.2579251099e+02, /* 0x43a2e571 */ +sb3 = 1.5367296143e+03, /* 0x44c01759 */ +sb4 = 3.1998581543e+03, /* 0x4547fdbb */ +sb5 = 2.5530502930e+03, /* 0x451f90ce */ +sb6 = 4.7452853394e+02, /* 0x43ed43a7 */ +sb7 = -2.2440952301e+01; /* 0xc1b38712 */ + +static float erfc1(float x) +{ + float_t s,P,Q; + + s = fabsf(x) - 1; + P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6))))); + Q = 1+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6))))); + return 1 - erx - P/Q; +} + +static float erfc2(uint32_t ix, float x) +{ + float_t s,R,S; + float z; + + if (ix < 0x3fa00000) /* |x| < 1.25 */ + return erfc1(x); + + x = fabsf(x); + s = 1/(x*x); + if (ix < 0x4036db6d) { /* |x| < 1/0.35 */ + R = ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*( + ra5+s*(ra6+s*ra7)))))); + S = 1.0f+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*( + sa5+s*(sa6+s*(sa7+s*sa8))))))); + } else { /* |x| >= 1/0.35 */ + R = rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*( + rb5+s*rb6))))); + S = 1.0f+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*( + sb5+s*(sb6+s*sb7)))))); + } + GET_FLOAT_WORD(ix, x); + SET_FLOAT_WORD(z, ix&0xffffe000); + return expf(-z*z - 0.5625f) * expf((z-x)*(z+x) + R/S)/x; +} + +float erff(float x) +{ + float r,s,z,y; + uint32_t ix; + int sign; + + GET_FLOAT_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix >= 0x7f800000) { + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1-2*sign + 1/x; + } + if (ix < 0x3f580000) { /* |x| < 0.84375 */ + if (ix < 0x31800000) { /* |x| < 2**-28 */ + /*avoid underflow */ + return 0.125f*(8*x + efx8*x); + } + z = x*x; + r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); + s = 1+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); + y = r/s; + return x + x*y; + } + if (ix < 0x40c00000) /* |x| < 6 */ + y = 1 - erfc2(ix,x); + else + y = 1 - 0x1p-120f; + return sign ? -y : y; +} + +float erfcf(float x) +{ + float r,s,z,y; + uint32_t ix; + int sign; + + GET_FLOAT_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix >= 0x7f800000) { + /* erfc(nan)=nan, erfc(+-inf)=0,2 */ + return 2*sign + 1/x; + } + + if (ix < 0x3f580000) { /* |x| < 0.84375 */ + if (ix < 0x23800000) /* |x| < 2**-56 */ + return 1.0f - x; + z = x*x; + r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); + s = 1.0f+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); + y = r/s; + if (sign || ix < 0x3e800000) /* x < 1/4 */ + return 1.0f - (x+x*y); + return 0.5f - (x - 0.5f + x*y); + } + if (ix < 0x41e00000) { /* |x| < 28 */ + return sign ? 2 - erfc2(ix,x) : erfc2(ix,x); + } + return sign ? 2 - 0x1p-120f : 0x1p-120f*0x1p-120f; +} diff --git a/src/orca-libc/src/math/erfl.c b/src/orca-libc/src/math/erfl.c new file mode 100644 index 00000000..e267c231 --- /dev/null +++ b/src/orca-libc/src/math/erfl.c @@ -0,0 +1,353 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_erfl.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* double erf(double x) + * double erfc(double x) + * x + * 2 |\ + * erf(x) = --------- | exp(-t*t)dt + * sqrt(pi) \| + * 0 + * + * erfc(x) = 1-erf(x) + * Note that + * erf(-x) = -erf(x) + * erfc(-x) = 2 - erfc(x) + * + * Method: + * 1. For |x| in [0, 0.84375] + * erf(x) = x + x*R(x^2) + * erfc(x) = 1 - erf(x) if x in [-.84375,0.25] + * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375] + * Remark. The formula is derived by noting + * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) + * and that + * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 + * is close to one. The interval is chosen because the fix + * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is + * near 0.6174), and by some experiment, 0.84375 is chosen to + * guarantee the error is less than one ulp for erf. + * + * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and + * c = 0.84506291151 rounded to single (24 bits) + * erf(x) = sign(x) * (c + P1(s)/Q1(s)) + * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0 + * 1+(c+P1(s)/Q1(s)) if x < 0 + * Remark: here we use the taylor series expansion at x=1. + * erf(1+s) = erf(1) + s*Poly(s) + * = 0.845.. + P1(s)/Q1(s) + * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] + * + * 3. For x in [1.25,1/0.35(~2.857143)], + * erfc(x) = (1/x)*exp(-x*x-0.5625+R1(z)/S1(z)) + * z=1/x^2 + * erf(x) = 1 - erfc(x) + * + * 4. For x in [1/0.35,107] + * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 + * = 2.0 - (1/x)*exp(-x*x-0.5625+R2(z)/S2(z)) + * if -6.666 x >= 107 + * erf(x) = sign(x) *(1 - tiny) (raise inexact) + * erfc(x) = tiny*tiny (raise underflow) if x > 0 + * = 2 - tiny if x<0 + * + * 7. Special case: + * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, + * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, + * erfc/erf(NaN) is NaN + */ + + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double erfl(long double x) +{ + return erf(x); +} +long double erfcl(long double x) +{ + return erfc(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +static const long double +erx = 0.845062911510467529296875L, + +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +/* 8 * (2/sqrt(pi) - 1) */ +efx8 = 1.0270333367641005911692712249723613735048E0L, +pp[6] = { + 1.122751350964552113068262337278335028553E6L, + -2.808533301997696164408397079650699163276E6L, + -3.314325479115357458197119660818768924100E5L, + -6.848684465326256109712135497895525446398E4L, + -2.657817695110739185591505062971929859314E3L, + -1.655310302737837556654146291646499062882E2L, +}, +qq[6] = { + 8.745588372054466262548908189000448124232E6L, + 3.746038264792471129367533128637019611485E6L, + 7.066358783162407559861156173539693900031E5L, + 7.448928604824620999413120955705448117056E4L, + 4.511583986730994111992253980546131408924E3L, + 1.368902937933296323345610240009071254014E2L, + /* 1.000000000000000000000000000000000000000E0 */ +}, + +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +/* erf(x+1) = 0.845062911510467529296875 + pa(x)/qa(x) + -0.15625 <= x <= +.25 + Peak relative error 8.5e-22 */ +pa[8] = { + -1.076952146179812072156734957705102256059E0L, + 1.884814957770385593365179835059971587220E2L, + -5.339153975012804282890066622962070115606E1L, + 4.435910679869176625928504532109635632618E1L, + 1.683219516032328828278557309642929135179E1L, + -2.360236618396952560064259585299045804293E0L, + 1.852230047861891953244413872297940938041E0L, + 9.394994446747752308256773044667843200719E-2L, +}, +qa[7] = { + 4.559263722294508998149925774781887811255E2L, + 3.289248982200800575749795055149780689738E2L, + 2.846070965875643009598627918383314457912E2L, + 1.398715859064535039433275722017479994465E2L, + 6.060190733759793706299079050985358190726E1L, + 2.078695677795422351040502569964299664233E1L, + 4.641271134150895940966798357442234498546E0L, + /* 1.000000000000000000000000000000000000000E0 */ +}, + +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +/* erfc(1/x) = x exp (-1/x^2 - 0.5625 + ra(x^2)/sa(x^2)) + 1/2.85711669921875 < 1/x < 1/1.25 + Peak relative error 3.1e-21 */ +ra[] = { + 1.363566591833846324191000679620738857234E-1L, + 1.018203167219873573808450274314658434507E1L, + 1.862359362334248675526472871224778045594E2L, + 1.411622588180721285284945138667933330348E3L, + 5.088538459741511988784440103218342840478E3L, + 8.928251553922176506858267311750789273656E3L, + 7.264436000148052545243018622742770549982E3L, + 2.387492459664548651671894725748959751119E3L, + 2.220916652813908085449221282808458466556E2L, +}, +sa[] = { + -1.382234625202480685182526402169222331847E1L, + -3.315638835627950255832519203687435946482E2L, + -2.949124863912936259747237164260785326692E3L, + -1.246622099070875940506391433635999693661E4L, + -2.673079795851665428695842853070996219632E4L, + -2.880269786660559337358397106518918220991E4L, + -1.450600228493968044773354186390390823713E4L, + -2.874539731125893533960680525192064277816E3L, + -1.402241261419067750237395034116942296027E2L, + /* 1.000000000000000000000000000000000000000E0 */ +}, + +/* + * Coefficients for approximation to erfc in [1/.35,107] + */ +/* erfc(1/x) = x exp (-1/x^2 - 0.5625 + rb(x^2)/sb(x^2)) + 1/6.6666259765625 < 1/x < 1/2.85711669921875 + Peak relative error 4.2e-22 */ +rb[] = { + -4.869587348270494309550558460786501252369E-5L, + -4.030199390527997378549161722412466959403E-3L, + -9.434425866377037610206443566288917589122E-2L, + -9.319032754357658601200655161585539404155E-1L, + -4.273788174307459947350256581445442062291E0L, + -8.842289940696150508373541814064198259278E0L, + -7.069215249419887403187988144752613025255E0L, + -1.401228723639514787920274427443330704764E0L, +}, +sb[] = { + 4.936254964107175160157544545879293019085E-3L, + 1.583457624037795744377163924895349412015E-1L, + 1.850647991850328356622940552450636420484E0L, + 9.927611557279019463768050710008450625415E0L, + 2.531667257649436709617165336779212114570E1L, + 2.869752886406743386458304052862814690045E1L, + 1.182059497870819562441683560749192539345E1L, + /* 1.000000000000000000000000000000000000000E0 */ +}, +/* erfc(1/x) = x exp (-1/x^2 - 0.5625 + rc(x^2)/sc(x^2)) + 1/107 <= 1/x <= 1/6.6666259765625 + Peak relative error 1.1e-21 */ +rc[] = { + -8.299617545269701963973537248996670806850E-5L, + -6.243845685115818513578933902532056244108E-3L, + -1.141667210620380223113693474478394397230E-1L, + -7.521343797212024245375240432734425789409E-1L, + -1.765321928311155824664963633786967602934E0L, + -1.029403473103215800456761180695263439188E0L, +}, +sc[] = { + 8.413244363014929493035952542677768808601E-3L, + 2.065114333816877479753334599639158060979E-1L, + 1.639064941530797583766364412782135680148E0L, + 4.936788463787115555582319302981666347450E0L, + 5.005177727208955487404729933261347679090E0L, + /* 1.000000000000000000000000000000000000000E0 */ +}; + +static long double erfc1(long double x) +{ + long double s,P,Q; + + s = fabsl(x) - 1; + P = pa[0] + s * (pa[1] + s * (pa[2] + + s * (pa[3] + s * (pa[4] + s * (pa[5] + s * (pa[6] + s * pa[7])))))); + Q = qa[0] + s * (qa[1] + s * (qa[2] + + s * (qa[3] + s * (qa[4] + s * (qa[5] + s * (qa[6] + s)))))); + return 1 - erx - P / Q; +} + +static long double erfc2(uint32_t ix, long double x) +{ + union ldshape u; + long double s,z,R,S; + + if (ix < 0x3fffa000) /* 0.84375 <= |x| < 1.25 */ + return erfc1(x); + + x = fabsl(x); + s = 1 / (x * x); + if (ix < 0x4000b6db) { /* 1.25 <= |x| < 2.857 ~ 1/.35 */ + R = ra[0] + s * (ra[1] + s * (ra[2] + s * (ra[3] + s * (ra[4] + + s * (ra[5] + s * (ra[6] + s * (ra[7] + s * ra[8]))))))); + S = sa[0] + s * (sa[1] + s * (sa[2] + s * (sa[3] + s * (sa[4] + + s * (sa[5] + s * (sa[6] + s * (sa[7] + s * (sa[8] + s)))))))); + } else if (ix < 0x4001d555) { /* 2.857 <= |x| < 6.6666259765625 */ + R = rb[0] + s * (rb[1] + s * (rb[2] + s * (rb[3] + s * (rb[4] + + s * (rb[5] + s * (rb[6] + s * rb[7])))))); + S = sb[0] + s * (sb[1] + s * (sb[2] + s * (sb[3] + s * (sb[4] + + s * (sb[5] + s * (sb[6] + s)))))); + } else { /* 6.666 <= |x| < 107 (erfc only) */ + R = rc[0] + s * (rc[1] + s * (rc[2] + s * (rc[3] + + s * (rc[4] + s * rc[5])))); + S = sc[0] + s * (sc[1] + s * (sc[2] + s * (sc[3] + + s * (sc[4] + s)))); + } + u.f = x; + u.i.m &= -1ULL << 40; + z = u.f; + return expl(-z*z - 0.5625) * expl((z - x) * (z + x) + R / S) / x; +} + +long double erfl(long double x) +{ + long double r, s, z, y; + union ldshape u = {x}; + uint32_t ix = (u.i.se & 0x7fffU)<<16 | u.i.m>>48; + int sign = u.i.se >> 15; + + if (ix >= 0x7fff0000) + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1 - 2*sign + 1/x; + if (ix < 0x3ffed800) { /* |x| < 0.84375 */ + if (ix < 0x3fde8000) { /* |x| < 2**-33 */ + return 0.125 * (8 * x + efx8 * x); /* avoid underflow */ + } + z = x * x; + r = pp[0] + z * (pp[1] + + z * (pp[2] + z * (pp[3] + z * (pp[4] + z * pp[5])))); + s = qq[0] + z * (qq[1] + + z * (qq[2] + z * (qq[3] + z * (qq[4] + z * (qq[5] + z))))); + y = r / s; + return x + x * y; + } + if (ix < 0x4001d555) /* |x| < 6.6666259765625 */ + y = 1 - erfc2(ix,x); + else + y = 1 - 0x1p-16382L; + return sign ? -y : y; +} + +long double erfcl(long double x) +{ + long double r, s, z, y; + union ldshape u = {x}; + uint32_t ix = (u.i.se & 0x7fffU)<<16 | u.i.m>>48; + int sign = u.i.se >> 15; + + if (ix >= 0x7fff0000) + /* erfc(nan) = nan, erfc(+-inf) = 0,2 */ + return 2*sign + 1/x; + if (ix < 0x3ffed800) { /* |x| < 0.84375 */ + if (ix < 0x3fbe0000) /* |x| < 2**-65 */ + return 1.0 - x; + z = x * x; + r = pp[0] + z * (pp[1] + + z * (pp[2] + z * (pp[3] + z * (pp[4] + z * pp[5])))); + s = qq[0] + z * (qq[1] + + z * (qq[2] + z * (qq[3] + z * (qq[4] + z * (qq[5] + z))))); + y = r / s; + if (ix < 0x3ffd8000) /* x < 1/4 */ + return 1.0 - (x + x * y); + return 0.5 - (x - 0.5 + x * y); + } + if (ix < 0x4005d600) /* |x| < 107 */ + return sign ? 2 - erfc2(ix,x) : erfc2(ix,x); + y = 0x1p-16382L; + return sign ? 2 - y : y*y; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double erfl(long double x) +{ + return erf(x); +} +long double erfcl(long double x) +{ + return erfc(x); +} +#endif diff --git a/src/libc-shim/src/exp.c b/src/orca-libc/src/math/exp.c similarity index 96% rename from src/libc-shim/src/exp.c rename to src/orca-libc/src/math/exp.c index 2d28a94f..b764d73c 100644 --- a/src/libc-shim/src/exp.c +++ b/src/orca-libc/src/math/exp.c @@ -57,9 +57,7 @@ static inline double specialcase(double_t tmp, uint64_t sbits, uint64_t ki) if (WANT_ROUNDING && y == 0.0) y = 0.0; /* The underflow exception needs to be signaled explicitly. */ - //WARN(orca): we don't have fp_barrier in wasm - //fp_force_eval(fp_barrier(0x1p-1022) * 0x1p-1022); - fp_force_eval((0x1p-1022) * 0x1p-1022); + fp_force_eval(fp_barrier(0x1p-1022) * 0x1p-1022); } y = 0x1p-1022 * y; return eval_as_double(y); diff --git a/src/orca-libc/src/math/exp10.c b/src/orca-libc/src/math/exp10.c new file mode 100644 index 00000000..26899eba --- /dev/null +++ b/src/orca-libc/src/math/exp10.c @@ -0,0 +1,24 @@ +#define _GNU_SOURCE +#include +#include + +double exp10(double x) +{ + static const double p10[] = { + 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, + 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, + 1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15 + }; + double n, y = modf(x, &n); + union {double f; uint64_t i;} u = {n}; + /* fabs(n) < 16 without raising invalid on nan */ + if ((u.i>>52 & 0x7ff) < 0x3ff+4) { + if (!y) return p10[(int)n+15]; + y = exp2(3.32192809488736234787031942948939 * y); + return y * p10[(int)n+15]; + } + return pow(10.0, x); +} + +weak_alias(exp10, pow10); diff --git a/src/orca-libc/src/math/exp10f.c b/src/orca-libc/src/math/exp10f.c new file mode 100644 index 00000000..d009f0a8 --- /dev/null +++ b/src/orca-libc/src/math/exp10f.c @@ -0,0 +1,22 @@ +#define _GNU_SOURCE +#include +#include + +float exp10f(float x) +{ + static const float p10[] = { + 1e-7f, 1e-6f, 1e-5f, 1e-4f, 1e-3f, 1e-2f, 1e-1f, + 1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7 + }; + float n, y = modff(x, &n); + union {float f; uint32_t i;} u = {n}; + /* fabsf(n) < 8 without raising invalid on nan */ + if ((u.i>>23 & 0xff) < 0x7f+3) { + if (!y) return p10[(int)n+7]; + y = exp2f(3.32192809488736234787031942948939f * y); + return y * p10[(int)n+7]; + } + return exp2(3.32192809488736234787031942948939 * x); +} + +weak_alias(exp10f, pow10f); diff --git a/src/orca-libc/src/math/exp10l.c b/src/orca-libc/src/math/exp10l.c new file mode 100644 index 00000000..f3da1a08 --- /dev/null +++ b/src/orca-libc/src/math/exp10l.c @@ -0,0 +1,32 @@ +#define _GNU_SOURCE +#include +#include +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double exp10l(long double x) +{ + return exp10(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double exp10l(long double x) +{ + static const long double p10[] = { + 1e-15L, 1e-14L, 1e-13L, 1e-12L, 1e-11L, 1e-10L, + 1e-9L, 1e-8L, 1e-7L, 1e-6L, 1e-5L, 1e-4L, 1e-3L, 1e-2L, 1e-1L, + 1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15 + }; + long double n, y = modfl(x, &n); + union ldshape u = {n}; + /* fabsl(n) < 16 without raising invalid on nan */ + if ((u.i.se & 0x7fff) < 0x3fff+4) { + if (!y) return p10[(int)n+15]; + y = exp2l(3.32192809488736234787031942948939L * y); + return y * p10[(int)n+15]; + } + return powl(10.0, x); +} +#endif + +weak_alias(exp10l, pow10l); diff --git a/src/orca-libc/src/math/exp2.c b/src/orca-libc/src/math/exp2.c new file mode 100644 index 00000000..e0ff54bd --- /dev/null +++ b/src/orca-libc/src/math/exp2.c @@ -0,0 +1,121 @@ +/* + * Double-precision 2^x function. + * + * Copyright (c) 2018, Arm Limited. + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include "libm.h" +#include "exp_data.h" + +#define N (1 << EXP_TABLE_BITS) +#define Shift __exp_data.exp2_shift +#define T __exp_data.tab +#define C1 __exp_data.exp2_poly[0] +#define C2 __exp_data.exp2_poly[1] +#define C3 __exp_data.exp2_poly[2] +#define C4 __exp_data.exp2_poly[3] +#define C5 __exp_data.exp2_poly[4] + +/* Handle cases that may overflow or underflow when computing the result that + is scale*(1+TMP) without intermediate rounding. The bit representation of + scale is in SBITS, however it has a computed exponent that may have + overflown into the sign bit so that needs to be adjusted before using it as + a double. (int32_t)KI is the k used in the argument reduction and exponent + adjustment of scale, positive k here means the result may overflow and + negative k means the result may underflow. */ +static inline double specialcase(double_t tmp, uint64_t sbits, uint64_t ki) +{ + double_t scale, y; + + if ((ki & 0x80000000) == 0) { + /* k > 0, the exponent of scale might have overflowed by 1. */ + sbits -= 1ull << 52; + scale = asdouble(sbits); + y = 2 * (scale + scale * tmp); + return eval_as_double(y); + } + /* k < 0, need special care in the subnormal range. */ + sbits += 1022ull << 52; + scale = asdouble(sbits); + y = scale + scale * tmp; + if (y < 1.0) { + /* Round y to the right precision before scaling it into the subnormal + range to avoid double rounding that can cause 0.5+E/2 ulp error where + E is the worst-case ulp error outside the subnormal range. So this + is only useful if the goal is better than 1 ulp worst-case error. */ + double_t hi, lo; + lo = scale - y + scale * tmp; + hi = 1.0 + y; + lo = 1.0 - hi + y + lo; + y = eval_as_double(hi + lo) - 1.0; + /* Avoid -0.0 with downward rounding. */ + if (WANT_ROUNDING && y == 0.0) + y = 0.0; + /* The underflow exception needs to be signaled explicitly. */ + fp_force_eval(fp_barrier(0x1p-1022) * 0x1p-1022); + } + y = 0x1p-1022 * y; + return eval_as_double(y); +} + +/* Top 12 bits of a double (sign and exponent bits). */ +static inline uint32_t top12(double x) +{ + return asuint64(x) >> 52; +} + +double exp2(double x) +{ + uint32_t abstop; + uint64_t ki, idx, top, sbits; + double_t kd, r, r2, scale, tail, tmp; + + abstop = top12(x) & 0x7ff; + if (predict_false(abstop - top12(0x1p-54) >= top12(512.0) - top12(0x1p-54))) { + if (abstop - top12(0x1p-54) >= 0x80000000) + /* Avoid spurious underflow for tiny x. */ + /* Note: 0 is common input. */ + return WANT_ROUNDING ? 1.0 + x : 1.0; + if (abstop >= top12(1024.0)) { + if (asuint64(x) == asuint64(-INFINITY)) + return 0.0; + if (abstop >= top12(INFINITY)) + return 1.0 + x; + if (!(asuint64(x) >> 63)) + return __math_oflow(0); + else if (asuint64(x) >= asuint64(-1075.0)) + return __math_uflow(0); + } + if (2 * asuint64(x) > 2 * asuint64(928.0)) + /* Large x is special cased below. */ + abstop = 0; + } + + /* exp2(x) = 2^(k/N) * 2^r, with 2^r in [2^(-1/2N),2^(1/2N)]. */ + /* x = k/N + r, with int k and r in [-1/2N, 1/2N]. */ + kd = eval_as_double(x + Shift); + ki = asuint64(kd); /* k. */ + kd -= Shift; /* k/N for int k. */ + r = x - kd; + /* 2^(k/N) ~= scale * (1 + tail). */ + idx = 2 * (ki % N); + top = ki << (52 - EXP_TABLE_BITS); + tail = asdouble(T[idx]); + /* This is only a valid scale when -1023*N < k < 1024*N. */ + sbits = T[idx + 1] + top; + /* exp2(x) = 2^(k/N) * 2^r ~= scale + scale * (tail + 2^r - 1). */ + /* Evaluation is optimized assuming superscalar pipelined execution. */ + r2 = r * r; + /* Without fma the worst case error is 0.5/N ulp larger. */ + /* Worst case error is less than 0.5+0.86/N+(abs poly error * 2^53) ulp. */ + tmp = tail + r * C1 + r2 * (C2 + r * C3) + r2 * r2 * (C4 + r * C5); + if (predict_false(abstop == 0)) + return specialcase(tmp, sbits, ki); + scale = asdouble(sbits); + /* Note: tmp == 0 or |tmp| > 2^-65 and scale > 2^-928, so there + is no spurious underflow here even without fma. */ + return eval_as_double(scale + scale * tmp); +} diff --git a/src/orca-libc/src/math/exp2f.c b/src/orca-libc/src/math/exp2f.c new file mode 100644 index 00000000..0360482c --- /dev/null +++ b/src/orca-libc/src/math/exp2f.c @@ -0,0 +1,69 @@ +/* + * Single-precision 2^x function. + * + * Copyright (c) 2017-2018, Arm Limited. + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include "libm.h" +#include "exp2f_data.h" + +/* +EXP2F_TABLE_BITS = 5 +EXP2F_POLY_ORDER = 3 + +ULP error: 0.502 (nearest rounding.) +Relative error: 1.69 * 2^-34 in [-1/64, 1/64] (before rounding.) +Wrong count: 168353 (all nearest rounding wrong results with fma.) +Non-nearest ULP error: 1 (rounded ULP error) +*/ + +#define N (1 << EXP2F_TABLE_BITS) +#define T __exp2f_data.tab +#define C __exp2f_data.poly +#define SHIFT __exp2f_data.shift_scaled + +static inline uint32_t top12(float x) +{ + return asuint(x) >> 20; +} + +float exp2f(float x) +{ + uint32_t abstop; + uint64_t ki, t; + double_t kd, xd, z, r, r2, y, s; + + xd = (double_t)x; + abstop = top12(x) & 0x7ff; + if (predict_false(abstop >= top12(128.0f))) { + /* |x| >= 128 or x is nan. */ + if (asuint(x) == asuint(-INFINITY)) + return 0.0f; + if (abstop >= top12(INFINITY)) + return x + x; + if (x > 0.0f) + return __math_oflowf(0); + if (x <= -150.0f) + return __math_uflowf(0); + } + + /* x = k/N + r with r in [-1/(2N), 1/(2N)] and int k. */ + kd = eval_as_double(xd + SHIFT); + ki = asuint64(kd); + kd -= SHIFT; /* k/N for int k. */ + r = xd - kd; + + /* exp2(x) = 2^(k/N) * 2^r ~= s * (C0*r^3 + C1*r^2 + C2*r + 1) */ + t = T[ki % N]; + t += ki << (52 - EXP2F_TABLE_BITS); + s = asdouble(t); + z = C[0] * r + C[1]; + r2 = r * r; + y = C[2] * r + 1; + y = z * r2 + y; + y = y * s; + return eval_as_float(y); +} diff --git a/src/libc-shim/src/exp2f_data.c b/src/orca-libc/src/math/exp2f_data.c similarity index 100% rename from src/libc-shim/src/exp2f_data.c rename to src/orca-libc/src/math/exp2f_data.c diff --git a/src/libc-shim/src/exp2f_data.h b/src/orca-libc/src/math/exp2f_data.h similarity index 91% rename from src/libc-shim/src/exp2f_data.h rename to src/orca-libc/src/math/exp2f_data.h index af78348b..fe744f15 100644 --- a/src/libc-shim/src/exp2f_data.h +++ b/src/orca-libc/src/math/exp2f_data.h @@ -11,7 +11,7 @@ /* Shared between expf, exp2f and powf. */ #define EXP2F_TABLE_BITS 5 #define EXP2F_POLY_ORDER 3 -extern const struct exp2f_data { +extern hidden const struct exp2f_data { uint64_t tab[1 << EXP2F_TABLE_BITS]; double shift_scaled; double poly[EXP2F_POLY_ORDER]; diff --git a/src/orca-libc/src/math/exp2l.c b/src/orca-libc/src/math/exp2l.c new file mode 100644 index 00000000..3565c1e6 --- /dev/null +++ b/src/orca-libc/src/math/exp2l.c @@ -0,0 +1,619 @@ +/* origin: FreeBSD /usr/src/lib/msun/ld80/s_exp2l.c and /usr/src/lib/msun/ld128/s_exp2l.c */ +/*- + * Copyright (c) 2005-2008 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double exp2l(long double x) +{ + return exp2(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +#define TBLBITS 7 +#define TBLSIZE (1 << TBLBITS) + +static const double +redux = 0x1.8p63 / TBLSIZE, +P1 = 0x1.62e42fefa39efp-1, +P2 = 0x1.ebfbdff82c58fp-3, +P3 = 0x1.c6b08d7049fap-5, +P4 = 0x1.3b2ab6fba4da5p-7, +P5 = 0x1.5d8804780a736p-10, +P6 = 0x1.430918835e33dp-13; + +static const double tbl[TBLSIZE * 2] = { + 0x1.6a09e667f3bcdp-1, -0x1.bdd3413b2648p-55, + 0x1.6c012750bdabfp-1, -0x1.2895667ff0cp-57, + 0x1.6dfb23c651a2fp-1, -0x1.bbe3a683c88p-58, + 0x1.6ff7df9519484p-1, -0x1.83c0f25860fp-56, + 0x1.71f75e8ec5f74p-1, -0x1.16e4786887bp-56, + 0x1.73f9a48a58174p-1, -0x1.0a8d96c65d5p-55, + 0x1.75feb564267c9p-1, -0x1.0245957316ep-55, + 0x1.780694fde5d3fp-1, 0x1.866b80a0216p-55, + 0x1.7a11473eb0187p-1, -0x1.41577ee0499p-56, + 0x1.7c1ed0130c132p-1, 0x1.f124cd1164ep-55, + 0x1.7e2f336cf4e62p-1, 0x1.05d02ba157ap-57, + 0x1.80427543e1a12p-1, -0x1.27c86626d97p-55, + 0x1.82589994cce13p-1, -0x1.d4c1dd41533p-55, + 0x1.8471a4623c7adp-1, -0x1.8d684a341cep-56, + 0x1.868d99b4492edp-1, -0x1.fc6f89bd4f68p-55, + 0x1.88ac7d98a6699p-1, 0x1.994c2f37cb5p-55, + 0x1.8ace5422aa0dbp-1, 0x1.6e9f156864bp-55, + 0x1.8cf3216b5448cp-1, -0x1.0d55e32e9e4p-57, + 0x1.8f1ae99157736p-1, 0x1.5cc13a2e397p-56, + 0x1.9145b0b91ffc6p-1, -0x1.dd6792e5825p-55, + 0x1.93737b0cdc5e5p-1, -0x1.75fc781b58p-58, + 0x1.95a44cbc8520fp-1, -0x1.64b7c96a5fp-57, + 0x1.97d829fde4e5p-1, -0x1.d185b7c1b86p-55, + 0x1.9a0f170ca07bap-1, -0x1.173bd91cee6p-55, + 0x1.9c49182a3f09p-1, 0x1.c7c46b071f2p-57, + 0x1.9e86319e32323p-1, 0x1.824ca78e64cp-57, + 0x1.a0c667b5de565p-1, -0x1.359495d1cd5p-55, + 0x1.a309bec4a2d33p-1, 0x1.6305c7ddc368p-55, + 0x1.a5503b23e255dp-1, -0x1.d2f6edb8d42p-55, + 0x1.a799e1330b358p-1, 0x1.bcb7ecac564p-55, + 0x1.a9e6b5579fdbfp-1, 0x1.0fac90ef7fdp-55, + 0x1.ac36bbfd3f37ap-1, -0x1.f9234cae76dp-56, + 0x1.ae89f995ad3adp-1, 0x1.7a1cd345dcc8p-55, + 0x1.b0e07298db666p-1, -0x1.bdef54c80e4p-55, + 0x1.b33a2b84f15fbp-1, -0x1.2805e3084d8p-58, + 0x1.b59728de5593ap-1, -0x1.c71dfbbba6ep-55, + 0x1.b7f76f2fb5e47p-1, -0x1.5584f7e54acp-57, + 0x1.ba5b030a1064ap-1, -0x1.efcd30e5429p-55, + 0x1.bcc1e904bc1d2p-1, 0x1.23dd07a2d9fp-56, + 0x1.bf2c25bd71e09p-1, -0x1.efdca3f6b9c8p-55, + 0x1.c199bdd85529cp-1, 0x1.11065895049p-56, + 0x1.c40ab5fffd07ap-1, 0x1.b4537e083c6p-55, + 0x1.c67f12e57d14bp-1, 0x1.2884dff483c8p-55, + 0x1.c8f6d9406e7b5p-1, 0x1.1acbc48805cp-57, + 0x1.cb720dcef9069p-1, 0x1.503cbd1e94ap-57, + 0x1.cdf0b555dc3fap-1, -0x1.dd83b53829dp-56, + 0x1.d072d4a07897cp-1, -0x1.cbc3743797a8p-55, + 0x1.d2f87080d89f2p-1, -0x1.d487b719d858p-55, + 0x1.d5818dcfba487p-1, 0x1.2ed02d75b37p-56, + 0x1.d80e316c98398p-1, -0x1.11ec18bedep-55, + 0x1.da9e603db3285p-1, 0x1.c2300696db5p-55, + 0x1.dd321f301b46p-1, 0x1.2da5778f019p-55, + 0x1.dfc97337b9b5fp-1, -0x1.1a5cd4f184b8p-55, + 0x1.e264614f5a129p-1, -0x1.7b627817a148p-55, + 0x1.e502ee78b3ff6p-1, 0x1.39e8980a9cdp-56, + 0x1.e7a51fbc74c83p-1, 0x1.2d522ca0c8ep-55, + 0x1.ea4afa2a490dap-1, -0x1.e9c23179c288p-55, + 0x1.ecf482d8e67f1p-1, -0x1.c93f3b411ad8p-55, + 0x1.efa1bee615a27p-1, 0x1.dc7f486a4b68p-55, + 0x1.f252b376bba97p-1, 0x1.3a1a5bf0d8e8p-55, + 0x1.f50765b6e454p-1, 0x1.9d3e12dd8a18p-55, + 0x1.f7bfdad9cbe14p-1, -0x1.dbb12d00635p-55, + 0x1.fa7c1819e90d8p-1, 0x1.74853f3a593p-56, + 0x1.fd3c22b8f71f1p-1, 0x1.2eb74966578p-58, + 0x1p+0, 0x0p+0, + 0x1.0163da9fb3335p+0, 0x1.b61299ab8cd8p-54, + 0x1.02c9a3e778061p+0, -0x1.19083535b08p-56, + 0x1.04315e86e7f85p+0, -0x1.0a31c1977c98p-54, + 0x1.059b0d3158574p+0, 0x1.d73e2a475b4p-55, + 0x1.0706b29ddf6dep+0, -0x1.c91dfe2b13cp-55, + 0x1.0874518759bc8p+0, 0x1.186be4bb284p-57, + 0x1.09e3ecac6f383p+0, 0x1.14878183161p-54, + 0x1.0b5586cf9890fp+0, 0x1.8a62e4adc61p-54, + 0x1.0cc922b7247f7p+0, 0x1.01edc16e24f8p-54, + 0x1.0e3ec32d3d1a2p+0, 0x1.03a1727c58p-59, + 0x1.0fb66affed31bp+0, -0x1.b9bedc44ebcp-57, + 0x1.11301d0125b51p+0, -0x1.6c51039449bp-54, + 0x1.12abdc06c31ccp+0, -0x1.1b514b36ca8p-58, + 0x1.1429aaea92dep+0, -0x1.32fbf9af1368p-54, + 0x1.15a98c8a58e51p+0, 0x1.2406ab9eeabp-55, + 0x1.172b83c7d517bp+0, -0x1.19041b9d78ap-55, + 0x1.18af9388c8deap+0, -0x1.11023d1970f8p-54, + 0x1.1a35beb6fcb75p+0, 0x1.e5b4c7b4969p-55, + 0x1.1bbe084045cd4p+0, -0x1.95386352ef6p-54, + 0x1.1d4873168b9aap+0, 0x1.e016e00a264p-54, + 0x1.1ed5022fcd91dp+0, -0x1.1df98027bb78p-54, + 0x1.2063b88628cd6p+0, 0x1.dc775814a85p-55, + 0x1.21f49917ddc96p+0, 0x1.2a97e9494a6p-55, + 0x1.2387a6e756238p+0, 0x1.9b07eb6c7058p-54, + 0x1.251ce4fb2a63fp+0, 0x1.ac155bef4f5p-55, + 0x1.26b4565e27cddp+0, 0x1.2bd339940eap-55, + 0x1.284dfe1f56381p+0, -0x1.a4c3a8c3f0d8p-54, + 0x1.29e9df51fdee1p+0, 0x1.612e8afad12p-55, + 0x1.2b87fd0dad99p+0, -0x1.10adcd6382p-59, + 0x1.2d285a6e4030bp+0, 0x1.0024754db42p-54, + 0x1.2ecafa93e2f56p+0, 0x1.1ca0f45d524p-56, + 0x1.306fe0a31b715p+0, 0x1.6f46ad23183p-55, + 0x1.32170fc4cd831p+0, 0x1.a9ce78e1804p-55, + 0x1.33c08b26416ffp+0, 0x1.327218436598p-54, + 0x1.356c55f929ff1p+0, -0x1.b5cee5c4e46p-55, + 0x1.371a7373aa9cbp+0, -0x1.63aeabf42ebp-54, + 0x1.38cae6d05d866p+0, -0x1.e958d3c99048p-54, + 0x1.3a7db34e59ff7p+0, -0x1.5e436d661f6p-56, + 0x1.3c32dc313a8e5p+0, -0x1.efff8375d2ap-54, + 0x1.3dea64c123422p+0, 0x1.ada0911f09fp-55, + 0x1.3fa4504ac801cp+0, -0x1.7d023f956fap-54, + 0x1.4160a21f72e2ap+0, -0x1.ef3691c309p-58, + 0x1.431f5d950a897p+0, -0x1.1c7dde35f7ap-55, + 0x1.44e086061892dp+0, 0x1.89b7a04ef8p-59, + 0x1.46a41ed1d0057p+0, 0x1.c944bd1648a8p-54, + 0x1.486a2b5c13cdp+0, 0x1.3c1a3b69062p-56, + 0x1.4a32af0d7d3dep+0, 0x1.9cb62f3d1be8p-54, + 0x1.4bfdad5362a27p+0, 0x1.d4397afec42p-56, + 0x1.4dcb299fddd0dp+0, 0x1.8ecdbbc6a78p-54, + 0x1.4f9b2769d2ca7p+0, -0x1.4b309d25958p-54, + 0x1.516daa2cf6642p+0, -0x1.f768569bd94p-55, + 0x1.5342b569d4f82p+0, -0x1.07abe1db13dp-55, + 0x1.551a4ca5d920fp+0, -0x1.d689cefede6p-55, + 0x1.56f4736b527dap+0, 0x1.9bb2c011d938p-54, + 0x1.58d12d497c7fdp+0, 0x1.295e15b9a1ep-55, + 0x1.5ab07dd485429p+0, 0x1.6324c0546478p-54, + 0x1.5c9268a5946b7p+0, 0x1.c4b1b81698p-60, + 0x1.5e76f15ad2148p+0, 0x1.ba6f93080e68p-54, + 0x1.605e1b976dc09p+0, -0x1.3e2429b56de8p-54, + 0x1.6247eb03a5585p+0, -0x1.383c17e40b48p-54, + 0x1.6434634ccc32p+0, -0x1.c483c759d89p-55, + 0x1.6623882552225p+0, -0x1.bb60987591cp-54, + 0x1.68155d44ca973p+0, 0x1.038ae44f74p-57, +}; + +/* + * exp2l(x): compute the base 2 exponential of x + * + * Accuracy: Peak error < 0.511 ulp. + * + * Method: (equally-spaced tables) + * + * Reduce x: + * x = 2**k + y, for integer k and |y| <= 1/2. + * Thus we have exp2l(x) = 2**k * exp2(y). + * + * Reduce y: + * y = i/TBLSIZE + z for integer i near y * TBLSIZE. + * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z), + * with |z| <= 2**-(TBLBITS+1). + * + * We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a + * degree-6 minimax polynomial with maximum error under 2**-69. + * The table entries each have 104 bits of accuracy, encoded as + * a pair of double precision values. + */ +long double exp2l(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + long double r, z; + uint32_t i0; + union {uint32_t u; int32_t i;} k; + + /* Filter out exceptional cases. */ + if (e >= 0x3fff + 13) { /* |x| >= 8192 or x is NaN */ + if (u.i.se >= 0x3fff + 14 && u.i.se >> 15 == 0) + /* overflow */ + return x * 0x1p16383L; + if (e == 0x7fff) /* -inf or -nan */ + return -1/x; + if (x < -16382) { + if (x <= -16446 || x - 0x1p63 + 0x1p63 != x) + /* underflow */ + FORCE_EVAL((float)(-0x1p-149/x)); + if (x <= -16446) + return 0; + } + } else if (e < 0x3fff - 64) { + return 1 + x; + } + + /* + * Reduce x, computing z, i0, and k. The low bits of x + redux + * contain the 16-bit integer part of the exponent (k) followed by + * TBLBITS fractional bits (i0). We use bit tricks to extract these + * as integers, then set z to the remainder. + * + * Example: Suppose x is 0xabc.123456p0 and TBLBITS is 8. + * Then the low-order word of x + redux is 0x000abc12, + * We split this into k = 0xabc and i0 = 0x12 (adjusted to + * index into the table), then we compute z = 0x0.003456p0. + */ + u.f = x + redux; + i0 = u.i.m + TBLSIZE / 2; + k.u = i0 / TBLSIZE * TBLSIZE; + k.i /= TBLSIZE; + i0 %= TBLSIZE; + u.f -= redux; + z = x - u.f; + + /* Compute r = exp2l(y) = exp2lt[i0] * p(z). */ + long double t_hi = tbl[2*i0]; + long double t_lo = tbl[2*i0 + 1]; + /* XXX This gives > 1 ulp errors outside of FE_TONEAREST mode */ + r = t_lo + (t_hi + t_lo) * z * (P1 + z * (P2 + z * (P3 + z * (P4 + + z * (P5 + z * P6))))) + t_hi; + + return scalbnl(r, k.i); +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +#define TBLBITS 7 +#define TBLSIZE (1 << TBLBITS) + +static const long double + P1 = 0x1.62e42fefa39ef35793c7673007e6p-1L, + P2 = 0x1.ebfbdff82c58ea86f16b06ec9736p-3L, + P3 = 0x1.c6b08d704a0bf8b33a762bad3459p-5L, + P4 = 0x1.3b2ab6fba4e7729ccbbe0b4f3fc2p-7L, + P5 = 0x1.5d87fe78a67311071dee13fd11d9p-10L, + P6 = 0x1.430912f86c7876f4b663b23c5fe5p-13L; + +static const double + P7 = 0x1.ffcbfc588b041p-17, + P8 = 0x1.62c0223a5c7c7p-20, + P9 = 0x1.b52541ff59713p-24, + P10 = 0x1.e4cf56a391e22p-28, + redux = 0x1.8p112 / TBLSIZE; + +static const long double tbl[TBLSIZE] = { + 0x1.6a09e667f3bcc908b2fb1366dfeap-1L, + 0x1.6c012750bdabeed76a99800f4edep-1L, + 0x1.6dfb23c651a2ef220e2cbe1bc0d4p-1L, + 0x1.6ff7df9519483cf87e1b4f3e1e98p-1L, + 0x1.71f75e8ec5f73dd2370f2ef0b148p-1L, + 0x1.73f9a48a58173bd5c9a4e68ab074p-1L, + 0x1.75feb564267c8bf6e9aa33a489a8p-1L, + 0x1.780694fde5d3f619ae02808592a4p-1L, + 0x1.7a11473eb0186d7d51023f6ccb1ap-1L, + 0x1.7c1ed0130c1327c49334459378dep-1L, + 0x1.7e2f336cf4e62105d02ba1579756p-1L, + 0x1.80427543e1a11b60de67649a3842p-1L, + 0x1.82589994cce128acf88afab34928p-1L, + 0x1.8471a4623c7acce52f6b97c6444cp-1L, + 0x1.868d99b4492ec80e41d90ac2556ap-1L, + 0x1.88ac7d98a669966530bcdf2d4cc0p-1L, + 0x1.8ace5422aa0db5ba7c55a192c648p-1L, + 0x1.8cf3216b5448bef2aa1cd161c57ap-1L, + 0x1.8f1ae991577362b982745c72eddap-1L, + 0x1.9145b0b91ffc588a61b469f6b6a0p-1L, + 0x1.93737b0cdc5e4f4501c3f2540ae8p-1L, + 0x1.95a44cbc8520ee9b483695a0e7fep-1L, + 0x1.97d829fde4e4f8b9e920f91e8eb6p-1L, + 0x1.9a0f170ca07b9ba3109b8c467844p-1L, + 0x1.9c49182a3f0901c7c46b071f28dep-1L, + 0x1.9e86319e323231824ca78e64c462p-1L, + 0x1.a0c667b5de564b29ada8b8cabbacp-1L, + 0x1.a309bec4a2d3358c171f770db1f4p-1L, + 0x1.a5503b23e255c8b424491caf88ccp-1L, + 0x1.a799e1330b3586f2dfb2b158f31ep-1L, + 0x1.a9e6b5579fdbf43eb243bdff53a2p-1L, + 0x1.ac36bbfd3f379c0db966a3126988p-1L, + 0x1.ae89f995ad3ad5e8734d17731c80p-1L, + 0x1.b0e07298db66590842acdfc6fb4ep-1L, + 0x1.b33a2b84f15faf6bfd0e7bd941b0p-1L, + 0x1.b59728de559398e3881111648738p-1L, + 0x1.b7f76f2fb5e46eaa7b081ab53ff6p-1L, + 0x1.ba5b030a10649840cb3c6af5b74cp-1L, + 0x1.bcc1e904bc1d2247ba0f45b3d06cp-1L, + 0x1.bf2c25bd71e088408d7025190cd0p-1L, + 0x1.c199bdd85529c2220cb12a0916bap-1L, + 0x1.c40ab5fffd07a6d14df820f17deap-1L, + 0x1.c67f12e57d14b4a2137fd20f2a26p-1L, + 0x1.c8f6d9406e7b511acbc48805c3f6p-1L, + 0x1.cb720dcef90691503cbd1e949d0ap-1L, + 0x1.cdf0b555dc3f9c44f8958fac4f12p-1L, + 0x1.d072d4a07897b8d0f22f21a13792p-1L, + 0x1.d2f87080d89f18ade123989ea50ep-1L, + 0x1.d5818dcfba48725da05aeb66dff8p-1L, + 0x1.d80e316c98397bb84f9d048807a0p-1L, + 0x1.da9e603db3285708c01a5b6d480cp-1L, + 0x1.dd321f301b4604b695de3c0630c0p-1L, + 0x1.dfc97337b9b5eb968cac39ed284cp-1L, + 0x1.e264614f5a128a12761fa17adc74p-1L, + 0x1.e502ee78b3ff6273d130153992d0p-1L, + 0x1.e7a51fbc74c834b548b2832378a4p-1L, + 0x1.ea4afa2a490d9858f73a18f5dab4p-1L, + 0x1.ecf482d8e67f08db0312fb949d50p-1L, + 0x1.efa1bee615a27771fd21a92dabb6p-1L, + 0x1.f252b376bba974e8696fc3638f24p-1L, + 0x1.f50765b6e4540674f84b762861a6p-1L, + 0x1.f7bfdad9cbe138913b4bfe72bd78p-1L, + 0x1.fa7c1819e90d82e90a7e74b26360p-1L, + 0x1.fd3c22b8f71f10975ba4b32bd006p-1L, + 0x1.0000000000000000000000000000p+0L, + 0x1.0163da9fb33356d84a66ae336e98p+0L, + 0x1.02c9a3e778060ee6f7caca4f7a18p+0L, + 0x1.04315e86e7f84bd738f9a20da442p+0L, + 0x1.059b0d31585743ae7c548eb68c6ap+0L, + 0x1.0706b29ddf6ddc6dc403a9d87b1ep+0L, + 0x1.0874518759bc808c35f25d942856p+0L, + 0x1.09e3ecac6f3834521e060c584d5cp+0L, + 0x1.0b5586cf9890f6298b92b7184200p+0L, + 0x1.0cc922b7247f7407b705b893dbdep+0L, + 0x1.0e3ec32d3d1a2020742e4f8af794p+0L, + 0x1.0fb66affed31af232091dd8a169ep+0L, + 0x1.11301d0125b50a4ebbf1aed9321cp+0L, + 0x1.12abdc06c31cbfb92bad324d6f84p+0L, + 0x1.1429aaea92ddfb34101943b2588ep+0L, + 0x1.15a98c8a58e512480d573dd562aep+0L, + 0x1.172b83c7d517adcdf7c8c50eb162p+0L, + 0x1.18af9388c8de9bbbf70b9a3c269cp+0L, + 0x1.1a35beb6fcb753cb698f692d2038p+0L, + 0x1.1bbe084045cd39ab1e72b442810ep+0L, + 0x1.1d4873168b9aa7805b8028990be8p+0L, + 0x1.1ed5022fcd91cb8819ff61121fbep+0L, + 0x1.2063b88628cd63b8eeb0295093f6p+0L, + 0x1.21f49917ddc962552fd29294bc20p+0L, + 0x1.2387a6e75623866c1fadb1c159c0p+0L, + 0x1.251ce4fb2a63f3582ab7de9e9562p+0L, + 0x1.26b4565e27cdd257a673281d3068p+0L, + 0x1.284dfe1f5638096cf15cf03c9fa0p+0L, + 0x1.29e9df51fdee12c25d15f5a25022p+0L, + 0x1.2b87fd0dad98ffddea46538fca24p+0L, + 0x1.2d285a6e4030b40091d536d0733ep+0L, + 0x1.2ecafa93e2f5611ca0f45d5239a4p+0L, + 0x1.306fe0a31b7152de8d5a463063bep+0L, + 0x1.32170fc4cd8313539cf1c3009330p+0L, + 0x1.33c08b26416ff4c9c8610d96680ep+0L, + 0x1.356c55f929ff0c94623476373be4p+0L, + 0x1.371a7373aa9caa7145502f45452ap+0L, + 0x1.38cae6d05d86585a9cb0d9bed530p+0L, + 0x1.3a7db34e59ff6ea1bc9299e0a1fep+0L, + 0x1.3c32dc313a8e484001f228b58cf0p+0L, + 0x1.3dea64c12342235b41223e13d7eep+0L, + 0x1.3fa4504ac801ba0bf701aa417b9cp+0L, + 0x1.4160a21f72e29f84325b8f3dbacap+0L, + 0x1.431f5d950a896dc704439410b628p+0L, + 0x1.44e086061892d03136f409df0724p+0L, + 0x1.46a41ed1d005772512f459229f0ap+0L, + 0x1.486a2b5c13cd013c1a3b69062f26p+0L, + 0x1.4a32af0d7d3de672d8bcf46f99b4p+0L, + 0x1.4bfdad5362a271d4397afec42e36p+0L, + 0x1.4dcb299fddd0d63b36ef1a9e19dep+0L, + 0x1.4f9b2769d2ca6ad33d8b69aa0b8cp+0L, + 0x1.516daa2cf6641c112f52c84d6066p+0L, + 0x1.5342b569d4f81df0a83c49d86bf4p+0L, + 0x1.551a4ca5d920ec52ec620243540cp+0L, + 0x1.56f4736b527da66ecb004764e61ep+0L, + 0x1.58d12d497c7fd252bc2b7343d554p+0L, + 0x1.5ab07dd48542958c93015191e9a8p+0L, + 0x1.5c9268a5946b701c4b1b81697ed4p+0L, + 0x1.5e76f15ad21486e9be4c20399d12p+0L, + 0x1.605e1b976dc08b076f592a487066p+0L, + 0x1.6247eb03a5584b1f0fa06fd2d9eap+0L, + 0x1.6434634ccc31fc76f8714c4ee122p+0L, + 0x1.66238825522249127d9e29b92ea2p+0L, + 0x1.68155d44ca973081c57227b9f69ep+0L, +}; + +static const float eps[TBLSIZE] = { + -0x1.5c50p-101, + -0x1.5d00p-106, + 0x1.8e90p-102, + -0x1.5340p-103, + 0x1.1bd0p-102, + -0x1.4600p-105, + -0x1.7a40p-104, + 0x1.d590p-102, + -0x1.d590p-101, + 0x1.b100p-103, + -0x1.0d80p-105, + 0x1.6b00p-103, + -0x1.9f00p-105, + 0x1.c400p-103, + 0x1.e120p-103, + -0x1.c100p-104, + -0x1.9d20p-103, + 0x1.a800p-108, + 0x1.4c00p-106, + -0x1.9500p-106, + 0x1.6900p-105, + -0x1.29d0p-100, + 0x1.4c60p-103, + 0x1.13a0p-102, + -0x1.5b60p-103, + -0x1.1c40p-103, + 0x1.db80p-102, + 0x1.91a0p-102, + 0x1.dc00p-105, + 0x1.44c0p-104, + 0x1.9710p-102, + 0x1.8760p-103, + -0x1.a720p-103, + 0x1.ed20p-103, + -0x1.49c0p-102, + -0x1.e000p-111, + 0x1.86a0p-103, + 0x1.2b40p-103, + -0x1.b400p-108, + 0x1.1280p-99, + -0x1.02d8p-102, + -0x1.e3d0p-103, + -0x1.b080p-105, + -0x1.f100p-107, + -0x1.16c0p-105, + -0x1.1190p-103, + -0x1.a7d2p-100, + 0x1.3450p-103, + -0x1.67c0p-105, + 0x1.4b80p-104, + -0x1.c4e0p-103, + 0x1.6000p-108, + -0x1.3f60p-105, + 0x1.93f0p-104, + 0x1.5fe0p-105, + 0x1.6f80p-107, + -0x1.7600p-106, + 0x1.21e0p-106, + -0x1.3a40p-106, + -0x1.40c0p-104, + -0x1.9860p-105, + -0x1.5d40p-108, + -0x1.1d70p-106, + 0x1.2760p-105, + 0x0.0000p+0, + 0x1.21e2p-104, + -0x1.9520p-108, + -0x1.5720p-106, + -0x1.4810p-106, + -0x1.be00p-109, + 0x1.0080p-105, + -0x1.5780p-108, + -0x1.d460p-105, + -0x1.6140p-105, + 0x1.4630p-104, + 0x1.ad50p-103, + 0x1.82e0p-105, + 0x1.1d3cp-101, + 0x1.6100p-107, + 0x1.ec30p-104, + 0x1.f200p-108, + 0x1.0b40p-103, + 0x1.3660p-102, + 0x1.d9d0p-103, + -0x1.02d0p-102, + 0x1.b070p-103, + 0x1.b9c0p-104, + -0x1.01c0p-103, + -0x1.dfe0p-103, + 0x1.1b60p-104, + -0x1.ae94p-101, + -0x1.3340p-104, + 0x1.b3d8p-102, + -0x1.6e40p-105, + -0x1.3670p-103, + 0x1.c140p-104, + 0x1.1840p-101, + 0x1.1ab0p-102, + -0x1.a400p-104, + 0x1.1f00p-104, + -0x1.7180p-103, + 0x1.4ce0p-102, + 0x1.9200p-107, + -0x1.54c0p-103, + 0x1.1b80p-105, + -0x1.1828p-101, + 0x1.5720p-102, + -0x1.a060p-100, + 0x1.9160p-102, + 0x1.a280p-104, + 0x1.3400p-107, + 0x1.2b20p-102, + 0x1.7800p-108, + 0x1.cfd0p-101, + 0x1.2ef0p-102, + -0x1.2760p-99, + 0x1.b380p-104, + 0x1.0048p-101, + -0x1.60b0p-102, + 0x1.a1ccp-100, + -0x1.a640p-104, + -0x1.08a0p-101, + 0x1.7e60p-102, + 0x1.22c0p-103, + -0x1.7200p-106, + 0x1.f0f0p-102, + 0x1.eb4ep-99, + 0x1.c6e0p-103, +}; + +/* + * exp2l(x): compute the base 2 exponential of x + * + * Accuracy: Peak error < 0.502 ulp. + * + * Method: (accurate tables) + * + * Reduce x: + * x = 2**k + y, for integer k and |y| <= 1/2. + * Thus we have exp2(x) = 2**k * exp2(y). + * + * Reduce y: + * y = i/TBLSIZE + z - eps[i] for integer i near y * TBLSIZE. + * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z - eps[i]), + * with |z - eps[i]| <= 2**-8 + 2**-98 for the table used. + * + * We compute exp2(i/TBLSIZE) via table lookup and exp2(z - eps[i]) via + * a degree-10 minimax polynomial with maximum error under 2**-120. + * The values in exp2t[] and eps[] are chosen such that + * exp2t[i] = exp2(i/TBLSIZE + eps[i]), and eps[i] is a small offset such + * that exp2t[i] is accurate to 2**-122. + * + * Note that the range of i is +-TBLSIZE/2, so we actually index the tables + * by i0 = i + TBLSIZE/2. + * + * This method is due to Gal, with many details due to Gal and Bachelis: + * + * Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library + * for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). + */ +long double +exp2l(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + long double r, z, t; + uint32_t i0; + union {uint32_t u; int32_t i;} k; + + /* Filter out exceptional cases. */ + if (e >= 0x3fff + 14) { /* |x| >= 16384 or x is NaN */ + if (u.i.se >= 0x3fff + 15 && u.i.se >> 15 == 0) + /* overflow */ + return x * 0x1p16383L; + if (e == 0x7fff) /* -inf or -nan */ + return -1/x; + if (x < -16382) { + if (x <= -16495 || x - 0x1p112 + 0x1p112 != x) + /* underflow */ + FORCE_EVAL((float)(-0x1p-149/x)); + if (x <= -16446) + return 0; + } + } else if (e < 0x3fff - 114) { + return 1 + x; + } + + /* + * Reduce x, computing z, i0, and k. The low bits of x + redux + * contain the 16-bit integer part of the exponent (k) followed by + * TBLBITS fractional bits (i0). We use bit tricks to extract these + * as integers, then set z to the remainder. + * + * Example: Suppose x is 0xabc.123456p0 and TBLBITS is 8. + * Then the low-order word of x + redux is 0x000abc12, + * We split this into k = 0xabc and i0 = 0x12 (adjusted to + * index into the table), then we compute z = 0x0.003456p0. + */ + u.f = x + redux; + i0 = u.i2.lo + TBLSIZE / 2; + k.u = i0 / TBLSIZE * TBLSIZE; + k.i /= TBLSIZE; + i0 %= TBLSIZE; + u.f -= redux; + z = x - u.f; + + /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */ + t = tbl[i0]; + z -= eps[i0]; + r = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * (P5 + z * (P6 + + z * (P7 + z * (P8 + z * (P9 + z * P10))))))))); + + return scalbnl(r, k.i); +} +#endif diff --git a/src/libc-shim/src/exp_data.c b/src/orca-libc/src/math/exp_data.c similarity index 100% rename from src/libc-shim/src/exp_data.c rename to src/orca-libc/src/math/exp_data.c diff --git a/src/libc-shim/src/exp_data.h b/src/orca-libc/src/math/exp_data.h similarity index 51% rename from src/libc-shim/src/exp_data.h rename to src/orca-libc/src/math/exp_data.h index 932a70a4..3e24bac5 100644 --- a/src/libc-shim/src/exp_data.h +++ b/src/orca-libc/src/math/exp_data.h @@ -12,17 +12,15 @@ #define EXP_POLY_ORDER 5 #define EXP_USE_TOINT_NARROW 0 #define EXP2_POLY_ORDER 5 - -extern const struct exp_data -{ - double invln2N; - double shift; - double negln2hiN; - double negln2loN; - double poly[4]; /* Last four coefficients. */ - double exp2_shift; - double exp2_poly[EXP2_POLY_ORDER]; - uint64_t tab[2 * (1 << EXP_TABLE_BITS)]; +extern hidden const struct exp_data { + double invln2N; + double shift; + double negln2hiN; + double negln2loN; + double poly[4]; /* Last four coefficients. */ + double exp2_shift; + double exp2_poly[EXP2_POLY_ORDER]; + uint64_t tab[2*(1 << EXP_TABLE_BITS)]; } __exp_data; #endif diff --git a/src/libc-shim/src/expf.c b/src/orca-libc/src/math/expf.c similarity index 100% rename from src/libc-shim/src/expf.c rename to src/orca-libc/src/math/expf.c diff --git a/src/orca-libc/src/math/expl.c b/src/orca-libc/src/math/expl.c new file mode 100644 index 00000000..0a7f44f6 --- /dev/null +++ b/src/orca-libc/src/math/expl.c @@ -0,0 +1,128 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_expl.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Exponential function, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, expl(); + * + * y = expl( x ); + * + * + * DESCRIPTION: + * + * Returns e (2.71828...) raised to the x power. + * + * Range reduction is accomplished by separating the argument + * into an integer k and fraction f such that + * + * x k f + * e = 2 e. + * + * A Pade' form of degree 5/6 is used to approximate exp(f) - 1 + * in the basic range [-0.5 ln 2, 0.5 ln 2]. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE +-10000 50000 1.12e-19 2.81e-20 + * + * + * Error amplification in the exponential function can be + * a serious matter. The error propagation involves + * exp( X(1+delta) ) = exp(X) ( 1 + X*delta + ... ), + * which shows that a 1 lsb error in representing X produces + * a relative error of X times 1 lsb in the function. + * While the routine gives an accurate result for arguments + * that are exactly represented by a long double precision + * computer number, the result contains amplified roundoff + * error for large arguments not exactly represented. + * + * + * ERROR MESSAGES: + * + * message condition value returned + * exp underflow x < MINLOG 0.0 + * exp overflow x > MAXLOG MAXNUM + * + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double expl(long double x) +{ + return exp(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 + +static const long double P[3] = { + 1.2617719307481059087798E-4L, + 3.0299440770744196129956E-2L, + 9.9999999999999999991025E-1L, +}; +static const long double Q[4] = { + 3.0019850513866445504159E-6L, + 2.5244834034968410419224E-3L, + 2.2726554820815502876593E-1L, + 2.0000000000000000000897E0L, +}; +static const long double +LN2HI = 6.9314575195312500000000E-1L, +LN2LO = 1.4286068203094172321215E-6L, +LOG2E = 1.4426950408889634073599E0L; + +long double expl(long double x) +{ + long double px, xx; + int k; + + if (isnan(x)) + return x; + if (x > 11356.5234062941439488L) /* x > ln(2^16384 - 0.5) */ + return x * 0x1p16383L; + if (x < -11399.4985314888605581L) /* x < ln(2^-16446) */ + return -0x1p-16445L/x; + + /* Express e**x = e**f 2**k + * = e**(f + k ln(2)) + */ + px = floorl(LOG2E * x + 0.5); + k = px; + x -= px * LN2HI; + x -= px * LN2LO; + + /* rational approximation of the fractional part: + * e**x = 1 + 2x P(x**2)/(Q(x**2) - x P(x**2)) + */ + xx = x * x; + px = x * __polevll(xx, P, 2); + x = px/(__polevll(xx, Q, 3) - px); + x = 1.0 + 2.0 * x; + return scalbnl(x, k); +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double expl(long double x) +{ + return exp(x); +} +#endif diff --git a/src/orca-libc/src/math/expm1.c b/src/orca-libc/src/math/expm1.c new file mode 100644 index 00000000..ac1e61e4 --- /dev/null +++ b/src/orca-libc/src/math/expm1.c @@ -0,0 +1,201 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* expm1(x) + * Returns exp(x)-1, the exponential of x minus 1. + * + * Method + * 1. Argument reduction: + * Given x, find r and integer k such that + * + * x = k*ln2 + r, |r| <= 0.5*ln2 ~ 0.34658 + * + * Here a correction term c will be computed to compensate + * the error in r when rounded to a floating-point number. + * + * 2. Approximating expm1(r) by a special rational function on + * the interval [0,0.34658]: + * Since + * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ... + * we define R1(r*r) by + * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r) + * That is, + * R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r) + * = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r)) + * = 1 - r^2/60 + r^4/2520 - r^6/100800 + ... + * We use a special Remez algorithm on [0,0.347] to generate + * a polynomial of degree 5 in r*r to approximate R1. The + * maximum error of this polynomial approximation is bounded + * by 2**-61. In other words, + * R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5 + * where Q1 = -1.6666666666666567384E-2, + * Q2 = 3.9682539681370365873E-4, + * Q3 = -9.9206344733435987357E-6, + * Q4 = 2.5051361420808517002E-7, + * Q5 = -6.2843505682382617102E-9; + * z = r*r, + * with error bounded by + * | 5 | -61 + * | 1.0+Q1*z+...+Q5*z - R1(z) | <= 2 + * | | + * + * expm1(r) = exp(r)-1 is then computed by the following + * specific way which minimize the accumulation rounding error: + * 2 3 + * r r [ 3 - (R1 + R1*r/2) ] + * expm1(r) = r + --- + --- * [--------------------] + * 2 2 [ 6 - r*(3 - R1*r/2) ] + * + * To compensate the error in the argument reduction, we use + * expm1(r+c) = expm1(r) + c + expm1(r)*c + * ~ expm1(r) + c + r*c + * Thus c+r*c will be added in as the correction terms for + * expm1(r+c). Now rearrange the term to avoid optimization + * screw up: + * ( 2 2 ) + * ({ ( r [ R1 - (3 - R1*r/2) ] ) } r ) + * expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- ) + * ({ ( 2 [ 6 - r*(3 - R1*r/2) ] ) } 2 ) + * ( ) + * + * = r - E + * 3. Scale back to obtain expm1(x): + * From step 1, we have + * expm1(x) = either 2^k*[expm1(r)+1] - 1 + * = or 2^k*[expm1(r) + (1-2^-k)] + * 4. Implementation notes: + * (A). To save one multiplication, we scale the coefficient Qi + * to Qi*2^i, and replace z by (x^2)/2. + * (B). To achieve maximum accuracy, we compute expm1(x) by + * (i) if x < -56*ln2, return -1.0, (raise inexact if x!=inf) + * (ii) if k=0, return r-E + * (iii) if k=-1, return 0.5*(r-E)-0.5 + * (iv) if k=1 if r < -0.25, return 2*((r+0.5)- E) + * else return 1.0+2.0*(r-E); + * (v) if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1) + * (vi) if k <= 20, return 2^k((1-2^-k)-(E-r)), else + * (vii) return 2^k(1-((E+2^-k)-r)) + * + * Special cases: + * expm1(INF) is INF, expm1(NaN) is NaN; + * expm1(-INF) is -1, and + * for finite argument, only expm1(0)=0 is exact. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Misc. info. + * For IEEE double + * if x > 7.09782712893383973096e+02 then expm1(x) overflow + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "libm.h" + +static const double +o_threshold = 7.09782712893383973096e+02, /* 0x40862E42, 0xFEFA39EF */ +ln2_hi = 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */ +ln2_lo = 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */ +invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */ +/* Scaled Q's: Qn_here = 2**n * Qn_above, for R(2*z) where z = hxs = x*x/2: */ +Q1 = -3.33333333333331316428e-02, /* BFA11111 111110F4 */ +Q2 = 1.58730158725481460165e-03, /* 3F5A01A0 19FE5585 */ +Q3 = -7.93650757867487942473e-05, /* BF14CE19 9EAADBB7 */ +Q4 = 4.00821782732936239552e-06, /* 3ED0CFCA 86E65239 */ +Q5 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ + +double expm1(double x) +{ + double_t y,hi,lo,c,t,e,hxs,hfx,r1,twopk; + union {double f; uint64_t i;} u = {x}; + uint32_t hx = u.i>>32 & 0x7fffffff; + int k, sign = u.i>>63; + + /* filter out huge and non-finite argument */ + if (hx >= 0x4043687A) { /* if |x|>=56*ln2 */ + if (isnan(x)) + return x; + if (sign) + return -1; + if (x > o_threshold) { + x *= 0x1p1023; + return x; + } + } + + /* argument reduction */ + if (hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */ + if (hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */ + if (!sign) { + hi = x - ln2_hi; + lo = ln2_lo; + k = 1; + } else { + hi = x + ln2_hi; + lo = -ln2_lo; + k = -1; + } + } else { + k = invln2*x + (sign ? -0.5 : 0.5); + t = k; + hi = x - t*ln2_hi; /* t*ln2_hi is exact here */ + lo = t*ln2_lo; + } + x = hi-lo; + c = (hi-x)-lo; + } else if (hx < 0x3c900000) { /* |x| < 2**-54, return x */ + if (hx < 0x00100000) + FORCE_EVAL((float)x); + return x; + } else + k = 0; + + /* x is now in primary range */ + hfx = 0.5*x; + hxs = x*hfx; + r1 = 1.0+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5)))); + t = 3.0-r1*hfx; + e = hxs*((r1-t)/(6.0 - x*t)); + if (k == 0) /* c is 0 */ + return x - (x*e-hxs); + e = x*(e-c) - c; + e -= hxs; + /* exp(x) ~ 2^k (x_reduced - e + 1) */ + if (k == -1) + return 0.5*(x-e) - 0.5; + if (k == 1) { + if (x < -0.25) + return -2.0*(e-(x+0.5)); + return 1.0+2.0*(x-e); + } + u.i = (uint64_t)(0x3ff + k)<<52; /* 2^k */ + twopk = u.f; + if (k < 0 || k > 56) { /* suffice to return exp(x)-1 */ + y = x - e + 1.0; + if (k == 1024) + y = y*2.0*0x1p1023; + else + y = y*twopk; + return y - 1.0; + } + u.i = (uint64_t)(0x3ff - k)<<52; /* 2^-k */ + if (k < 20) + y = (x-e+(1-u.f))*twopk; + else + y = (x-(e+u.f)+1)*twopk; + return y; +} diff --git a/src/orca-libc/src/math/expm1f.c b/src/orca-libc/src/math/expm1f.c new file mode 100644 index 00000000..09a41afe --- /dev/null +++ b/src/orca-libc/src/math/expm1f.c @@ -0,0 +1,110 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float +ln2_hi = 6.9313812256e-01, /* 0x3f317180 */ +ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */ +invln2 = 1.4426950216e+00, /* 0x3fb8aa3b */ +/* + * Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]: + * |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04 + * Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c): + */ +Q1 = -3.3333212137e-2, /* -0x888868.0p-28 */ +Q2 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ + +float expm1f(float x) +{ + float_t y,hi,lo,c,t,e,hxs,hfx,r1,twopk; + union {float f; uint32_t i;} u = {x}; + uint32_t hx = u.i & 0x7fffffff; + int k, sign = u.i >> 31; + + /* filter out huge and non-finite argument */ + if (hx >= 0x4195b844) { /* if |x|>=27*ln2 */ + if (hx > 0x7f800000) /* NaN */ + return x; + if (sign) + return -1; + if (hx > 0x42b17217) { /* x > log(FLT_MAX) */ + x *= 0x1p127f; + return x; + } + } + + /* argument reduction */ + if (hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */ + if (hx < 0x3F851592) { /* and |x| < 1.5 ln2 */ + if (!sign) { + hi = x - ln2_hi; + lo = ln2_lo; + k = 1; + } else { + hi = x + ln2_hi; + lo = -ln2_lo; + k = -1; + } + } else { + k = invln2*x + (sign ? -0.5f : 0.5f); + t = k; + hi = x - t*ln2_hi; /* t*ln2_hi is exact here */ + lo = t*ln2_lo; + } + x = hi-lo; + c = (hi-x)-lo; + } else if (hx < 0x33000000) { /* when |x|<2**-25, return x */ + if (hx < 0x00800000) + FORCE_EVAL(x*x); + return x; + } else + k = 0; + + /* x is now in primary range */ + hfx = 0.5f*x; + hxs = x*hfx; + r1 = 1.0f+hxs*(Q1+hxs*Q2); + t = 3.0f - r1*hfx; + e = hxs*((r1-t)/(6.0f - x*t)); + if (k == 0) /* c is 0 */ + return x - (x*e-hxs); + e = x*(e-c) - c; + e -= hxs; + /* exp(x) ~ 2^k (x_reduced - e + 1) */ + if (k == -1) + return 0.5f*(x-e) - 0.5f; + if (k == 1) { + if (x < -0.25f) + return -2.0f*(e-(x+0.5f)); + return 1.0f + 2.0f*(x-e); + } + u.i = (0x7f+k)<<23; /* 2^k */ + twopk = u.f; + if (k < 0 || k > 56) { /* suffice to return exp(x)-1 */ + y = x - e + 1.0f; + if (k == 128) + y = y*2.0f*0x1p127f; + else + y = y*twopk; + return y - 1.0f; + } + u.i = (0x7f-k)<<23; /* 2^-k */ + if (k < 23) + y = (x-e+(1-u.f))*twopk; + else + y = (x-(e+u.f)+1)*twopk; + return y; +} diff --git a/src/orca-libc/src/math/expm1l.c b/src/orca-libc/src/math/expm1l.c new file mode 100644 index 00000000..d1715078 --- /dev/null +++ b/src/orca-libc/src/math/expm1l.c @@ -0,0 +1,123 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_expm1l.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Exponential function, minus 1 + * Long double precision + * + * + * SYNOPSIS: + * + * long double x, y, expm1l(); + * + * y = expm1l( x ); + * + * + * DESCRIPTION: + * + * Returns e (2.71828...) raised to the x power, minus 1. + * + * Range reduction is accomplished by separating the argument + * into an integer k and fraction f such that + * + * x k f + * e = 2 e. + * + * An expansion x + .5 x^2 + x^3 R(x) approximates exp(f) - 1 + * in the basic range [-0.5 ln 2, 0.5 ln 2]. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -45,+maxarg 200,000 1.2e-19 2.5e-20 + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double expm1l(long double x) +{ + return expm1(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 + +/* exp(x) - 1 = x + 0.5 x^2 + x^3 P(x)/Q(x) + -.5 ln 2 < x < .5 ln 2 + Theoretical peak relative error = 3.4e-22 */ +static const long double +P0 = -1.586135578666346600772998894928250240826E4L, +P1 = 2.642771505685952966904660652518429479531E3L, +P2 = -3.423199068835684263987132888286791620673E2L, +P3 = 1.800826371455042224581246202420972737840E1L, +P4 = -5.238523121205561042771939008061958820811E-1L, +Q0 = -9.516813471998079611319047060563358064497E4L, +Q1 = 3.964866271411091674556850458227710004570E4L, +Q2 = -7.207678383830091850230366618190187434796E3L, +Q3 = 7.206038318724600171970199625081491823079E2L, +Q4 = -4.002027679107076077238836622982900945173E1L, +/* Q5 = 1.000000000000000000000000000000000000000E0 */ +/* C1 + C2 = ln 2 */ +C1 = 6.93145751953125E-1L, +C2 = 1.428606820309417232121458176568075500134E-6L, +/* ln 2^-65 */ +minarg = -4.5054566736396445112120088E1L, +/* ln 2^16384 */ +maxarg = 1.1356523406294143949492E4L; + +long double expm1l(long double x) +{ + long double px, qx, xx; + int k; + + if (isnan(x)) + return x; + if (x > maxarg) + return x*0x1p16383L; /* overflow, unless x==inf */ + if (x == 0.0) + return x; + if (x < minarg) + return -1.0; + + xx = C1 + C2; + /* Express x = ln 2 (k + remainder), remainder not exceeding 1/2. */ + px = floorl(0.5 + x / xx); + k = px; + /* remainder times ln 2 */ + x -= px * C1; + x -= px * C2; + + /* Approximate exp(remainder ln 2).*/ + px = (((( P4 * x + P3) * x + P2) * x + P1) * x + P0) * x; + qx = (((( x + Q4) * x + Q3) * x + Q2) * x + Q1) * x + Q0; + xx = x * x; + qx = x + (0.5 * xx + xx * px / qx); + + /* exp(x) = exp(k ln 2) exp(remainder ln 2) = 2^k exp(remainder ln 2). + We have qx = exp(remainder ln 2) - 1, so + exp(x) - 1 = 2^k (qx + 1) - 1 = 2^k qx + 2^k - 1. */ + px = scalbnl(1.0, k); + x = px * qx + (px - 1.0); + return x; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double expm1l(long double x) +{ + return expm1(x); +} +#endif diff --git a/src/orca-libc/src/math/fabs.c b/src/orca-libc/src/math/fabs.c new file mode 100644 index 00000000..e8258cfd --- /dev/null +++ b/src/orca-libc/src/math/fabs.c @@ -0,0 +1,9 @@ +#include +#include + +double fabs(double x) +{ + union {double f; uint64_t i;} u = {x}; + u.i &= -1ULL/2; + return u.f; +} diff --git a/src/orca-libc/src/math/fabsf.c b/src/orca-libc/src/math/fabsf.c new file mode 100644 index 00000000..4efc8d68 --- /dev/null +++ b/src/orca-libc/src/math/fabsf.c @@ -0,0 +1,9 @@ +#include +#include + +float fabsf(float x) +{ + union {float f; uint32_t i;} u = {x}; + u.i &= 0x7fffffff; + return u.f; +} diff --git a/src/orca-libc/src/math/fabsl.c b/src/orca-libc/src/math/fabsl.c new file mode 100644 index 00000000..c4f36ec2 --- /dev/null +++ b/src/orca-libc/src/math/fabsl.c @@ -0,0 +1,15 @@ +#include "libm.h" +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fabsl(long double x) +{ + return fabs(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double fabsl(long double x) +{ + union ldshape u = {x}; + + u.i.se &= 0x7fff; + return u.f; +} +#endif diff --git a/src/orca-libc/src/math/fdim.c b/src/orca-libc/src/math/fdim.c new file mode 100644 index 00000000..95854606 --- /dev/null +++ b/src/orca-libc/src/math/fdim.c @@ -0,0 +1,10 @@ +#include + +double fdim(double x, double y) +{ + if (isnan(x)) + return x; + if (isnan(y)) + return y; + return x > y ? x - y : 0; +} diff --git a/src/orca-libc/src/math/fdimf.c b/src/orca-libc/src/math/fdimf.c new file mode 100644 index 00000000..543c3648 --- /dev/null +++ b/src/orca-libc/src/math/fdimf.c @@ -0,0 +1,10 @@ +#include + +float fdimf(float x, float y) +{ + if (isnan(x)) + return x; + if (isnan(y)) + return y; + return x > y ? x - y : 0; +} diff --git a/src/orca-libc/src/math/fdiml.c b/src/orca-libc/src/math/fdiml.c new file mode 100644 index 00000000..62e29b7d --- /dev/null +++ b/src/orca-libc/src/math/fdiml.c @@ -0,0 +1,18 @@ +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fdiml(long double x, long double y) +{ + return fdim(x, y); +} +#else +long double fdiml(long double x, long double y) +{ + if (isnan(x)) + return x; + if (isnan(y)) + return y; + return x > y ? x - y : 0; +} +#endif diff --git a/src/orca-libc/src/math/finite.c b/src/orca-libc/src/math/finite.c new file mode 100644 index 00000000..25a0575f --- /dev/null +++ b/src/orca-libc/src/math/finite.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include + +int finite(double x) +{ + return isfinite(x); +} diff --git a/src/orca-libc/src/math/finitef.c b/src/orca-libc/src/math/finitef.c new file mode 100644 index 00000000..2c4c7714 --- /dev/null +++ b/src/orca-libc/src/math/finitef.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include + +int finitef(float x) +{ + return isfinite(x); +} diff --git a/src/orca-libc/src/math/floor.c b/src/orca-libc/src/math/floor.c new file mode 100644 index 00000000..14a31cd8 --- /dev/null +++ b/src/orca-libc/src/math/floor.c @@ -0,0 +1,31 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const double_t toint = 1/EPS; + +double floor(double x) +{ + union {double f; uint64_t i;} u = {x}; + int e = u.i >> 52 & 0x7ff; + double_t y; + + if (e >= 0x3ff+52 || x == 0) + return x; + /* y = int(x) - x, where int(x) is an integer neighbor of x */ + if (u.i >> 63) + y = x - toint + toint - x; + else + y = x + toint - toint - x; + /* special case because of non-nearest rounding modes */ + if (e <= 0x3ff-1) { + FORCE_EVAL(y); + return u.i >> 63 ? -1 : 0; + } + if (y > 0) + return x + y - 1; + return x + y; +} diff --git a/src/orca-libc/src/math/floorf.c b/src/orca-libc/src/math/floorf.c new file mode 100644 index 00000000..dceec739 --- /dev/null +++ b/src/orca-libc/src/math/floorf.c @@ -0,0 +1,27 @@ +#include "libm.h" + +float floorf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = (int)(u.i >> 23 & 0xff) - 0x7f; + uint32_t m; + + if (e >= 23) + return x; + if (e >= 0) { + m = 0x007fffff >> e; + if ((u.i & m) == 0) + return x; + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31) + u.i += m; + u.i &= ~m; + } else { + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31 == 0) + u.i = 0; + else if (u.i << 1) + u.f = -1.0; + } + return u.f; +} diff --git a/src/orca-libc/src/math/floorl.c b/src/orca-libc/src/math/floorl.c new file mode 100644 index 00000000..16aaec48 --- /dev/null +++ b/src/orca-libc/src/math/floorl.c @@ -0,0 +1,34 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double floorl(long double x) +{ + return floor(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +static const long double toint = 1/LDBL_EPSILON; + +long double floorl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + long double y; + + if (e >= 0x3fff+LDBL_MANT_DIG-1 || x == 0) + return x; + /* y = int(x) - x, where int(x) is an integer neighbor of x */ + if (u.i.se >> 15) + y = x - toint + toint - x; + else + y = x + toint - toint - x; + /* special case because of non-nearest rounding modes */ + if (e <= 0x3fff-1) { + FORCE_EVAL(y); + return u.i.se >> 15 ? -1 : 0; + } + if (y > 0) + return x + y - 1; + return x + y; +} +#endif diff --git a/src/orca-libc/src/math/fma.c b/src/orca-libc/src/math/fma.c new file mode 100644 index 00000000..0c6f90c9 --- /dev/null +++ b/src/orca-libc/src/math/fma.c @@ -0,0 +1,183 @@ +#include +#include +#include +#include "atomic.h" + +#define ASUINT64(x) ((union {double f; uint64_t i;}){x}).i +#define ZEROINFNAN (0x7ff-0x3ff-52-1) + +struct num { uint64_t m; int e; int sign; }; + +static struct num normalize(double x) +{ + uint64_t ix = ASUINT64(x); + int e = ix>>52; + int sign = e & 0x800; + e &= 0x7ff; + if (!e) { + ix = ASUINT64(x*0x1p63); + e = ix>>52 & 0x7ff; + e = e ? e-63 : 0x800; + } + ix &= (1ull<<52)-1; + ix |= 1ull<<52; + ix <<= 1; + e -= 0x3ff + 52 + 1; + return (struct num){ix,e,sign}; +} + +static void mul(uint64_t *hi, uint64_t *lo, uint64_t x, uint64_t y) +{ + uint64_t t1,t2,t3; + uint64_t xlo = (uint32_t)x, xhi = x>>32; + uint64_t ylo = (uint32_t)y, yhi = y>>32; + + t1 = xlo*ylo; + t2 = xlo*yhi + xhi*ylo; + t3 = xhi*yhi; + *lo = t1 + (t2<<32); + *hi = t3 + (t2>>32) + (t1 > *lo); +} + +double fma(double x, double y, double z) +{ + #pragma STDC FENV_ACCESS ON + + /* normalize so top 10bits and last bit are 0 */ + struct num nx, ny, nz; + nx = normalize(x); + ny = normalize(y); + nz = normalize(z); + + if (nx.e >= ZEROINFNAN || ny.e >= ZEROINFNAN) + return x*y + z; + if (nz.e >= ZEROINFNAN) { + if (nz.e > ZEROINFNAN) /* z==0 */ + return x*y + z; + return z; + } + + /* mul: r = x*y */ + uint64_t rhi, rlo, zhi, zlo; + mul(&rhi, &rlo, nx.m, ny.m); + /* either top 20 or 21 bits of rhi and last 2 bits of rlo are 0 */ + + /* align exponents */ + int e = nx.e + ny.e; + int d = nz.e - e; + /* shift bits z<<=kz, r>>=kr, so kz+kr == d, set e = e+kr (== ez-kz) */ + if (d > 0) { + if (d < 64) { + zlo = nz.m<>64-d; + } else { + zlo = 0; + zhi = nz.m; + e = nz.e - 64; + d -= 64; + if (d == 0) { + } else if (d < 64) { + rlo = rhi<<64-d | rlo>>d | !!(rlo<<64-d); + rhi = rhi>>d; + } else { + rlo = 1; + rhi = 0; + } + } + } else { + zhi = 0; + d = -d; + if (d == 0) { + zlo = nz.m; + } else if (d < 64) { + zlo = nz.m>>d | !!(nz.m<<64-d); + } else { + zlo = 1; + } + } + + /* add */ + int sign = nx.sign^ny.sign; + int samesign = !(sign^nz.sign); + int nonzero = 1; + if (samesign) { + /* r += z */ + rlo += zlo; + rhi += zhi + (rlo < zlo); + } else { + /* r -= z */ + uint64_t t = rlo; + rlo -= zlo; + rhi = rhi - zhi - (t < rlo); + if (rhi>>63) { + rlo = -rlo; + rhi = -rhi-!!rlo; + sign = !sign; + } + nonzero = !!rhi; + } + + /* set rhi to top 63bit of the result (last bit is sticky) */ + if (nonzero) { + e += 64; + d = a_clz_64(rhi)-1; + /* note: d > 0 */ + rhi = rhi<>64-d | !!(rlo<>1 | (rlo&1); + else + rhi = rlo<>1 | (rhi&1) | 1ull<<62; + if (sign) + i = -i; + r = i; + r = 2*r - c; /* remove top bit */ + + /* raise underflow portably, such that it + cannot be optimized away */ + { + double_t tiny = DBL_MIN/FLT_MIN * r; + r += (double)(tiny*tiny) * (r-r); + } + } + } else { + /* only round once when scaled */ + d = 10; + i = ( rhi>>d | !!(rhi<<64-d) ) << d; + if (sign) + i = -i; + r = i; + } + } + return scalbn(r, e); +} diff --git a/src/orca-libc/src/math/fmaf.c b/src/orca-libc/src/math/fmaf.c new file mode 100644 index 00000000..7c65acf1 --- /dev/null +++ b/src/orca-libc/src/math/fmaf.c @@ -0,0 +1,92 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_fmaf.c */ +/*- + * Copyright (c) 2005-2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +/* + * Fused multiply-add: Compute x * y + z with a single rounding error. + * + * A double has more than twice as much precision than a float, so + * direct double-precision arithmetic suffices, except where double + * rounding occurs. + */ +float fmaf(float x, float y, float z) +{ + #pragma STDC FENV_ACCESS ON + double xy, result; + union {double f; uint64_t i;} u; + int e; + + xy = (double)x * y; + result = xy + z; + u.f = result; + e = u.i>>52 & 0x7ff; + /* Common case: The double precision result is fine. */ + if ((u.i & 0x1fffffff) != 0x10000000 || /* not a halfway case */ + e == 0x7ff || /* NaN */ + (result - xy == z && result - z == xy) || /* exact */ + fegetround() != FE_TONEAREST) /* not round-to-nearest */ + { + /* + underflow may not be raised correctly, example: + fmaf(0x1p-120f, 0x1p-120f, 0x1p-149f) + */ +#if defined(FE_INEXACT) && defined(FE_UNDERFLOW) + if (e < 0x3ff-126 && e >= 0x3ff-149 && fetestexcept(FE_INEXACT)) { + feclearexcept(FE_INEXACT); + /* TODO: gcc and clang bug workaround */ + volatile float vz = z; + result = xy + vz; + if (fetestexcept(FE_INEXACT)) + feraiseexcept(FE_UNDERFLOW); + else + feraiseexcept(FE_INEXACT); + } +#endif + z = result; + return z; + } + + /* + * If result is inexact, and exactly halfway between two float values, + * we need to adjust the low-order bit in the direction of the error. + */ + double err; + int neg = u.i >> 63; + if (neg == (z > xy)) + err = xy - result + z; + else + err = z - result + xy; + if (neg == (err < 0)) + u.i++; + else + u.i--; + z = u.f; + return z; +} diff --git a/src/orca-libc/src/math/fmal.c b/src/orca-libc/src/math/fmal.c new file mode 100644 index 00000000..dd0e2633 --- /dev/null +++ b/src/orca-libc/src/math/fmal.c @@ -0,0 +1,297 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_fmal.c */ +/*- + * Copyright (c) 2005-2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "libm.h" +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fmal(long double x, long double y, long double z) +{ + return fma(x, y, z); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#include +#if LDBL_MANT_DIG == 64 +#define LASTBIT(u) (u.i.m & 1) +#define SPLIT (0x1p32L + 1) +#elif LDBL_MANT_DIG == 113 +#define LASTBIT(u) (u.i.lo & 1) +#define SPLIT (0x1p57L + 1) +#endif + +/* + * A struct dd represents a floating-point number with twice the precision + * of a long double. We maintain the invariant that "hi" stores the high-order + * bits of the result. + */ +struct dd { + long double hi; + long double lo; +}; + +/* + * Compute a+b exactly, returning the exact result in a struct dd. We assume + * that both a and b are finite, but make no assumptions about their relative + * magnitudes. + */ +static inline struct dd dd_add(long double a, long double b) +{ + struct dd ret; + long double s; + + ret.hi = a + b; + s = ret.hi - a; + ret.lo = (a - (ret.hi - s)) + (b - s); + return (ret); +} + +/* + * Compute a+b, with a small tweak: The least significant bit of the + * result is adjusted into a sticky bit summarizing all the bits that + * were lost to rounding. This adjustment negates the effects of double + * rounding when the result is added to another number with a higher + * exponent. For an explanation of round and sticky bits, see any reference + * on FPU design, e.g., + * + * J. Coonen. An Implementation Guide to a Proposed Standard for + * Floating-Point Arithmetic. Computer, vol. 13, no. 1, Jan 1980. + */ +static inline long double add_adjusted(long double a, long double b) +{ + struct dd sum; + union ldshape u; + + sum = dd_add(a, b); + if (sum.lo != 0) { + u.f = sum.hi; + if (!LASTBIT(u)) + sum.hi = nextafterl(sum.hi, INFINITY * sum.lo); + } + return (sum.hi); +} + +/* + * Compute ldexp(a+b, scale) with a single rounding error. It is assumed + * that the result will be subnormal, and care is taken to ensure that + * double rounding does not occur. + */ +static inline long double add_and_denormalize(long double a, long double b, int scale) +{ + struct dd sum; + int bits_lost; + union ldshape u; + + sum = dd_add(a, b); + + /* + * If we are losing at least two bits of accuracy to denormalization, + * then the first lost bit becomes a round bit, and we adjust the + * lowest bit of sum.hi to make it a sticky bit summarizing all the + * bits in sum.lo. With the sticky bit adjusted, the hardware will + * break any ties in the correct direction. + * + * If we are losing only one bit to denormalization, however, we must + * break the ties manually. + */ + if (sum.lo != 0) { + u.f = sum.hi; + bits_lost = -u.i.se - scale + 1; + if ((bits_lost != 1) ^ LASTBIT(u)) + sum.hi = nextafterl(sum.hi, INFINITY * sum.lo); + } + return scalbnl(sum.hi, scale); +} + +/* + * Compute a*b exactly, returning the exact result in a struct dd. We assume + * that both a and b are normalized, so no underflow or overflow will occur. + * The current rounding mode must be round-to-nearest. + */ +static inline struct dd dd_mul(long double a, long double b) +{ + struct dd ret; + long double ha, hb, la, lb, p, q; + + p = a * SPLIT; + ha = a - p; + ha += p; + la = a - ha; + + p = b * SPLIT; + hb = b - p; + hb += p; + lb = b - hb; + + p = ha * hb; + q = ha * lb + la * hb; + + ret.hi = p + q; + ret.lo = p - ret.hi + q + la * lb; + return (ret); +} + +/* + * Fused multiply-add: Compute x * y + z with a single rounding error. + * + * We use scaling to avoid overflow/underflow, along with the + * canonical precision-doubling technique adapted from: + * + * Dekker, T. A Floating-Point Technique for Extending the + * Available Precision. Numer. Math. 18, 224-242 (1971). + */ +long double fmal(long double x, long double y, long double z) +{ + #pragma STDC FENV_ACCESS ON + long double xs, ys, zs, adj; + struct dd xy, r; + int oround; + int ex, ey, ez; + int spread; + + /* + * Handle special cases. The order of operations and the particular + * return values here are crucial in handling special cases involving + * infinities, NaNs, overflows, and signed zeroes correctly. + */ + if (!isfinite(x) || !isfinite(y)) + return (x * y + z); + if (!isfinite(z)) + return (z); + if (x == 0.0 || y == 0.0) + return (x * y + z); + if (z == 0.0) + return (x * y); + + xs = frexpl(x, &ex); + ys = frexpl(y, &ey); + zs = frexpl(z, &ez); + oround = fegetround(); + spread = ex + ey - ez; + + /* + * If x * y and z are many orders of magnitude apart, the scaling + * will overflow, so we handle these cases specially. Rounding + * modes other than FE_TONEAREST are painful. + */ + if (spread < -LDBL_MANT_DIG) { +#ifdef FE_INEXACT + feraiseexcept(FE_INEXACT); +#endif +#ifdef FE_UNDERFLOW + if (!isnormal(z)) + feraiseexcept(FE_UNDERFLOW); +#endif + switch (oround) { + default: /* FE_TONEAREST */ + return (z); +#ifdef FE_TOWARDZERO + case FE_TOWARDZERO: + if (x > 0.0 ^ y < 0.0 ^ z < 0.0) + return (z); + else + return (nextafterl(z, 0)); +#endif +#ifdef FE_DOWNWARD + case FE_DOWNWARD: + if (x > 0.0 ^ y < 0.0) + return (z); + else + return (nextafterl(z, -INFINITY)); +#endif +#ifdef FE_UPWARD + case FE_UPWARD: + if (x > 0.0 ^ y < 0.0) + return (nextafterl(z, INFINITY)); + else + return (z); +#endif + } + } + if (spread <= LDBL_MANT_DIG * 2) + zs = scalbnl(zs, -spread); + else + zs = copysignl(LDBL_MIN, zs); + + fesetround(FE_TONEAREST); + + /* + * Basic approach for round-to-nearest: + * + * (xy.hi, xy.lo) = x * y (exact) + * (r.hi, r.lo) = xy.hi + z (exact) + * adj = xy.lo + r.lo (inexact; low bit is sticky) + * result = r.hi + adj (correctly rounded) + */ + xy = dd_mul(xs, ys); + r = dd_add(xy.hi, zs); + + spread = ex + ey; + + if (r.hi == 0.0) { + /* + * When the addends cancel to 0, ensure that the result has + * the correct sign. + */ + fesetround(oround); +#ifdef __wasilibc_unmodified_upstream // WASI doesn't need old GCC workarounds + volatile long double vzs = zs; /* XXX gcc CSE bug workaround */ +#else + long double vzs = zs; +#endif + return xy.hi + vzs + scalbnl(xy.lo, spread); + } + + if (oround != FE_TONEAREST) { + /* + * There is no need to worry about double rounding in directed + * rounding modes. + * But underflow may not be raised correctly, example in downward rounding: + * fmal(0x1.0000000001p-16000L, 0x1.0000000001p-400L, -0x1p-16440L) + */ + long double ret; +#if defined(FE_INEXACT) && defined(FE_UNDERFLOW) + int e = fetestexcept(FE_INEXACT); + feclearexcept(FE_INEXACT); +#endif + fesetround(oround); + adj = r.lo + xy.lo; + ret = scalbnl(r.hi + adj, spread); +#if defined(FE_INEXACT) && defined(FE_UNDERFLOW) + if (ilogbl(ret) < -16382 && fetestexcept(FE_INEXACT)) + feraiseexcept(FE_UNDERFLOW); + else if (e) + feraiseexcept(FE_INEXACT); +#endif + return ret; + } + + adj = add_adjusted(r.lo, xy.lo); + if (spread + ilogbl(r.hi) > -16383) + return scalbnl(r.hi + adj, spread); + else + return add_and_denormalize(r.hi, adj, spread); +} +#endif diff --git a/src/orca-libc/src/math/fmax.c b/src/orca-libc/src/math/fmax.c new file mode 100644 index 00000000..94f0caa1 --- /dev/null +++ b/src/orca-libc/src/math/fmax.c @@ -0,0 +1,13 @@ +#include + +double fmax(double x, double y) +{ + if (isnan(x)) + return y; + if (isnan(y)) + return x; + /* handle signed zeros, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) + return signbit(x) ? y : x; + return x < y ? y : x; +} diff --git a/src/orca-libc/src/math/fmaxf.c b/src/orca-libc/src/math/fmaxf.c new file mode 100644 index 00000000..695d8179 --- /dev/null +++ b/src/orca-libc/src/math/fmaxf.c @@ -0,0 +1,13 @@ +#include + +float fmaxf(float x, float y) +{ + if (isnan(x)) + return y; + if (isnan(y)) + return x; + /* handle signed zeroes, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) + return signbit(x) ? y : x; + return x < y ? y : x; +} diff --git a/src/orca-libc/src/math/fmaxl.c b/src/orca-libc/src/math/fmaxl.c new file mode 100644 index 00000000..4b03158e --- /dev/null +++ b/src/orca-libc/src/math/fmaxl.c @@ -0,0 +1,21 @@ +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fmaxl(long double x, long double y) +{ + return fmax(x, y); +} +#else +long double fmaxl(long double x, long double y) +{ + if (isnan(x)) + return y; + if (isnan(y)) + return x; + /* handle signed zeros, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) + return signbit(x) ? y : x; + return x < y ? y : x; +} +#endif diff --git a/src/orca-libc/src/math/fmin.c b/src/orca-libc/src/math/fmin.c new file mode 100644 index 00000000..08a8fd17 --- /dev/null +++ b/src/orca-libc/src/math/fmin.c @@ -0,0 +1,13 @@ +#include + +double fmin(double x, double y) +{ + if (isnan(x)) + return y; + if (isnan(y)) + return x; + /* handle signed zeros, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) + return signbit(x) ? x : y; + return x < y ? x : y; +} diff --git a/src/orca-libc/src/math/fminf.c b/src/orca-libc/src/math/fminf.c new file mode 100644 index 00000000..3573c7de --- /dev/null +++ b/src/orca-libc/src/math/fminf.c @@ -0,0 +1,13 @@ +#include + +float fminf(float x, float y) +{ + if (isnan(x)) + return y; + if (isnan(y)) + return x; + /* handle signed zeros, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) + return signbit(x) ? x : y; + return x < y ? x : y; +} diff --git a/src/orca-libc/src/math/fminl.c b/src/orca-libc/src/math/fminl.c new file mode 100644 index 00000000..69bc24a7 --- /dev/null +++ b/src/orca-libc/src/math/fminl.c @@ -0,0 +1,21 @@ +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fminl(long double x, long double y) +{ + return fmin(x, y); +} +#else +long double fminl(long double x, long double y) +{ + if (isnan(x)) + return y; + if (isnan(y)) + return x; + /* handle signed zeros, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) + return signbit(x) ? x : y; + return x < y ? x : y; +} +#endif diff --git a/src/orca-libc/src/math/fmod.c b/src/orca-libc/src/math/fmod.c new file mode 100644 index 00000000..6849722b --- /dev/null +++ b/src/orca-libc/src/math/fmod.c @@ -0,0 +1,68 @@ +#include +#include + +double fmod(double x, double y) +{ + union {double f; uint64_t i;} ux = {x}, uy = {y}; + int ex = ux.i>>52 & 0x7ff; + int ey = uy.i>>52 & 0x7ff; + int sx = ux.i>>63; + uint64_t i; + + /* in the followings uxi should be ux.i, but then gcc wrongly adds */ + /* float load/store to inner loops ruining performance and code size */ + uint64_t uxi = ux.i; + + if (uy.i<<1 == 0 || isnan(y) || ex == 0x7ff) + return (x*y)/(x*y); + if (uxi<<1 <= uy.i<<1) { + if (uxi<<1 == uy.i<<1) + return 0*x; + return x; + } + + /* normalize x and y */ + if (!ex) { + for (i = uxi<<12; i>>63 == 0; ex--, i <<= 1); + uxi <<= -ex + 1; + } else { + uxi &= -1ULL >> 12; + uxi |= 1ULL << 52; + } + if (!ey) { + for (i = uy.i<<12; i>>63 == 0; ey--, i <<= 1); + uy.i <<= -ey + 1; + } else { + uy.i &= -1ULL >> 12; + uy.i |= 1ULL << 52; + } + + /* x mod y */ + for (; ex > ey; ex--) { + i = uxi - uy.i; + if (i >> 63 == 0) { + if (i == 0) + return 0*x; + uxi = i; + } + uxi <<= 1; + } + i = uxi - uy.i; + if (i >> 63 == 0) { + if (i == 0) + return 0*x; + uxi = i; + } + for (; uxi>>52 == 0; uxi <<= 1, ex--); + + /* scale result */ + if (ex > 0) { + uxi -= 1ULL << 52; + uxi |= (uint64_t)ex << 52; + } else { + uxi >>= -ex + 1; + } + uxi |= (uint64_t)sx << 63; + ux.i = uxi; + return ux.f; +} diff --git a/src/orca-libc/src/math/fmodf.c b/src/orca-libc/src/math/fmodf.c new file mode 100644 index 00000000..ff58f933 --- /dev/null +++ b/src/orca-libc/src/math/fmodf.c @@ -0,0 +1,65 @@ +#include +#include + +float fmodf(float x, float y) +{ + union {float f; uint32_t i;} ux = {x}, uy = {y}; + int ex = ux.i>>23 & 0xff; + int ey = uy.i>>23 & 0xff; + uint32_t sx = ux.i & 0x80000000; + uint32_t i; + uint32_t uxi = ux.i; + + if (uy.i<<1 == 0 || isnan(y) || ex == 0xff) + return (x*y)/(x*y); + if (uxi<<1 <= uy.i<<1) { + if (uxi<<1 == uy.i<<1) + return 0*x; + return x; + } + + /* normalize x and y */ + if (!ex) { + for (i = uxi<<9; i>>31 == 0; ex--, i <<= 1); + uxi <<= -ex + 1; + } else { + uxi &= -1U >> 9; + uxi |= 1U << 23; + } + if (!ey) { + for (i = uy.i<<9; i>>31 == 0; ey--, i <<= 1); + uy.i <<= -ey + 1; + } else { + uy.i &= -1U >> 9; + uy.i |= 1U << 23; + } + + /* x mod y */ + for (; ex > ey; ex--) { + i = uxi - uy.i; + if (i >> 31 == 0) { + if (i == 0) + return 0*x; + uxi = i; + } + uxi <<= 1; + } + i = uxi - uy.i; + if (i >> 31 == 0) { + if (i == 0) + return 0*x; + uxi = i; + } + for (; uxi>>23 == 0; uxi <<= 1, ex--); + + /* scale result up */ + if (ex > 0) { + uxi -= 1U << 23; + uxi |= (uint32_t)ex << 23; + } else { + uxi >>= -ex + 1; + } + uxi |= sx; + ux.i = uxi; + return ux.f; +} diff --git a/src/orca-libc/src/math/fmodl.c b/src/orca-libc/src/math/fmodl.c new file mode 100644 index 00000000..9f5b8739 --- /dev/null +++ b/src/orca-libc/src/math/fmodl.c @@ -0,0 +1,105 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fmodl(long double x, long double y) +{ + return fmod(x, y); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double fmodl(long double x, long double y) +{ + union ldshape ux = {x}, uy = {y}; + int ex = ux.i.se & 0x7fff; + int ey = uy.i.se & 0x7fff; + int sx = ux.i.se & 0x8000; + + if (y == 0 || isnan(y) || ex == 0x7fff) + return (x*y)/(x*y); + ux.i.se = ex; + uy.i.se = ey; + if (ux.f <= uy.f) { + if (ux.f == uy.f) + return 0*x; + return x; + } + + /* normalize x and y */ + if (!ex) { + ux.f *= 0x1p120f; + ex = ux.i.se - 120; + } + if (!ey) { + uy.f *= 0x1p120f; + ey = uy.i.se - 120; + } + + /* x mod y */ +#if LDBL_MANT_DIG == 64 + uint64_t i, mx, my; + mx = ux.i.m; + my = uy.i.m; + for (; ex > ey; ex--) { + i = mx - my; + if (mx >= my) { + if (i == 0) + return 0*x; + mx = 2*i; + } else if (2*mx < mx) { + mx = 2*mx - my; + } else { + mx = 2*mx; + } + } + i = mx - my; + if (mx >= my) { + if (i == 0) + return 0*x; + mx = i; + } + for (; mx >> 63 == 0; mx *= 2, ex--); + ux.i.m = mx; +#elif LDBL_MANT_DIG == 113 + uint64_t hi, lo, xhi, xlo, yhi, ylo; + xhi = (ux.i2.hi & -1ULL>>16) | 1ULL<<48; + yhi = (uy.i2.hi & -1ULL>>16) | 1ULL<<48; + xlo = ux.i2.lo; + ylo = uy.i2.lo; + for (; ex > ey; ex--) { + hi = xhi - yhi; + lo = xlo - ylo; + if (xlo < ylo) + hi -= 1; + if (hi >> 63 == 0) { + if ((hi|lo) == 0) + return 0*x; + xhi = 2*hi + (lo>>63); + xlo = 2*lo; + } else { + xhi = 2*xhi + (xlo>>63); + xlo = 2*xlo; + } + } + hi = xhi - yhi; + lo = xlo - ylo; + if (xlo < ylo) + hi -= 1; + if (hi >> 63 == 0) { + if ((hi|lo) == 0) + return 0*x; + xhi = hi; + xlo = lo; + } + for (; xhi >> 48 == 0; xhi = 2*xhi + (xlo>>63), xlo = 2*xlo, ex--); + ux.i2.hi = xhi; + ux.i2.lo = xlo; +#endif + + /* scale result */ + if (ex <= 0) { + ux.i.se = (ex+120)|sx; + ux.f *= 0x1p-120f; + } else + ux.i.se = ex|sx; + return ux.f; +} +#endif diff --git a/src/orca-libc/src/math/frexp.c b/src/orca-libc/src/math/frexp.c new file mode 100644 index 00000000..27b6266e --- /dev/null +++ b/src/orca-libc/src/math/frexp.c @@ -0,0 +1,23 @@ +#include +#include + +double frexp(double x, int *e) +{ + union { double d; uint64_t i; } y = { x }; + int ee = y.i>>52 & 0x7ff; + + if (!ee) { + if (x) { + x = frexp(x*0x1p64, e); + *e -= 64; + } else *e = 0; + return x; + } else if (ee == 0x7ff) { + return x; + } + + *e = ee - 0x3fe; + y.i &= 0x800fffffffffffffull; + y.i |= 0x3fe0000000000000ull; + return y.d; +} diff --git a/src/orca-libc/src/math/frexpf.c b/src/orca-libc/src/math/frexpf.c new file mode 100644 index 00000000..07870975 --- /dev/null +++ b/src/orca-libc/src/math/frexpf.c @@ -0,0 +1,23 @@ +#include +#include + +float frexpf(float x, int *e) +{ + union { float f; uint32_t i; } y = { x }; + int ee = y.i>>23 & 0xff; + + if (!ee) { + if (x) { + x = frexpf(x*0x1p64, e); + *e -= 64; + } else *e = 0; + return x; + } else if (ee == 0xff) { + return x; + } + + *e = ee - 0x7e; + y.i &= 0x807ffffful; + y.i |= 0x3f000000ul; + return y.f; +} diff --git a/src/orca-libc/src/math/frexpl.c b/src/orca-libc/src/math/frexpl.c new file mode 100644 index 00000000..3c1b5537 --- /dev/null +++ b/src/orca-libc/src/math/frexpl.c @@ -0,0 +1,29 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double frexpl(long double x, int *e) +{ + return frexp(x, e); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double frexpl(long double x, int *e) +{ + union ldshape u = {x}; + int ee = u.i.se & 0x7fff; + + if (!ee) { + if (x) { + x = frexpl(x*0x1p120, e); + *e -= 120; + } else *e = 0; + return x; + } else if (ee == 0x7fff) { + return x; + } + + *e = ee - 0x3ffe; + u.i.se &= 0x8000; + u.i.se |= 0x3ffe; + return u.f; +} +#endif diff --git a/src/orca-libc/src/math/hypot.c b/src/orca-libc/src/math/hypot.c new file mode 100644 index 00000000..6071bf1e --- /dev/null +++ b/src/orca-libc/src/math/hypot.c @@ -0,0 +1,67 @@ +#include +#include +#include + +#if FLT_EVAL_METHOD > 1U && LDBL_MANT_DIG == 64 +#define SPLIT (0x1p32 + 1) +#else +#define SPLIT (0x1p27 + 1) +#endif + +static void sq(double_t *hi, double_t *lo, double x) +{ + double_t xh, xl, xc; + + xc = (double_t)x*SPLIT; + xh = x - xc + xc; + xl = x - xh; + *hi = (double_t)x*x; + *lo = xh*xh - *hi + 2*xh*xl + xl*xl; +} + +double hypot(double x, double y) +{ + union {double f; uint64_t i;} ux = {x}, uy = {y}, ut; + int ex, ey; + double_t hx, lx, hy, ly, z; + + /* arrange |x| >= |y| */ + ux.i &= -1ULL>>1; + uy.i &= -1ULL>>1; + if (ux.i < uy.i) { + ut = ux; + ux = uy; + uy = ut; + } + + /* special cases */ + ex = ux.i>>52; + ey = uy.i>>52; + x = ux.f; + y = uy.f; + /* note: hypot(inf,nan) == inf */ + if (ey == 0x7ff) + return y; + if (ex == 0x7ff || uy.i == 0) + return x; + /* note: hypot(x,y) ~= x + y*y/x/2 with inexact for small y/x */ + /* 64 difference is enough for ld80 double_t */ + if (ex - ey > 64) + return x + y; + + /* precise sqrt argument in nearest rounding mode without overflow */ + /* xh*xh must not overflow and xl*xl must not underflow in sq */ + z = 1; + if (ex > 0x3ff+510) { + z = 0x1p700; + x *= 0x1p-700; + y *= 0x1p-700; + } else if (ey < 0x3ff-450) { + z = 0x1p-700; + x *= 0x1p700; + y *= 0x1p700; + } + sq(&hx, &lx, x); + sq(&hy, &ly, y); + return z*sqrt(ly+lx+hy+hx); +} diff --git a/src/orca-libc/src/math/hypotf.c b/src/orca-libc/src/math/hypotf.c new file mode 100644 index 00000000..2fc214b7 --- /dev/null +++ b/src/orca-libc/src/math/hypotf.c @@ -0,0 +1,35 @@ +#include +#include + +float hypotf(float x, float y) +{ + union {float f; uint32_t i;} ux = {x}, uy = {y}, ut; + float_t z; + + ux.i &= -1U>>1; + uy.i &= -1U>>1; + if (ux.i < uy.i) { + ut = ux; + ux = uy; + uy = ut; + } + + x = ux.f; + y = uy.f; + if (uy.i == 0xff<<23) + return y; + if (ux.i >= 0xff<<23 || uy.i == 0 || ux.i - uy.i >= 25<<23) + return x + y; + + z = 1; + if (ux.i >= (0x7f+60)<<23) { + z = 0x1p90f; + x *= 0x1p-90f; + y *= 0x1p-90f; + } else if (uy.i < (0x7f-60)<<23) { + z = 0x1p-90f; + x *= 0x1p90f; + y *= 0x1p90f; + } + return z*sqrtf((double)x*x + (double)y*y); +} diff --git a/src/orca-libc/src/math/hypotl.c b/src/orca-libc/src/math/hypotl.c new file mode 100644 index 00000000..479aa92c --- /dev/null +++ b/src/orca-libc/src/math/hypotl.c @@ -0,0 +1,66 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double hypotl(long double x, long double y) +{ + return hypot(x, y); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#if LDBL_MANT_DIG == 64 +#define SPLIT (0x1p32L+1) +#elif LDBL_MANT_DIG == 113 +#define SPLIT (0x1p57L+1) +#endif + +static void sq(long double *hi, long double *lo, long double x) +{ + long double xh, xl, xc; + xc = x*SPLIT; + xh = x - xc + xc; + xl = x - xh; + *hi = x*x; + *lo = xh*xh - *hi + 2*xh*xl + xl*xl; +} + +long double hypotl(long double x, long double y) +{ + union ldshape ux = {x}, uy = {y}; + int ex, ey; + long double hx, lx, hy, ly, z; + + ux.i.se &= 0x7fff; + uy.i.se &= 0x7fff; + if (ux.i.se < uy.i.se) { + ex = uy.i.se; + ey = ux.i.se; + x = uy.f; + y = ux.f; + } else { + ex = ux.i.se; + ey = uy.i.se; + x = ux.f; + y = uy.f; + } + + if (ex == 0x7fff && isinf(y)) + return y; + if (ex == 0x7fff || y == 0) + return x; + if (ex - ey > LDBL_MANT_DIG) + return x + y; + + z = 1; + if (ex > 0x3fff+8000) { + z = 0x1p10000L; + x *= 0x1p-10000L; + y *= 0x1p-10000L; + } else if (ey < 0x3fff-8000) { + z = 0x1p-10000L; + x *= 0x1p10000L; + y *= 0x1p10000L; + } + sq(&hx, &lx, x); + sq(&hy, &ly, y); + return z*sqrtl(ly+lx+hy+hx); +} +#endif diff --git a/src/orca-libc/src/math/ilogb.c b/src/orca-libc/src/math/ilogb.c new file mode 100644 index 00000000..64d40154 --- /dev/null +++ b/src/orca-libc/src/math/ilogb.c @@ -0,0 +1,26 @@ +#include +#include "libm.h" + +int ilogb(double x) +{ + #pragma STDC FENV_ACCESS ON + union {double f; uint64_t i;} u = {x}; + uint64_t i = u.i; + int e = i>>52 & 0x7ff; + + if (!e) { + i <<= 12; + if (i == 0) { + FORCE_EVAL(0/0.0f); + return FP_ILOGB0; + } + /* subnormal x */ + for (e = -0x3ff; i>>63 == 0; e--, i<<=1); + return e; + } + if (e == 0x7ff) { + FORCE_EVAL(0/0.0f); + return i<<12 ? FP_ILOGBNAN : INT_MAX; + } + return e - 0x3ff; +} diff --git a/src/orca-libc/src/math/ilogbf.c b/src/orca-libc/src/math/ilogbf.c new file mode 100644 index 00000000..e23ba209 --- /dev/null +++ b/src/orca-libc/src/math/ilogbf.c @@ -0,0 +1,26 @@ +#include +#include "libm.h" + +int ilogbf(float x) +{ + #pragma STDC FENV_ACCESS ON + union {float f; uint32_t i;} u = {x}; + uint32_t i = u.i; + int e = i>>23 & 0xff; + + if (!e) { + i <<= 9; + if (i == 0) { + FORCE_EVAL(0/0.0f); + return FP_ILOGB0; + } + /* subnormal x */ + for (e = -0x7f; i>>31 == 0; e--, i<<=1); + return e; + } + if (e == 0xff) { + FORCE_EVAL(0/0.0f); + return i<<9 ? FP_ILOGBNAN : INT_MAX; + } + return e - 0x7f; +} diff --git a/src/orca-libc/src/math/ilogbl.c b/src/orca-libc/src/math/ilogbl.c new file mode 100644 index 00000000..7b1a9cf8 --- /dev/null +++ b/src/orca-libc/src/math/ilogbl.c @@ -0,0 +1,55 @@ +#include +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +int ilogbl(long double x) +{ + return ilogb(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +int ilogbl(long double x) +{ + #pragma STDC FENV_ACCESS ON + union ldshape u = {x}; + uint64_t m = u.i.m; + int e = u.i.se & 0x7fff; + + if (!e) { + if (m == 0) { + FORCE_EVAL(0/0.0f); + return FP_ILOGB0; + } + /* subnormal x */ + for (e = -0x3fff+1; m>>63 == 0; e--, m<<=1); + return e; + } + if (e == 0x7fff) { + FORCE_EVAL(0/0.0f); + return m<<1 ? FP_ILOGBNAN : INT_MAX; + } + return e - 0x3fff; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +int ilogbl(long double x) +{ + #pragma STDC FENV_ACCESS ON + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + + if (!e) { + if (x == 0) { + FORCE_EVAL(0/0.0f); + return FP_ILOGB0; + } + /* subnormal x */ + x *= 0x1p120; + return ilogbl(x) - 120; + } + if (e == 0x7fff) { + FORCE_EVAL(0/0.0f); + u.i.se = 0; + return u.f ? FP_ILOGBNAN : INT_MAX; + } + return e - 0x3fff; +} +#endif diff --git a/src/orca-libc/src/math/j0.c b/src/orca-libc/src/math/j0.c new file mode 100644 index 00000000..d722d942 --- /dev/null +++ b/src/orca-libc/src/math/j0.c @@ -0,0 +1,375 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j0.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* j0(x), y0(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j0(x): + * 1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ... + * 2. Reduce x to |x| since j0(x)=j0(-x), and + * for x in (0,2) + * j0(x) = 1-z/4+ z^2*R0/S0, where z = x*x; + * (precision: |j0-1+z/4-z^2R0/S0 |<2**-63.67 ) + * for x in (2,inf) + * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * as follow: + * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4) + * = 1/sqrt(2) * (cos(x) + sin(x)) + * sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j0(nan)= nan + * j0(0) = 1 + * j0(inf) = 0 + * + * Method -- y0(x): + * 1. For x<2. + * Since + * y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...) + * therefore y0(x)-2/pi*j0(x)*ln(x) is an even function. + * We use the following function to approximate y0, + * y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2 + * where + * U(z) = u00 + u01*z + ... + u06*z^6 + * V(z) = 1 + v01*z + ... + v04*z^4 + * with absolute approximation error bounded by 2**-72. + * Note: For tiny x, U/V = u0 and j0(x)~1, hence + * y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27) + * 2. For x>=2. + * y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * by the method mentioned above. + * 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0. + */ + +#include "libm.h" + +static double pzero(double), qzero(double); + +static const double +invsqrtpi = 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */ +tpi = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ + +/* common method when |x|>=2 */ +static double common(uint32_t ix, double x, int y0) +{ + double s,c,ss,cc,z; + + /* + * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x-pi/4)-q0(x)*sin(x-pi/4)) + * y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x-pi/4)+q0(x)*cos(x-pi/4)) + * + * sin(x-pi/4) = (sin(x) - cos(x))/sqrt(2) + * cos(x-pi/4) = (sin(x) + cos(x))/sqrt(2) + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + */ + s = sin(x); + c = cos(x); + if (y0) + c = -c; + cc = s+c; + /* avoid overflow in 2*x, big ulp error when x>=0x1p1023 */ + if (ix < 0x7fe00000) { + ss = s-c; + z = -cos(2*x); + if (s*c < 0) + cc = z/ss; + else + ss = z/cc; + if (ix < 0x48000000) { + if (y0) + ss = -ss; + cc = pzero(x)*cc-qzero(x)*ss; + } + } + return invsqrtpi*cc/sqrt(x); +} + +/* R0/S0 on [0, 2.00] */ +static const double +R02 = 1.56249999999999947958e-02, /* 0x3F8FFFFF, 0xFFFFFFFD */ +R03 = -1.89979294238854721751e-04, /* 0xBF28E6A5, 0xB61AC6E9 */ +R04 = 1.82954049532700665670e-06, /* 0x3EBEB1D1, 0x0C503919 */ +R05 = -4.61832688532103189199e-09, /* 0xBE33D5E7, 0x73D63FCE */ +S01 = 1.56191029464890010492e-02, /* 0x3F8FFCE8, 0x82C8C2A4 */ +S02 = 1.16926784663337450260e-04, /* 0x3F1EA6D2, 0xDD57DBF4 */ +S03 = 5.13546550207318111446e-07, /* 0x3EA13B54, 0xCE84D5A9 */ +S04 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ + +double j0(double x) +{ + double z,r,s; + uint32_t ix; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + + /* j0(+-inf)=0, j0(nan)=nan */ + if (ix >= 0x7ff00000) + return 1/(x*x); + x = fabs(x); + + if (ix >= 0x40000000) { /* |x| >= 2 */ + /* large ulp error near zeros: 2.4, 5.52, 8.6537,.. */ + return common(ix,x,0); + } + + /* 1 - x*x/4 + x*x*R(x^2)/S(x^2) */ + if (ix >= 0x3f200000) { /* |x| >= 2**-13 */ + /* up to 4ulp error close to 2 */ + z = x*x; + r = z*(R02+z*(R03+z*(R04+z*R05))); + s = 1+z*(S01+z*(S02+z*(S03+z*S04))); + return (1+x/2)*(1-x/2) + z*(r/s); + } + + /* 1 - x*x/4 */ + /* prevent underflow */ + /* inexact should be raised when x!=0, this is not done correctly */ + if (ix >= 0x38000000) /* |x| >= 2**-127 */ + x = 0.25*x*x; + return 1 - x; +} + +static const double +u00 = -7.38042951086872317523e-02, /* 0xBFB2E4D6, 0x99CBD01F */ +u01 = 1.76666452509181115538e-01, /* 0x3FC69D01, 0x9DE9E3FC */ +u02 = -1.38185671945596898896e-02, /* 0xBF8C4CE8, 0xB16CFA97 */ +u03 = 3.47453432093683650238e-04, /* 0x3F36C54D, 0x20B29B6B */ +u04 = -3.81407053724364161125e-06, /* 0xBECFFEA7, 0x73D25CAD */ +u05 = 1.95590137035022920206e-08, /* 0x3E550057, 0x3B4EABD4 */ +u06 = -3.98205194132103398453e-11, /* 0xBDC5E43D, 0x693FB3C8 */ +v01 = 1.27304834834123699328e-02, /* 0x3F8A1270, 0x91C9C71A */ +v02 = 7.60068627350353253702e-05, /* 0x3F13ECBB, 0xF578C6C1 */ +v03 = 2.59150851840457805467e-07, /* 0x3E91642D, 0x7FF202FD */ +v04 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ + +double y0(double x) +{ + double z,u,v; + uint32_t ix,lx; + + EXTRACT_WORDS(ix, lx, x); + + /* y0(nan)=nan, y0(<0)=nan, y0(0)=-inf, y0(inf)=0 */ + if ((ix<<1 | lx) == 0) + return -1/0.0; + if (ix>>31) + return 0/0.0; + if (ix >= 0x7ff00000) + return 1/x; + + if (ix >= 0x40000000) { /* x >= 2 */ + /* large ulp errors near zeros: 3.958, 7.086,.. */ + return common(ix,x,1); + } + + /* U(x^2)/V(x^2) + (2/pi)*j0(x)*log(x) */ + if (ix >= 0x3e400000) { /* x >= 2**-27 */ + /* large ulp error near the first zero, x ~= 0.89 */ + z = x*x; + u = u00+z*(u01+z*(u02+z*(u03+z*(u04+z*(u05+z*u06))))); + v = 1.0+z*(v01+z*(v02+z*(v03+z*v04))); + return u/v + tpi*(j0(x)*log(x)); + } + return u00 + tpi*log(x); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +static const double pR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */ + -8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */ + -2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */ + -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */ + -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */ +}; +static const double pS8[5] = { + 1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */ + 3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */ + 4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */ + 1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */ + 4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */ +}; + +static const double pR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */ + -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */ + -4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */ + -6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */ + -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */ + -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */ +}; +static const double pS5[5] = { + 6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */ + 1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */ + 5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */ + 9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */ + 2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */ +}; + +static const double pR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */ + -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */ + -2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */ + -2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */ + -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */ + -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */ +}; +static const double pS3[5] = { + 3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */ + 3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */ + 1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */ + 1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */ + 1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */ +}; + +static const double pR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */ + -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */ + -1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */ + -7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */ + -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */ + -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */ +}; +static const double pS2[5] = { + 2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */ + 1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */ + 2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */ + 1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */ + 1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */ +}; + +static double pzero(double x) +{ + const double *p,*q; + double_t z,r,s; + uint32_t ix; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x40200000){p = pR8; q = pS8;} + else if (ix >= 0x40122E8B){p = pR5; q = pS5;} + else if (ix >= 0x4006DB6D){p = pR3; q = pS3;} + else /*ix >= 0x40000000*/ {p = pR2; q = pS2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return 1.0 + r/s; +} + + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +static const double qR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */ + 1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */ + 5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */ + 8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */ + 3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */ +}; +static const double qS8[6] = { + 1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */ + 8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */ + 1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */ + 8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */ + 8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */ + -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */ +}; + +static const double qR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */ + 7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */ + 5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */ + 1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */ + 1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */ + 1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */ +}; +static const double qS5[6] = { + 8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */ + 2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */ + 1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */ + 5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */ + 3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */ + -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */ +}; + +static const double qR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */ + 7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */ + 3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */ + 4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */ + 1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */ + 1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */ +}; +static const double qS3[6] = { + 4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */ + 7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */ + 3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */ + 6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */ + 2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */ + -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */ +}; + +static const double qR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */ + 7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */ + 1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */ + 1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */ + 3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */ + 1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */ +}; +static const double qS2[6] = { + 3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */ + 2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */ + 8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */ + 8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */ + 2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */ + -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */ +}; + +static double qzero(double x) +{ + const double *p,*q; + double_t s,r,z; + uint32_t ix; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x40200000){p = qR8; q = qS8;} + else if (ix >= 0x40122E8B){p = qR5; q = qS5;} + else if (ix >= 0x4006DB6D){p = qR3; q = qS3;} + else /*ix >= 0x40000000*/ {p = qR2; q = qS2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (-.125 + r/s)/x; +} diff --git a/src/orca-libc/src/math/j0f.c b/src/orca-libc/src/math/j0f.c new file mode 100644 index 00000000..fab554a3 --- /dev/null +++ b/src/orca-libc/src/math/j0f.c @@ -0,0 +1,314 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j0f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#define _GNU_SOURCE +#include "libm.h" + +static float pzerof(float), qzerof(float); + +static const float +invsqrtpi = 5.6418961287e-01, /* 0x3f106ebb */ +tpi = 6.3661974669e-01; /* 0x3f22f983 */ + +static float common(uint32_t ix, float x, int y0) +{ + float z,s,c,ss,cc; + /* + * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) + * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) + */ + s = sinf(x); + c = cosf(x); + if (y0) + c = -c; + cc = s+c; + if (ix < 0x7f000000) { + ss = s-c; + z = -cosf(2*x); + if (s*c < 0) + cc = z/ss; + else + ss = z/cc; + if (ix < 0x58800000) { + if (y0) + ss = -ss; + cc = pzerof(x)*cc-qzerof(x)*ss; + } + } + return invsqrtpi*cc/sqrtf(x); +} + +/* R0/S0 on [0, 2.00] */ +static const float +R02 = 1.5625000000e-02, /* 0x3c800000 */ +R03 = -1.8997929874e-04, /* 0xb947352e */ +R04 = 1.8295404516e-06, /* 0x35f58e88 */ +R05 = -4.6183270541e-09, /* 0xb19eaf3c */ +S01 = 1.5619102865e-02, /* 0x3c7fe744 */ +S02 = 1.1692678527e-04, /* 0x38f53697 */ +S03 = 5.1354652442e-07, /* 0x3509daa6 */ +S04 = 1.1661400734e-09; /* 0x30a045e8 */ + +float j0f(float x) +{ + float z,r,s; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x7f800000) + return 1/(x*x); + x = fabsf(x); + + if (ix >= 0x40000000) { /* |x| >= 2 */ + /* large ulp error near zeros */ + return common(ix, x, 0); + } + if (ix >= 0x3a000000) { /* |x| >= 2**-11 */ + /* up to 4ulp error near 2 */ + z = x*x; + r = z*(R02+z*(R03+z*(R04+z*R05))); + s = 1+z*(S01+z*(S02+z*(S03+z*S04))); + return (1+x/2)*(1-x/2) + z*(r/s); + } + if (ix >= 0x21800000) /* |x| >= 2**-60 */ + x = 0.25f*x*x; + return 1 - x; +} + +static const float +u00 = -7.3804296553e-02, /* 0xbd9726b5 */ +u01 = 1.7666645348e-01, /* 0x3e34e80d */ +u02 = -1.3818567619e-02, /* 0xbc626746 */ +u03 = 3.4745343146e-04, /* 0x39b62a69 */ +u04 = -3.8140706238e-06, /* 0xb67ff53c */ +u05 = 1.9559013964e-08, /* 0x32a802ba */ +u06 = -3.9820518410e-11, /* 0xae2f21eb */ +v01 = 1.2730483897e-02, /* 0x3c509385 */ +v02 = 7.6006865129e-05, /* 0x389f65e0 */ +v03 = 2.5915085189e-07, /* 0x348b216c */ +v04 = 4.4111031494e-10; /* 0x2ff280c2 */ + +float y0f(float x) +{ + float z,u,v; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + if ((ix & 0x7fffffff) == 0) + return -1/0.0f; + if (ix>>31) + return 0/0.0f; + if (ix >= 0x7f800000) + return 1/x; + if (ix >= 0x40000000) { /* |x| >= 2.0 */ + /* large ulp error near zeros */ + return common(ix,x,1); + } + if (ix >= 0x39000000) { /* x >= 2**-13 */ + /* large ulp error at x ~= 0.89 */ + z = x*x; + u = u00+z*(u01+z*(u02+z*(u03+z*(u04+z*(u05+z*u06))))); + v = 1+z*(v01+z*(v02+z*(v03+z*v04))); + return u/v + tpi*(j0f(x)*logf(x)); + } + return u00 + tpi*logf(x); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +static const float pR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -7.0312500000e-02, /* 0xbd900000 */ + -8.0816707611e+00, /* 0xc1014e86 */ + -2.5706311035e+02, /* 0xc3808814 */ + -2.4852163086e+03, /* 0xc51b5376 */ + -5.2530439453e+03, /* 0xc5a4285a */ +}; +static const float pS8[5] = { + 1.1653436279e+02, /* 0x42e91198 */ + 3.8337448730e+03, /* 0x456f9beb */ + 4.0597855469e+04, /* 0x471e95db */ + 1.1675296875e+05, /* 0x47e4087c */ + 4.7627726562e+04, /* 0x473a0bba */ +}; +static const float pR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.1412546255e-11, /* 0xad48c58a */ + -7.0312492549e-02, /* 0xbd8fffff */ + -4.1596107483e+00, /* 0xc0851b88 */ + -6.7674766541e+01, /* 0xc287597b */ + -3.3123129272e+02, /* 0xc3a59d9b */ + -3.4643338013e+02, /* 0xc3ad3779 */ +}; +static const float pS5[5] = { + 6.0753936768e+01, /* 0x42730408 */ + 1.0512523193e+03, /* 0x44836813 */ + 5.9789707031e+03, /* 0x45bad7c4 */ + 9.6254453125e+03, /* 0x461665c8 */ + 2.4060581055e+03, /* 0x451660ee */ +}; + +static const float pR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.5470459075e-09, /* 0xb12f081b */ + -7.0311963558e-02, /* 0xbd8fffb8 */ + -2.4090321064e+00, /* 0xc01a2d95 */ + -2.1965976715e+01, /* 0xc1afba52 */ + -5.8079170227e+01, /* 0xc2685112 */ + -3.1447946548e+01, /* 0xc1fb9565 */ +}; +static const float pS3[5] = { + 3.5856033325e+01, /* 0x420f6c94 */ + 3.6151397705e+02, /* 0x43b4c1ca */ + 1.1936077881e+03, /* 0x44953373 */ + 1.1279968262e+03, /* 0x448cffe6 */ + 1.7358093262e+02, /* 0x432d94b8 */ +}; + +static const float pR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.8753431271e-08, /* 0xb3be98b7 */ + -7.0303097367e-02, /* 0xbd8ffb12 */ + -1.4507384300e+00, /* 0xbfb9b1cc */ + -7.6356959343e+00, /* 0xc0f4579f */ + -1.1193166733e+01, /* 0xc1331736 */ + -3.2336456776e+00, /* 0xc04ef40d */ +}; +static const float pS2[5] = { + 2.2220300674e+01, /* 0x41b1c32d */ + 1.3620678711e+02, /* 0x430834f0 */ + 2.7047027588e+02, /* 0x43873c32 */ + 1.5387539673e+02, /* 0x4319e01a */ + 1.4657617569e+01, /* 0x416a859a */ +}; + +static float pzerof(float x) +{ + const float *p,*q; + float_t z,r,s; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x41000000){p = pR8; q = pS8;} + else if (ix >= 0x409173eb){p = pR5; q = pS5;} + else if (ix >= 0x4036d917){p = pR3; q = pS3;} + else /*ix >= 0x40000000*/ {p = pR2; q = pS2;} + z = 1.0f/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0f+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return 1.0f + r/s; +} + + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +static const float qR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 7.3242187500e-02, /* 0x3d960000 */ + 1.1768206596e+01, /* 0x413c4a93 */ + 5.5767340088e+02, /* 0x440b6b19 */ + 8.8591972656e+03, /* 0x460a6cca */ + 3.7014625000e+04, /* 0x471096a0 */ +}; +static const float qS8[6] = { + 1.6377603149e+02, /* 0x4323c6aa */ + 8.0983447266e+03, /* 0x45fd12c2 */ + 1.4253829688e+05, /* 0x480b3293 */ + 8.0330925000e+05, /* 0x49441ed4 */ + 8.4050156250e+05, /* 0x494d3359 */ + -3.4389928125e+05, /* 0xc8a7eb69 */ +}; + +static const float qR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.8408595828e-11, /* 0x2da1ec79 */ + 7.3242180049e-02, /* 0x3d95ffff */ + 5.8356351852e+00, /* 0x40babd86 */ + 1.3511157227e+02, /* 0x43071c90 */ + 1.0272437744e+03, /* 0x448067cd */ + 1.9899779053e+03, /* 0x44f8bf4b */ +}; +static const float qS5[6] = { + 8.2776611328e+01, /* 0x42a58da0 */ + 2.0778142090e+03, /* 0x4501dd07 */ + 1.8847289062e+04, /* 0x46933e94 */ + 5.6751113281e+04, /* 0x475daf1d */ + 3.5976753906e+04, /* 0x470c88c1 */ + -5.3543427734e+03, /* 0xc5a752be */ +}; + +static const float qR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.3774099900e-09, /* 0x3196681b */ + 7.3241114616e-02, /* 0x3d95ff70 */ + 3.3442313671e+00, /* 0x405607e3 */ + 4.2621845245e+01, /* 0x422a7cc5 */ + 1.7080809021e+02, /* 0x432acedf */ + 1.6673394775e+02, /* 0x4326bbe4 */ +}; +static const float qS3[6] = { + 4.8758872986e+01, /* 0x42430916 */ + 7.0968920898e+02, /* 0x44316c1c */ + 3.7041481934e+03, /* 0x4567825f */ + 6.4604252930e+03, /* 0x45c9e367 */ + 2.5163337402e+03, /* 0x451d4557 */ + -1.4924745178e+02, /* 0xc3153f59 */ +}; + +static const float qR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.5044444979e-07, /* 0x342189db */ + 7.3223426938e-02, /* 0x3d95f62a */ + 1.9981917143e+00, /* 0x3fffc4bf */ + 1.4495602608e+01, /* 0x4167edfd */ + 3.1666231155e+01, /* 0x41fd5471 */ + 1.6252708435e+01, /* 0x4182058c */ +}; +static const float qS2[6] = { + 3.0365585327e+01, /* 0x41f2ecb8 */ + 2.6934811401e+02, /* 0x4386ac8f */ + 8.4478375244e+02, /* 0x44533229 */ + 8.8293585205e+02, /* 0x445cbbe5 */ + 2.1266638184e+02, /* 0x4354aa98 */ + -5.3109550476e+00, /* 0xc0a9f358 */ +}; + +static float qzerof(float x) +{ + const float *p,*q; + float_t s,r,z; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x41000000){p = qR8; q = qS8;} + else if (ix >= 0x409173eb){p = qR5; q = qS5;} + else if (ix >= 0x4036d917){p = qR3; q = qS3;} + else /*ix >= 0x40000000*/ {p = qR2; q = qS2;} + z = 1.0f/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0f+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (-.125f + r/s)/x; +} diff --git a/src/orca-libc/src/math/j1.c b/src/orca-libc/src/math/j1.c new file mode 100644 index 00000000..df724d17 --- /dev/null +++ b/src/orca-libc/src/math/j1.c @@ -0,0 +1,362 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j1.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* j1(x), y1(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j1(x): + * 1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ... + * 2. Reduce x to |x| since j1(x)=-j1(-x), and + * for x in (0,2) + * j1(x) = x/2 + x*z*R0/S0, where z = x*x; + * (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 ) + * for x in (2,inf) + * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1)) + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * as follow: + * cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) + * = -1/sqrt(2) * (sin(x) + cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j1(nan)= nan + * j1(0) = 0 + * j1(inf) = 0 + * + * Method -- y1(x): + * 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN + * 2. For x<2. + * Since + * y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...) + * therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function. + * We use the following function to approximate y1, + * y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2 + * where for x in [0,2] (abs err less than 2**-65.89) + * U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4 + * V(z) = 1 + v0[0]*z + ... + v0[4]*z^5 + * Note: For tiny x, 1/x dominate y1 and hence + * y1(tiny) = -2/pi/tiny, (choose tiny<2**-54) + * 3. For x>=2. + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * by method mentioned above. + */ + +#include "libm.h" + +static double pone(double), qone(double); + +static const double +invsqrtpi = 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */ +tpi = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ + +static double common(uint32_t ix, double x, int y1, int sign) +{ + double z,s,c,ss,cc; + + /* + * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x-3pi/4)-q1(x)*sin(x-3pi/4)) + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x-3pi/4)+q1(x)*cos(x-3pi/4)) + * + * sin(x-3pi/4) = -(sin(x) + cos(x))/sqrt(2) + * cos(x-3pi/4) = (sin(x) - cos(x))/sqrt(2) + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + */ + s = sin(x); + if (y1) + s = -s; + c = cos(x); + cc = s-c; + if (ix < 0x7fe00000) { + /* avoid overflow in 2*x */ + ss = -s-c; + z = cos(2*x); + if (s*c > 0) + cc = z/ss; + else + ss = z/cc; + if (ix < 0x48000000) { + if (y1) + ss = -ss; + cc = pone(x)*cc-qone(x)*ss; + } + } + if (sign) + cc = -cc; + return invsqrtpi*cc/sqrt(x); +} + +/* R0/S0 on [0,2] */ +static const double +r00 = -6.25000000000000000000e-02, /* 0xBFB00000, 0x00000000 */ +r01 = 1.40705666955189706048e-03, /* 0x3F570D9F, 0x98472C61 */ +r02 = -1.59955631084035597520e-05, /* 0xBEF0C5C6, 0xBA169668 */ +r03 = 4.96727999609584448412e-08, /* 0x3E6AAAFA, 0x46CA0BD9 */ +s01 = 1.91537599538363460805e-02, /* 0x3F939D0B, 0x12637E53 */ +s02 = 1.85946785588630915560e-04, /* 0x3F285F56, 0xB9CDF664 */ +s03 = 1.17718464042623683263e-06, /* 0x3EB3BFF8, 0x333F8498 */ +s04 = 5.04636257076217042715e-09, /* 0x3E35AC88, 0xC97DFF2C */ +s05 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ + +double j1(double x) +{ + double z,r,s; + uint32_t ix; + int sign; + + GET_HIGH_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix >= 0x7ff00000) + return 1/(x*x); + if (ix >= 0x40000000) /* |x| >= 2 */ + return common(ix, fabs(x), 0, sign); + if (ix >= 0x38000000) { /* |x| >= 2**-127 */ + z = x*x; + r = z*(r00+z*(r01+z*(r02+z*r03))); + s = 1+z*(s01+z*(s02+z*(s03+z*(s04+z*s05)))); + z = r/s; + } else + /* avoid underflow, raise inexact if x!=0 */ + z = x; + return (0.5 + z)*x; +} + +static const double U0[5] = { + -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */ + 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */ + -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */ + 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */ + -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */ +}; +static const double V0[5] = { + 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */ + 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */ + 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */ + 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */ + 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */ +}; + +double y1(double x) +{ + double z,u,v; + uint32_t ix,lx; + + EXTRACT_WORDS(ix, lx, x); + /* y1(nan)=nan, y1(<0)=nan, y1(0)=-inf, y1(inf)=0 */ + if ((ix<<1 | lx) == 0) + return -1/0.0; + if (ix>>31) + return 0/0.0; + if (ix >= 0x7ff00000) + return 1/x; + + if (ix >= 0x40000000) /* x >= 2 */ + return common(ix, x, 1, 0); + if (ix < 0x3c900000) /* x < 2**-54 */ + return -tpi/x; + z = x*x; + u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4]))); + v = 1+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4])))); + return x*(u/v) + tpi*(j1(x)*log(x)-1/x); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +static const double pr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */ + 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */ + 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */ + 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */ + 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */ +}; +static const double ps8[5] = { + 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */ + 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */ + 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */ + 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */ + 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */ +}; + +static const double pr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */ + 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */ + 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */ + 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */ + 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */ + 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */ +}; +static const double ps5[5] = { + 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */ + 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */ + 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */ + 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */ + 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */ +}; + +static const double pr3[6] = { + 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */ + 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */ + 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */ + 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */ + 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */ + 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */ +}; +static const double ps3[5] = { + 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */ + 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */ + 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */ + 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */ + 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */ +}; + +static const double pr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */ + 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */ + 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */ + 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */ + 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */ + 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */ +}; +static const double ps2[5] = { + 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */ + 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */ + 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */ + 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */ + 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */ +}; + +static double pone(double x) +{ + const double *p,*q; + double_t z,r,s; + uint32_t ix; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x40200000){p = pr8; q = ps8;} + else if (ix >= 0x40122E8B){p = pr5; q = ps5;} + else if (ix >= 0x4006DB6D){p = pr3; q = ps3;} + else /*ix >= 0x40000000*/ {p = pr2; q = ps2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return 1.0+ r/s; +} + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +static const double qr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */ + -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */ + -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */ + -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */ + -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */ +}; +static const double qs8[6] = { + 1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */ + 7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */ + 1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */ + 7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */ + 6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */ + -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */ +}; + +static const double qr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */ + -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */ + -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */ + -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */ + -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */ + -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */ +}; +static const double qs5[6] = { + 8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */ + 1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */ + 1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */ + 4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */ + 2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */ + -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */ +}; + +static const double qr3[6] = { + -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */ + -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */ + -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */ + -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */ + -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */ + -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */ +}; +static const double qs3[6] = { + 4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */ + 6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */ + 3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */ + 5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */ + 1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */ + -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */ +}; + +static const double qr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */ + -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */ + -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */ + -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */ + -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */ + -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */ +}; +static const double qs2[6] = { + 2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */ + 2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */ + 7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */ + 7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */ + 1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */ + -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */ +}; + +static double qone(double x) +{ + const double *p,*q; + double_t s,r,z; + uint32_t ix; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x40200000){p = qr8; q = qs8;} + else if (ix >= 0x40122E8B){p = qr5; q = qs5;} + else if (ix >= 0x4006DB6D){p = qr3; q = qs3;} + else /*ix >= 0x40000000*/ {p = qr2; q = qs2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (.375 + r/s)/x; +} diff --git a/src/orca-libc/src/math/j1f.c b/src/orca-libc/src/math/j1f.c new file mode 100644 index 00000000..3434c53d --- /dev/null +++ b/src/orca-libc/src/math/j1f.c @@ -0,0 +1,310 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j1f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#define _GNU_SOURCE +#include "libm.h" + +static float ponef(float), qonef(float); + +static const float +invsqrtpi = 5.6418961287e-01, /* 0x3f106ebb */ +tpi = 6.3661974669e-01; /* 0x3f22f983 */ + +static float common(uint32_t ix, float x, int y1, int sign) +{ + double z,s,c,ss,cc; + + s = sinf(x); + if (y1) + s = -s; + c = cosf(x); + cc = s-c; + if (ix < 0x7f000000) { + ss = -s-c; + z = cosf(2*x); + if (s*c > 0) + cc = z/ss; + else + ss = z/cc; + if (ix < 0x58800000) { + if (y1) + ss = -ss; + cc = ponef(x)*cc-qonef(x)*ss; + } + } + if (sign) + cc = -cc; + return invsqrtpi*cc/sqrtf(x); +} + +/* R0/S0 on [0,2] */ +static const float +r00 = -6.2500000000e-02, /* 0xbd800000 */ +r01 = 1.4070566976e-03, /* 0x3ab86cfd */ +r02 = -1.5995563444e-05, /* 0xb7862e36 */ +r03 = 4.9672799207e-08, /* 0x335557d2 */ +s01 = 1.9153760746e-02, /* 0x3c9ce859 */ +s02 = 1.8594678841e-04, /* 0x3942fab6 */ +s03 = 1.1771846857e-06, /* 0x359dffc2 */ +s04 = 5.0463624390e-09, /* 0x31ad6446 */ +s05 = 1.2354227016e-11; /* 0x2d59567e */ + +float j1f(float x) +{ + float z,r,s; + uint32_t ix; + int sign; + + GET_FLOAT_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix >= 0x7f800000) + return 1/(x*x); + if (ix >= 0x40000000) /* |x| >= 2 */ + return common(ix, fabsf(x), 0, sign); + if (ix >= 0x39000000) { /* |x| >= 2**-13 */ + z = x*x; + r = z*(r00+z*(r01+z*(r02+z*r03))); + s = 1+z*(s01+z*(s02+z*(s03+z*(s04+z*s05)))); + z = 0.5f + r/s; + } else + z = 0.5f; + return z*x; +} + +static const float U0[5] = { + -1.9605709612e-01, /* 0xbe48c331 */ + 5.0443872809e-02, /* 0x3d4e9e3c */ + -1.9125689287e-03, /* 0xbafaaf2a */ + 2.3525259166e-05, /* 0x37c5581c */ + -9.1909917899e-08, /* 0xb3c56003 */ +}; +static const float V0[5] = { + 1.9916731864e-02, /* 0x3ca3286a */ + 2.0255257550e-04, /* 0x3954644b */ + 1.3560879779e-06, /* 0x35b602d4 */ + 6.2274145840e-09, /* 0x31d5f8eb */ + 1.6655924903e-11, /* 0x2d9281cf */ +}; + +float y1f(float x) +{ + float z,u,v; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + if ((ix & 0x7fffffff) == 0) + return -1/0.0f; + if (ix>>31) + return 0/0.0f; + if (ix >= 0x7f800000) + return 1/x; + if (ix >= 0x40000000) /* |x| >= 2.0 */ + return common(ix,x,1,0); + if (ix < 0x33000000) /* x < 2**-25 */ + return -tpi/x; + z = x*x; + u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4]))); + v = 1.0f+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4])))); + return x*(u/v) + tpi*(j1f(x)*logf(x)-1.0f/x); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +static const float pr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 1.1718750000e-01, /* 0x3df00000 */ + 1.3239480972e+01, /* 0x4153d4ea */ + 4.1205184937e+02, /* 0x43ce06a3 */ + 3.8747453613e+03, /* 0x45722bed */ + 7.9144794922e+03, /* 0x45f753d6 */ +}; +static const float ps8[5] = { + 1.1420736694e+02, /* 0x42e46a2c */ + 3.6509309082e+03, /* 0x45642ee5 */ + 3.6956207031e+04, /* 0x47105c35 */ + 9.7602796875e+04, /* 0x47bea166 */ + 3.0804271484e+04, /* 0x46f0a88b */ +}; + +static const float pr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.3199052094e-11, /* 0x2d68333f */ + 1.1718749255e-01, /* 0x3defffff */ + 6.8027510643e+00, /* 0x40d9b023 */ + 1.0830818176e+02, /* 0x42d89dca */ + 5.1763616943e+02, /* 0x440168b7 */ + 5.2871520996e+02, /* 0x44042dc6 */ +}; +static const float ps5[5] = { + 5.9280597687e+01, /* 0x426d1f55 */ + 9.9140142822e+02, /* 0x4477d9b1 */ + 5.3532670898e+03, /* 0x45a74a23 */ + 7.8446904297e+03, /* 0x45f52586 */ + 1.5040468750e+03, /* 0x44bc0180 */ +}; + +static const float pr3[6] = { + 3.0250391081e-09, /* 0x314fe10d */ + 1.1718686670e-01, /* 0x3defffab */ + 3.9329774380e+00, /* 0x407bb5e7 */ + 3.5119403839e+01, /* 0x420c7a45 */ + 9.1055007935e+01, /* 0x42b61c2a */ + 4.8559066772e+01, /* 0x42423c7c */ +}; +static const float ps3[5] = { + 3.4791309357e+01, /* 0x420b2a4d */ + 3.3676245117e+02, /* 0x43a86198 */ + 1.0468714600e+03, /* 0x4482dbe3 */ + 8.9081134033e+02, /* 0x445eb3ed */ + 1.0378793335e+02, /* 0x42cf936c */ +}; + +static const float pr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.0771083225e-07, /* 0x33e74ea8 */ + 1.1717621982e-01, /* 0x3deffa16 */ + 2.3685150146e+00, /* 0x401795c0 */ + 1.2242610931e+01, /* 0x4143e1bc */ + 1.7693971634e+01, /* 0x418d8d41 */ + 5.0735230446e+00, /* 0x40a25a4d */ +}; +static const float ps2[5] = { + 2.1436485291e+01, /* 0x41ab7dec */ + 1.2529022980e+02, /* 0x42fa9499 */ + 2.3227647400e+02, /* 0x436846c7 */ + 1.1767937469e+02, /* 0x42eb5bd7 */ + 8.3646392822e+00, /* 0x4105d590 */ +}; + +static float ponef(float x) +{ + const float *p,*q; + float_t z,r,s; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x41000000){p = pr8; q = ps8;} + else if (ix >= 0x409173eb){p = pr5; q = ps5;} + else if (ix >= 0x4036d917){p = pr3; q = ps3;} + else /*ix >= 0x40000000*/ {p = pr2; q = ps2;} + z = 1.0f/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0f+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return 1.0f + r/s; +} + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +static const float qr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -1.0253906250e-01, /* 0xbdd20000 */ + -1.6271753311e+01, /* 0xc1822c8d */ + -7.5960174561e+02, /* 0xc43de683 */ + -1.1849806641e+04, /* 0xc639273a */ + -4.8438511719e+04, /* 0xc73d3683 */ +}; +static const float qs8[6] = { + 1.6139537048e+02, /* 0x43216537 */ + 7.8253862305e+03, /* 0x45f48b17 */ + 1.3387534375e+05, /* 0x4802bcd6 */ + 7.1965775000e+05, /* 0x492fb29c */ + 6.6660125000e+05, /* 0x4922be94 */ + -2.9449025000e+05, /* 0xc88fcb48 */ +}; + +static const float qr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.0897993405e-11, /* 0xadb7d219 */ + -1.0253904760e-01, /* 0xbdd1fffe */ + -8.0564479828e+00, /* 0xc100e736 */ + -1.8366960144e+02, /* 0xc337ab6b */ + -1.3731937256e+03, /* 0xc4aba633 */ + -2.6124443359e+03, /* 0xc523471c */ +}; +static const float qs5[6] = { + 8.1276550293e+01, /* 0x42a28d98 */ + 1.9917987061e+03, /* 0x44f8f98f */ + 1.7468484375e+04, /* 0x468878f8 */ + 4.9851425781e+04, /* 0x4742bb6d */ + 2.7948074219e+04, /* 0x46da5826 */ + -4.7191835938e+03, /* 0xc5937978 */ +}; + +static const float qr3[6] = { + -5.0783124372e-09, /* 0xb1ae7d4f */ + -1.0253783315e-01, /* 0xbdd1ff5b */ + -4.6101160049e+00, /* 0xc0938612 */ + -5.7847221375e+01, /* 0xc267638e */ + -2.2824453735e+02, /* 0xc3643e9a */ + -2.1921012878e+02, /* 0xc35b35cb */ +}; +static const float qs3[6] = { + 4.7665153503e+01, /* 0x423ea91e */ + 6.7386511230e+02, /* 0x4428775e */ + 3.3801528320e+03, /* 0x45534272 */ + 5.5477290039e+03, /* 0x45ad5dd5 */ + 1.9031191406e+03, /* 0x44ede3d0 */ + -1.3520118713e+02, /* 0xc3073381 */ +}; + +static const float qr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.7838172539e-07, /* 0xb43f8932 */ + -1.0251704603e-01, /* 0xbdd1f475 */ + -2.7522056103e+00, /* 0xc0302423 */ + -1.9663616180e+01, /* 0xc19d4f16 */ + -4.2325313568e+01, /* 0xc2294d1f */ + -2.1371921539e+01, /* 0xc1aaf9b2 */ +}; +static const float qs2[6] = { + 2.9533363342e+01, /* 0x41ec4454 */ + 2.5298155212e+02, /* 0x437cfb47 */ + 7.5750280762e+02, /* 0x443d602e */ + 7.3939318848e+02, /* 0x4438d92a */ + 1.5594900513e+02, /* 0x431bf2f2 */ + -4.9594988823e+00, /* 0xc09eb437 */ +}; + +static float qonef(float x) +{ + const float *p,*q; + float_t s,r,z; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x41000000){p = qr8; q = qs8;} + else if (ix >= 0x409173eb){p = qr5; q = qs5;} + else if (ix >= 0x4036d917){p = qr3; q = qs3;} + else /*ix >= 0x40000000*/ {p = qr2; q = qs2;} + z = 1.0f/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0f+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (.375f + r/s)/x; +} diff --git a/src/orca-libc/src/math/jn.c b/src/orca-libc/src/math/jn.c new file mode 100644 index 00000000..4878a54f --- /dev/null +++ b/src/orca-libc/src/math/jn.c @@ -0,0 +1,280 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_jn.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * jn(n, x), yn(n, x) + * floating point Bessel's function of the 1st and 2nd kind + * of order n + * + * Special cases: + * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal; + * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal. + * Note 2. About jn(n,x), yn(n,x) + * For n=0, j0(x) is called, + * for n=1, j1(x) is called, + * for n<=x, forward recursion is used starting + * from values of j0(x) and j1(x). + * for n>x, a continued fraction approximation to + * j(n,x)/j(n-1,x) is evaluated and then backward + * recursion is used starting from a supposed value + * for j(n,x). The resulting value of j(0,x) is + * compared with the actual value to correct the + * supposed value of j(n,x). + * + * yn(n,x) is similar in all respects, except + * that forward recursion is used for all + * values of n>1. + */ + +#include "libm.h" + +static const double invsqrtpi = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ + +double jn(int n, double x) +{ + uint32_t ix, lx; + int nm1, i, sign; + double a, b, temp; + + EXTRACT_WORDS(ix, lx, x); + sign = ix>>31; + ix &= 0x7fffffff; + + if ((ix | (lx|-lx)>>31) > 0x7ff00000) /* nan */ + return x; + + /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x) + * Thus, J(-n,x) = J(n,-x) + */ + /* nm1 = |n|-1 is used instead of |n| to handle n==INT_MIN */ + if (n == 0) + return j0(x); + if (n < 0) { + nm1 = -(n+1); + x = -x; + sign ^= 1; + } else + nm1 = n-1; + if (nm1 == 0) + return j1(x); + + sign &= n; /* even n: 0, odd n: signbit(x) */ + x = fabs(x); + if ((ix|lx) == 0 || ix == 0x7ff00000) /* if x is 0 or inf */ + b = 0.0; + else if (nm1 < x) { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + if (ix >= 0x52d00000) { /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + switch(nm1&3) { + case 0: temp = -cos(x)+sin(x); break; + case 1: temp = -cos(x)-sin(x); break; + case 2: temp = cos(x)-sin(x); break; + default: + case 3: temp = cos(x)+sin(x); break; + } + b = invsqrtpi*temp/sqrt(x); + } else { + a = j0(x); + b = j1(x); + for (i=0; i 32) /* underflow */ + b = 0.0; + else { + temp = x*0.5; + b = temp; + a = 1.0; + for (i=2; i<=nm1+1; i++) { + a *= (double)i; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + } + b = b/a; + } + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + double t,q0,q1,w,h,z,tmp,nf; + int k; + + nf = nm1 + 1.0; + w = 2*nf/x; + h = 2/x; + z = w+h; + q0 = w; + q1 = w*z - 1.0; + k = 1; + while (q1 < 1.0e9) { + k += 1; + z += h; + tmp = z*q1 - q0; + q0 = q1; + q1 = tmp; + } + for (t=0.0, i=k; i>=0; i--) + t = 1/(2*(i+nf)/x - t); + a = t; + b = 1.0; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf*log(fabs(w)); + if (tmp < 7.09782712893383973096e+02) { + for (i=nm1; i>0; i--) { + temp = b; + b = b*(2.0*i)/x - a; + a = temp; + } + } else { + for (i=nm1; i>0; i--) { + temp = b; + b = b*(2.0*i)/x - a; + a = temp; + /* scale b to avoid spurious overflow */ + if (b > 0x1p500) { + a /= b; + t /= b; + b = 1.0; + } + } + } + z = j0(x); + w = j1(x); + if (fabs(z) >= fabs(w)) + b = t*z/b; + else + b = t*w/a; + } + } + return sign ? -b : b; +} + + +double yn(int n, double x) +{ + uint32_t ix, lx, ib; + int nm1, sign, i; + double a, b, temp; + + EXTRACT_WORDS(ix, lx, x); + sign = ix>>31; + ix &= 0x7fffffff; + + if ((ix | (lx|-lx)>>31) > 0x7ff00000) /* nan */ + return x; + if (sign && (ix|lx)!=0) /* x < 0 */ + return 0/0.0; + if (ix == 0x7ff00000) + return 0.0; + + if (n == 0) + return y0(x); + if (n < 0) { + nm1 = -(n+1); + sign = n&1; + } else { + nm1 = n-1; + sign = 0; + } + if (nm1 == 0) + return sign ? -y1(x) : y1(x); + + if (ix >= 0x52d00000) { /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + switch(nm1&3) { + case 0: temp = -sin(x)-cos(x); break; + case 1: temp = -sin(x)+cos(x); break; + case 2: temp = sin(x)+cos(x); break; + default: + case 3: temp = sin(x)-cos(x); break; + } + b = invsqrtpi*temp/sqrt(x); + } else { + a = y0(x); + b = y1(x); + /* quit if b is -inf */ + GET_HIGH_WORD(ib, b); + for (i=0; i>31; + ix &= 0x7fffffff; + if (ix > 0x7f800000) /* nan */ + return x; + + /* J(-n,x) = J(n,-x), use |n|-1 to avoid overflow in -n */ + if (n == 0) + return j0f(x); + if (n < 0) { + nm1 = -(n+1); + x = -x; + sign ^= 1; + } else + nm1 = n-1; + if (nm1 == 0) + return j1f(x); + + sign &= n; /* even n: 0, odd n: signbit(x) */ + x = fabsf(x); + if (ix == 0 || ix == 0x7f800000) /* if x is 0 or inf */ + b = 0.0f; + else if (nm1 < x) { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + a = j0f(x); + b = j1f(x); + for (i=0; i 8) /* underflow */ + nm1 = 8; + temp = 0.5f * x; + b = temp; + a = 1.0f; + for (i=2; i<=nm1+1; i++) { + a *= (float)i; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + } + b = b/a; + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + float t,q0,q1,w,h,z,tmp,nf; + int k; + + nf = nm1+1.0f; + w = 2*nf/x; + h = 2/x; + z = w+h; + q0 = w; + q1 = w*z - 1.0f; + k = 1; + while (q1 < 1.0e4f) { + k += 1; + z += h; + tmp = z*q1 - q0; + q0 = q1; + q1 = tmp; + } + for (t=0.0f, i=k; i>=0; i--) + t = 1.0f/(2*(i+nf)/x-t); + a = t; + b = 1.0f; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf*logf(fabsf(w)); + if (tmp < 88.721679688f) { + for (i=nm1; i>0; i--) { + temp = b; + b = 2.0f*i*b/x - a; + a = temp; + } + } else { + for (i=nm1; i>0; i--){ + temp = b; + b = 2.0f*i*b/x - a; + a = temp; + /* scale b to avoid spurious overflow */ + if (b > 0x1p60f) { + a /= b; + t /= b; + b = 1.0f; + } + } + } + z = j0f(x); + w = j1f(x); + if (fabsf(z) >= fabsf(w)) + b = t*z/b; + else + b = t*w/a; + } + } + return sign ? -b : b; +} + +float ynf(int n, float x) +{ + uint32_t ix, ib; + int nm1, sign, i; + float a, b, temp; + + GET_FLOAT_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix > 0x7f800000) /* nan */ + return x; + if (sign && ix != 0) /* x < 0 */ + return 0/0.0f; + if (ix == 0x7f800000) + return 0.0f; + + if (n == 0) + return y0f(x); + if (n < 0) { + nm1 = -(n+1); + sign = n&1; + } else { + nm1 = n-1; + sign = 0; + } + if (nm1 == 0) + return sign ? -y1f(x) : y1f(x); + + a = y0f(x); + b = y1f(x); + /* quit if b is -inf */ + GET_FLOAT_WORD(ib,b); + for (i = 0; i < nm1 && ib != 0xff800000; ) { + i++; + temp = b; + b = (2.0f*i/x)*b - a; + GET_FLOAT_WORD(ib, b); + a = temp; + } + return sign ? -b : b; +} diff --git a/src/orca-libc/src/math/ldexp.c b/src/orca-libc/src/math/ldexp.c new file mode 100644 index 00000000..f4d1cd6a --- /dev/null +++ b/src/orca-libc/src/math/ldexp.c @@ -0,0 +1,6 @@ +#include + +double ldexp(double x, int n) +{ + return scalbn(x, n); +} diff --git a/src/orca-libc/src/math/ldexpf.c b/src/orca-libc/src/math/ldexpf.c new file mode 100644 index 00000000..3bad5f39 --- /dev/null +++ b/src/orca-libc/src/math/ldexpf.c @@ -0,0 +1,6 @@ +#include + +float ldexpf(float x, int n) +{ + return scalbnf(x, n); +} diff --git a/src/orca-libc/src/math/ldexpl.c b/src/orca-libc/src/math/ldexpl.c new file mode 100644 index 00000000..fd145ccc --- /dev/null +++ b/src/orca-libc/src/math/ldexpl.c @@ -0,0 +1,6 @@ +#include + +long double ldexpl(long double x, int n) +{ + return scalbnl(x, n); +} diff --git a/src/orca-libc/src/math/lgamma.c b/src/orca-libc/src/math/lgamma.c new file mode 100644 index 00000000..2fc9b478 --- /dev/null +++ b/src/orca-libc/src/math/lgamma.c @@ -0,0 +1,7 @@ +#include +#include "libm.h" + +double lgamma(double x) +{ + return __lgamma_r(x, &__signgam); +} diff --git a/src/orca-libc/src/math/lgamma_r.c b/src/orca-libc/src/math/lgamma_r.c new file mode 100644 index 00000000..f9984cd0 --- /dev/null +++ b/src/orca-libc/src/math/lgamma_r.c @@ -0,0 +1,283 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* lgamma_r(x, signgamp) + * Reentrant version of the logarithm of the Gamma function + * with user provide pointer for the sign of Gamma(x). + * + * Method: + * 1. Argument Reduction for 0 < x <= 8 + * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may + * reduce x to a number in [1.5,2.5] by + * lgamma(1+s) = log(s) + lgamma(s) + * for example, + * lgamma(7.3) = log(6.3) + lgamma(6.3) + * = log(6.3*5.3) + lgamma(5.3) + * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) + * 2. Polynomial approximation of lgamma around its + * minimun ymin=1.461632144968362245 to maintain monotonicity. + * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use + * Let z = x-ymin; + * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) + * where + * poly(z) is a 14 degree polynomial. + * 2. Rational approximation in the primary interval [2,3] + * We use the following approximation: + * s = x-2.0; + * lgamma(x) = 0.5*s + s*P(s)/Q(s) + * with accuracy + * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 + * Our algorithms are based on the following observation + * + * zeta(2)-1 2 zeta(3)-1 3 + * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... + * 2 3 + * + * where Euler = 0.5771... is the Euler constant, which is very + * close to 0.5. + * + * 3. For x>=8, we have + * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... + * (better formula: + * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) + * Let z = 1/x, then we approximation + * f(z) = lgamma(x) - (x-0.5)(log(x)-1) + * by + * 3 5 11 + * w = w0 + w1*z + w2*z + w3*z + ... + w6*z + * where + * |w - f(z)| < 2**-58.74 + * + * 4. For negative x, since (G is gamma function) + * -x*G(-x)*G(x) = pi/sin(pi*x), + * we have + * G(x) = pi/(sin(pi*x)*(-x)*G(-x)) + * since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0 + * Hence, for x<0, signgam = sign(sin(pi*x)) and + * lgamma(x) = log(|Gamma(x)|) + * = log(pi/(|x*sin(pi*x)|)) - lgamma(-x); + * Note: one should avoid compute pi*(-x) directly in the + * computation of sin(pi*(-x)). + * + * 5. Special Cases + * lgamma(2+s) ~ s*(1-Euler) for tiny s + * lgamma(1) = lgamma(2) = 0 + * lgamma(x) ~ -log(|x|) for tiny x + * lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero + * lgamma(inf) = inf + * lgamma(-inf) = inf (bug for bug compatible with C99!?) + * + */ + +#include "libm.h" + +static const double +pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */ +a0 = 7.72156649015328655494e-02, /* 0x3FB3C467, 0xE37DB0C8 */ +a1 = 3.22467033424113591611e-01, /* 0x3FD4A34C, 0xC4A60FAD */ +a2 = 6.73523010531292681824e-02, /* 0x3FB13E00, 0x1A5562A7 */ +a3 = 2.05808084325167332806e-02, /* 0x3F951322, 0xAC92547B */ +a4 = 7.38555086081402883957e-03, /* 0x3F7E404F, 0xB68FEFE8 */ +a5 = 2.89051383673415629091e-03, /* 0x3F67ADD8, 0xCCB7926B */ +a6 = 1.19270763183362067845e-03, /* 0x3F538A94, 0x116F3F5D */ +a7 = 5.10069792153511336608e-04, /* 0x3F40B6C6, 0x89B99C00 */ +a8 = 2.20862790713908385557e-04, /* 0x3F2CF2EC, 0xED10E54D */ +a9 = 1.08011567247583939954e-04, /* 0x3F1C5088, 0x987DFB07 */ +a10 = 2.52144565451257326939e-05, /* 0x3EFA7074, 0x428CFA52 */ +a11 = 4.48640949618915160150e-05, /* 0x3F07858E, 0x90A45837 */ +tc = 1.46163214496836224576e+00, /* 0x3FF762D8, 0x6356BE3F */ +tf = -1.21486290535849611461e-01, /* 0xBFBF19B9, 0xBCC38A42 */ +/* tt = -(tail of tf) */ +tt = -3.63867699703950536541e-18, /* 0xBC50C7CA, 0xA48A971F */ +t0 = 4.83836122723810047042e-01, /* 0x3FDEF72B, 0xC8EE38A2 */ +t1 = -1.47587722994593911752e-01, /* 0xBFC2E427, 0x8DC6C509 */ +t2 = 6.46249402391333854778e-02, /* 0x3FB08B42, 0x94D5419B */ +t3 = -3.27885410759859649565e-02, /* 0xBFA0C9A8, 0xDF35B713 */ +t4 = 1.79706750811820387126e-02, /* 0x3F9266E7, 0x970AF9EC */ +t5 = -1.03142241298341437450e-02, /* 0xBF851F9F, 0xBA91EC6A */ +t6 = 6.10053870246291332635e-03, /* 0x3F78FCE0, 0xE370E344 */ +t7 = -3.68452016781138256760e-03, /* 0xBF6E2EFF, 0xB3E914D7 */ +t8 = 2.25964780900612472250e-03, /* 0x3F6282D3, 0x2E15C915 */ +t9 = -1.40346469989232843813e-03, /* 0xBF56FE8E, 0xBF2D1AF1 */ +t10 = 8.81081882437654011382e-04, /* 0x3F4CDF0C, 0xEF61A8E9 */ +t11 = -5.38595305356740546715e-04, /* 0xBF41A610, 0x9C73E0EC */ +t12 = 3.15632070903625950361e-04, /* 0x3F34AF6D, 0x6C0EBBF7 */ +t13 = -3.12754168375120860518e-04, /* 0xBF347F24, 0xECC38C38 */ +t14 = 3.35529192635519073543e-04, /* 0x3F35FD3E, 0xE8C2D3F4 */ +u0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */ +u1 = 6.32827064025093366517e-01, /* 0x3FE4401E, 0x8B005DFF */ +u2 = 1.45492250137234768737e+00, /* 0x3FF7475C, 0xD119BD6F */ +u3 = 9.77717527963372745603e-01, /* 0x3FEF4976, 0x44EA8450 */ +u4 = 2.28963728064692451092e-01, /* 0x3FCD4EAE, 0xF6010924 */ +u5 = 1.33810918536787660377e-02, /* 0x3F8B678B, 0xBF2BAB09 */ +v1 = 2.45597793713041134822e+00, /* 0x4003A5D7, 0xC2BD619C */ +v2 = 2.12848976379893395361e+00, /* 0x40010725, 0xA42B18F5 */ +v3 = 7.69285150456672783825e-01, /* 0x3FE89DFB, 0xE45050AF */ +v4 = 1.04222645593369134254e-01, /* 0x3FBAAE55, 0xD6537C88 */ +v5 = 3.21709242282423911810e-03, /* 0x3F6A5ABB, 0x57D0CF61 */ +s0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */ +s1 = 2.14982415960608852501e-01, /* 0x3FCB848B, 0x36E20878 */ +s2 = 3.25778796408930981787e-01, /* 0x3FD4D98F, 0x4F139F59 */ +s3 = 1.46350472652464452805e-01, /* 0x3FC2BB9C, 0xBEE5F2F7 */ +s4 = 2.66422703033638609560e-02, /* 0x3F9B481C, 0x7E939961 */ +s5 = 1.84028451407337715652e-03, /* 0x3F5E26B6, 0x7368F239 */ +s6 = 3.19475326584100867617e-05, /* 0x3F00BFEC, 0xDD17E945 */ +r1 = 1.39200533467621045958e+00, /* 0x3FF645A7, 0x62C4AB74 */ +r2 = 7.21935547567138069525e-01, /* 0x3FE71A18, 0x93D3DCDC */ +r3 = 1.71933865632803078993e-01, /* 0x3FC601ED, 0xCCFBDF27 */ +r4 = 1.86459191715652901344e-02, /* 0x3F9317EA, 0x742ED475 */ +r5 = 7.77942496381893596434e-04, /* 0x3F497DDA, 0xCA41A95B */ +r6 = 7.32668430744625636189e-06, /* 0x3EDEBAF7, 0xA5B38140 */ +w0 = 4.18938533204672725052e-01, /* 0x3FDACFE3, 0x90C97D69 */ +w1 = 8.33333333333329678849e-02, /* 0x3FB55555, 0x5555553B */ +w2 = -2.77777777728775536470e-03, /* 0xBF66C16C, 0x16B02E5C */ +w3 = 7.93650558643019558500e-04, /* 0x3F4A019F, 0x98CF38B6 */ +w4 = -5.95187557450339963135e-04, /* 0xBF4380CB, 0x8C0FE741 */ +w5 = 8.36339918996282139126e-04, /* 0x3F4B67BA, 0x4CDAD5D1 */ +w6 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ + +/* sin(pi*x) assuming x > 2^-100, if sin(pi*x)==0 the sign is arbitrary */ +static double sin_pi(double x) +{ + int n; + + /* spurious inexact if odd int */ + x = 2.0*(x*0.5 - floor(x*0.5)); /* x mod 2.0 */ + + n = (int)(x*4.0); + n = (n+1)/2; + x -= n*0.5f; + x *= pi; + + switch (n) { + default: /* case 4: */ + case 0: return __sin(x, 0.0, 0); + case 1: return __cos(x, 0.0); + case 2: return __sin(-x, 0.0, 0); + case 3: return -__cos(x, 0.0); + } +} + +double __lgamma_r(double x, int *signgamp) +{ + union {double f; uint64_t i;} u = {x}; + double_t t,y,z,nadj,p,p1,p2,p3,q,r,w; + uint32_t ix; + int sign,i; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + *signgamp = 1; + sign = u.i>>63; + ix = u.i>>32 & 0x7fffffff; + if (ix >= 0x7ff00000) + return x*x; + if (ix < (0x3ff-70)<<20) { /* |x|<2**-70, return -log(|x|) */ + if(sign) { + x = -x; + *signgamp = -1; + } + return -log(x); + } + if (sign) { + x = -x; + t = sin_pi(x); + if (t == 0.0) /* -integer */ + return 1.0/(x-x); + if (t > 0.0) + *signgamp = -1; + else + t = -t; + nadj = log(pi/(t*x)); + } + + /* purge off 1 and 2 */ + if ((ix == 0x3ff00000 || ix == 0x40000000) && (uint32_t)u.i == 0) + r = 0; + /* for x < 2.0 */ + else if (ix < 0x40000000) { + if (ix <= 0x3feccccc) { /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -log(x); + if (ix >= 0x3FE76944) { + y = 1.0 - x; + i = 0; + } else if (ix >= 0x3FCDA661) { + y = x - (tc-1.0); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0; + if (ix >= 0x3FFBB4C3) { /* [1.7316,2] */ + y = 2.0 - x; + i = 0; + } else if(ix >= 0x3FF3B4C4) { /* [1.23,1.73] */ + y = x - tc; + i = 1; + } else { + y = x - 1.0; + i = 2; + } + } + switch (i) { + case 0: + z = y*y; + p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10)))); + p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11))))); + p = y*p1+p2; + r += (p-0.5*y); + break; + case 1: + z = y*y; + w = z*y; + p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12))); /* parallel comp */ + p2 = t1+w*(t4+w*(t7+w*(t10+w*t13))); + p3 = t2+w*(t5+w*(t8+w*(t11+w*t14))); + p = z*p1-(tt-w*(p2+y*p3)); + r += tf + p; + break; + case 2: + p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5))))); + p2 = 1.0+y*(v1+y*(v2+y*(v3+y*(v4+y*v5)))); + r += -0.5*y + p1/p2; + } + } else if (ix < 0x40200000) { /* x < 8.0 */ + i = (int)x; + y = x - (double)i; + p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6)))))); + q = 1.0+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6))))); + r = 0.5*y+p/q; + z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ + switch (i) { + case 7: z *= y + 6.0; /* FALLTHRU */ + case 6: z *= y + 5.0; /* FALLTHRU */ + case 5: z *= y + 4.0; /* FALLTHRU */ + case 4: z *= y + 3.0; /* FALLTHRU */ + case 3: z *= y + 2.0; /* FALLTHRU */ + r += log(z); + break; + } + } else if (ix < 0x43900000) { /* 8.0 <= x < 2**58 */ + t = log(x); + z = 1.0/x; + y = z*z; + w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6))))); + r = (x-0.5)*(t-1.0)+w; + } else /* 2**58 <= x <= inf */ + r = x*(log(x)-1.0); + if (sign) + r = nadj - r; + return r; +} + +weak_alias(__lgamma_r, lgamma_r); diff --git a/src/orca-libc/src/math/lgammaf.c b/src/orca-libc/src/math/lgammaf.c new file mode 100644 index 00000000..2ae051d0 --- /dev/null +++ b/src/orca-libc/src/math/lgammaf.c @@ -0,0 +1,7 @@ +#include +#include "libm.h" + +float lgammaf(float x) +{ + return __lgammaf_r(x, &__signgam); +} diff --git a/src/orca-libc/src/math/lgammaf_r.c b/src/orca-libc/src/math/lgammaf_r.c new file mode 100644 index 00000000..3f353f19 --- /dev/null +++ b/src/orca-libc/src/math/lgammaf_r.c @@ -0,0 +1,218 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgammaf_r.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float +pi = 3.1415927410e+00, /* 0x40490fdb */ +a0 = 7.7215664089e-02, /* 0x3d9e233f */ +a1 = 3.2246702909e-01, /* 0x3ea51a66 */ +a2 = 6.7352302372e-02, /* 0x3d89f001 */ +a3 = 2.0580807701e-02, /* 0x3ca89915 */ +a4 = 7.3855509982e-03, /* 0x3bf2027e */ +a5 = 2.8905137442e-03, /* 0x3b3d6ec6 */ +a6 = 1.1927076848e-03, /* 0x3a9c54a1 */ +a7 = 5.1006977446e-04, /* 0x3a05b634 */ +a8 = 2.2086278477e-04, /* 0x39679767 */ +a9 = 1.0801156895e-04, /* 0x38e28445 */ +a10 = 2.5214456400e-05, /* 0x37d383a2 */ +a11 = 4.4864096708e-05, /* 0x383c2c75 */ +tc = 1.4616321325e+00, /* 0x3fbb16c3 */ +tf = -1.2148628384e-01, /* 0xbdf8cdcd */ +/* tt = -(tail of tf) */ +tt = 6.6971006518e-09, /* 0x31e61c52 */ +t0 = 4.8383611441e-01, /* 0x3ef7b95e */ +t1 = -1.4758771658e-01, /* 0xbe17213c */ +t2 = 6.4624942839e-02, /* 0x3d845a15 */ +t3 = -3.2788541168e-02, /* 0xbd064d47 */ +t4 = 1.7970675603e-02, /* 0x3c93373d */ +t5 = -1.0314224288e-02, /* 0xbc28fcfe */ +t6 = 6.1005386524e-03, /* 0x3bc7e707 */ +t7 = -3.6845202558e-03, /* 0xbb7177fe */ +t8 = 2.2596477065e-03, /* 0x3b141699 */ +t9 = -1.4034647029e-03, /* 0xbab7f476 */ +t10 = 8.8108185446e-04, /* 0x3a66f867 */ +t11 = -5.3859531181e-04, /* 0xba0d3085 */ +t12 = 3.1563205994e-04, /* 0x39a57b6b */ +t13 = -3.1275415677e-04, /* 0xb9a3f927 */ +t14 = 3.3552918467e-04, /* 0x39afe9f7 */ +u0 = -7.7215664089e-02, /* 0xbd9e233f */ +u1 = 6.3282704353e-01, /* 0x3f2200f4 */ +u2 = 1.4549225569e+00, /* 0x3fba3ae7 */ +u3 = 9.7771751881e-01, /* 0x3f7a4bb2 */ +u4 = 2.2896373272e-01, /* 0x3e6a7578 */ +u5 = 1.3381091878e-02, /* 0x3c5b3c5e */ +v1 = 2.4559779167e+00, /* 0x401d2ebe */ +v2 = 2.1284897327e+00, /* 0x4008392d */ +v3 = 7.6928514242e-01, /* 0x3f44efdf */ +v4 = 1.0422264785e-01, /* 0x3dd572af */ +v5 = 3.2170924824e-03, /* 0x3b52d5db */ +s0 = -7.7215664089e-02, /* 0xbd9e233f */ +s1 = 2.1498242021e-01, /* 0x3e5c245a */ +s2 = 3.2577878237e-01, /* 0x3ea6cc7a */ +s3 = 1.4635047317e-01, /* 0x3e15dce6 */ +s4 = 2.6642270386e-02, /* 0x3cda40e4 */ +s5 = 1.8402845599e-03, /* 0x3af135b4 */ +s6 = 3.1947532989e-05, /* 0x3805ff67 */ +r1 = 1.3920053244e+00, /* 0x3fb22d3b */ +r2 = 7.2193557024e-01, /* 0x3f38d0c5 */ +r3 = 1.7193385959e-01, /* 0x3e300f6e */ +r4 = 1.8645919859e-02, /* 0x3c98bf54 */ +r5 = 7.7794247773e-04, /* 0x3a4beed6 */ +r6 = 7.3266842264e-06, /* 0x36f5d7bd */ +w0 = 4.1893854737e-01, /* 0x3ed67f1d */ +w1 = 8.3333335817e-02, /* 0x3daaaaab */ +w2 = -2.7777778450e-03, /* 0xbb360b61 */ +w3 = 7.9365057172e-04, /* 0x3a500cfd */ +w4 = -5.9518753551e-04, /* 0xba1c065c */ +w5 = 8.3633989561e-04, /* 0x3a5b3dd2 */ +w6 = -1.6309292987e-03; /* 0xbad5c4e8 */ + +/* sin(pi*x) assuming x > 2^-100, if sin(pi*x)==0 the sign is arbitrary */ +static float sin_pi(float x) +{ + double_t y; + int n; + + /* spurious inexact if odd int */ + x = 2*(x*0.5f - floorf(x*0.5f)); /* x mod 2.0 */ + + n = (int)(x*4); + n = (n+1)/2; + y = x - n*0.5f; + y *= 3.14159265358979323846; + switch (n) { + default: /* case 4: */ + case 0: return __sindf(y); + case 1: return __cosdf(y); + case 2: return __sindf(-y); + case 3: return -__cosdf(y); + } +} + +float __lgammaf_r(float x, int *signgamp) +{ + union {float f; uint32_t i;} u = {x}; + float t,y,z,nadj,p,p1,p2,p3,q,r,w; + uint32_t ix; + int i,sign; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + *signgamp = 1; + sign = u.i>>31; + ix = u.i & 0x7fffffff; + if (ix >= 0x7f800000) + return x*x; + if (ix < 0x35000000) { /* |x| < 2**-21, return -log(|x|) */ + if (sign) { + *signgamp = -1; + x = -x; + } + return -logf(x); + } + if (sign) { + x = -x; + t = sin_pi(x); + if (t == 0.0f) /* -integer */ + return 1.0f/(x-x); + if (t > 0.0f) + *signgamp = -1; + else + t = -t; + nadj = logf(pi/(t*x)); + } + + /* purge off 1 and 2 */ + if (ix == 0x3f800000 || ix == 0x40000000) + r = 0; + /* for x < 2.0 */ + else if (ix < 0x40000000) { + if (ix <= 0x3f666666) { /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -logf(x); + if (ix >= 0x3f3b4a20) { + y = 1.0f - x; + i = 0; + } else if (ix >= 0x3e6d3308) { + y = x - (tc-1.0f); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0f; + if (ix >= 0x3fdda618) { /* [1.7316,2] */ + y = 2.0f - x; + i = 0; + } else if (ix >= 0x3F9da620) { /* [1.23,1.73] */ + y = x - tc; + i = 1; + } else { + y = x - 1.0f; + i = 2; + } + } + switch(i) { + case 0: + z = y*y; + p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10)))); + p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11))))); + p = y*p1+p2; + r += p - 0.5f*y; + break; + case 1: + z = y*y; + w = z*y; + p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12))); /* parallel comp */ + p2 = t1+w*(t4+w*(t7+w*(t10+w*t13))); + p3 = t2+w*(t5+w*(t8+w*(t11+w*t14))); + p = z*p1-(tt-w*(p2+y*p3)); + r += (tf + p); + break; + case 2: + p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5))))); + p2 = 1.0f+y*(v1+y*(v2+y*(v3+y*(v4+y*v5)))); + r += -0.5f*y + p1/p2; + } + } else if (ix < 0x41000000) { /* x < 8.0 */ + i = (int)x; + y = x - (float)i; + p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6)))))); + q = 1.0f+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6))))); + r = 0.5f*y+p/q; + z = 1.0f; /* lgamma(1+s) = log(s) + lgamma(s) */ + switch (i) { + case 7: z *= y + 6.0f; /* FALLTHRU */ + case 6: z *= y + 5.0f; /* FALLTHRU */ + case 5: z *= y + 4.0f; /* FALLTHRU */ + case 4: z *= y + 3.0f; /* FALLTHRU */ + case 3: z *= y + 2.0f; /* FALLTHRU */ + r += logf(z); + break; + } + } else if (ix < 0x5c800000) { /* 8.0 <= x < 2**58 */ + t = logf(x); + z = 1.0f/x; + y = z*z; + w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6))))); + r = (x-0.5f)*(t-1.0f)+w; + } else /* 2**58 <= x <= inf */ + r = x*(logf(x)-1.0f); + if (sign) + r = nadj - r; + return r; +} + +weak_alias(__lgammaf_r, lgammaf_r); diff --git a/src/orca-libc/src/math/lgammal.c b/src/orca-libc/src/math/lgammal.c new file mode 100644 index 00000000..abbd4fc6 --- /dev/null +++ b/src/orca-libc/src/math/lgammal.c @@ -0,0 +1,353 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_lgammal.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* lgammal(x) + * Reentrant version of the logarithm of the Gamma function + * with user provide pointer for the sign of Gamma(x). + * + * Method: + * 1. Argument Reduction for 0 < x <= 8 + * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may + * reduce x to a number in [1.5,2.5] by + * lgamma(1+s) = log(s) + lgamma(s) + * for example, + * lgamma(7.3) = log(6.3) + lgamma(6.3) + * = log(6.3*5.3) + lgamma(5.3) + * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) + * 2. Polynomial approximation of lgamma around its + * minimun ymin=1.461632144968362245 to maintain monotonicity. + * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use + * Let z = x-ymin; + * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) + * 2. Rational approximation in the primary interval [2,3] + * We use the following approximation: + * s = x-2.0; + * lgamma(x) = 0.5*s + s*P(s)/Q(s) + * Our algorithms are based on the following observation + * + * zeta(2)-1 2 zeta(3)-1 3 + * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... + * 2 3 + * + * where Euler = 0.5771... is the Euler constant, which is very + * close to 0.5. + * + * 3. For x>=8, we have + * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... + * (better formula: + * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) + * Let z = 1/x, then we approximation + * f(z) = lgamma(x) - (x-0.5)(log(x)-1) + * by + * 3 5 11 + * w = w0 + w1*z + w2*z + w3*z + ... + w6*z + * + * 4. For negative x, since (G is gamma function) + * -x*G(-x)*G(x) = pi/sin(pi*x), + * we have + * G(x) = pi/(sin(pi*x)*(-x)*G(-x)) + * since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0 + * Hence, for x<0, signgam = sign(sin(pi*x)) and + * lgamma(x) = log(|Gamma(x)|) + * = log(pi/(|x*sin(pi*x)|)) - lgamma(-x); + * Note: one should avoid compute pi*(-x) directly in the + * computation of sin(pi*(-x)). + * + * 5. Special Cases + * lgamma(2+s) ~ s*(1-Euler) for tiny s + * lgamma(1)=lgamma(2)=0 + * lgamma(x) ~ -log(x) for tiny x + * lgamma(0) = lgamma(inf) = inf + * lgamma(-integer) = +-inf + * + */ + +#define _GNU_SOURCE +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double __lgammal_r(long double x, int *sg) +{ + return __lgamma_r(x, sg); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +static const long double +pi = 3.14159265358979323846264L, + +/* lgam(1+x) = 0.5 x + x a(x)/b(x) + -0.268402099609375 <= x <= 0 + peak relative error 6.6e-22 */ +a0 = -6.343246574721079391729402781192128239938E2L, +a1 = 1.856560238672465796768677717168371401378E3L, +a2 = 2.404733102163746263689288466865843408429E3L, +a3 = 8.804188795790383497379532868917517596322E2L, +a4 = 1.135361354097447729740103745999661157426E2L, +a5 = 3.766956539107615557608581581190400021285E0L, + +b0 = 8.214973713960928795704317259806842490498E3L, +b1 = 1.026343508841367384879065363925870888012E4L, +b2 = 4.553337477045763320522762343132210919277E3L, +b3 = 8.506975785032585797446253359230031874803E2L, +b4 = 6.042447899703295436820744186992189445813E1L, +/* b5 = 1.000000000000000000000000000000000000000E0 */ + + +tc = 1.4616321449683623412626595423257213284682E0L, +tf = -1.2148629053584961146050602565082954242826E-1, /* double precision */ +/* tt = (tail of tf), i.e. tf + tt has extended precision. */ +tt = 3.3649914684731379602768989080467587736363E-18L, +/* lgam ( 1.4616321449683623412626595423257213284682E0 ) = +-1.2148629053584960809551455717769158215135617312999903886372437313313530E-1 */ + +/* lgam (x + tc) = tf + tt + x g(x)/h(x) + -0.230003726999612341262659542325721328468 <= x + <= 0.2699962730003876587373404576742786715318 + peak relative error 2.1e-21 */ +g0 = 3.645529916721223331888305293534095553827E-18L, +g1 = 5.126654642791082497002594216163574795690E3L, +g2 = 8.828603575854624811911631336122070070327E3L, +g3 = 5.464186426932117031234820886525701595203E3L, +g4 = 1.455427403530884193180776558102868592293E3L, +g5 = 1.541735456969245924860307497029155838446E2L, +g6 = 4.335498275274822298341872707453445815118E0L, + +h0 = 1.059584930106085509696730443974495979641E4L, +h1 = 2.147921653490043010629481226937850618860E4L, +h2 = 1.643014770044524804175197151958100656728E4L, +h3 = 5.869021995186925517228323497501767586078E3L, +h4 = 9.764244777714344488787381271643502742293E2L, +h5 = 6.442485441570592541741092969581997002349E1L, +/* h6 = 1.000000000000000000000000000000000000000E0 */ + + +/* lgam (x+1) = -0.5 x + x u(x)/v(x) + -0.100006103515625 <= x <= 0.231639862060546875 + peak relative error 1.3e-21 */ +u0 = -8.886217500092090678492242071879342025627E1L, +u1 = 6.840109978129177639438792958320783599310E2L, +u2 = 2.042626104514127267855588786511809932433E3L, +u3 = 1.911723903442667422201651063009856064275E3L, +u4 = 7.447065275665887457628865263491667767695E2L, +u5 = 1.132256494121790736268471016493103952637E2L, +u6 = 4.484398885516614191003094714505960972894E0L, + +v0 = 1.150830924194461522996462401210374632929E3L, +v1 = 3.399692260848747447377972081399737098610E3L, +v2 = 3.786631705644460255229513563657226008015E3L, +v3 = 1.966450123004478374557778781564114347876E3L, +v4 = 4.741359068914069299837355438370682773122E2L, +v5 = 4.508989649747184050907206782117647852364E1L, +/* v6 = 1.000000000000000000000000000000000000000E0 */ + + +/* lgam (x+2) = .5 x + x s(x)/r(x) + 0 <= x <= 1 + peak relative error 7.2e-22 */ +s0 = 1.454726263410661942989109455292824853344E6L, +s1 = -3.901428390086348447890408306153378922752E6L, +s2 = -6.573568698209374121847873064292963089438E6L, +s3 = -3.319055881485044417245964508099095984643E6L, +s4 = -7.094891568758439227560184618114707107977E5L, +s5 = -6.263426646464505837422314539808112478303E4L, +s6 = -1.684926520999477529949915657519454051529E3L, + +r0 = -1.883978160734303518163008696712983134698E7L, +r1 = -2.815206082812062064902202753264922306830E7L, +r2 = -1.600245495251915899081846093343626358398E7L, +r3 = -4.310526301881305003489257052083370058799E6L, +r4 = -5.563807682263923279438235987186184968542E5L, +r5 = -3.027734654434169996032905158145259713083E4L, +r6 = -4.501995652861105629217250715790764371267E2L, +/* r6 = 1.000000000000000000000000000000000000000E0 */ + + +/* lgam(x) = ( x - 0.5 ) * log(x) - x + LS2PI + 1/x w(1/x^2) + x >= 8 + Peak relative error 1.51e-21 +w0 = LS2PI - 0.5 */ +w0 = 4.189385332046727417803e-1L, +w1 = 8.333333333333331447505E-2L, +w2 = -2.777777777750349603440E-3L, +w3 = 7.936507795855070755671E-4L, +w4 = -5.952345851765688514613E-4L, +w5 = 8.412723297322498080632E-4L, +w6 = -1.880801938119376907179E-3L, +w7 = 4.885026142432270781165E-3L; + +/* sin(pi*x) assuming x > 2^-1000, if sin(pi*x)==0 the sign is arbitrary */ +static long double sin_pi(long double x) +{ + int n; + + /* spurious inexact if odd int */ + x *= 0.5; + x = 2.0*(x - floorl(x)); /* x mod 2.0 */ + + n = (int)(x*4.0); + n = (n+1)/2; + x -= n*0.5f; + x *= pi; + + switch (n) { + default: /* case 4: */ + case 0: return __sinl(x, 0.0, 0); + case 1: return __cosl(x, 0.0); + case 2: return __sinl(-x, 0.0, 0); + case 3: return -__cosl(x, 0.0); + } +} + +long double __lgammal_r(long double x, int *sg) { + long double t, y, z, nadj, p, p1, p2, q, r, w; + union ldshape u = {x}; + uint32_t ix = (u.i.se & 0x7fffU)<<16 | u.i.m>>48; + int sign = u.i.se >> 15; + int i; + + *sg = 1; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + if (ix >= 0x7fff0000) + return x * x; + if (ix < 0x3fc08000) { /* |x|<2**-63, return -log(|x|) */ + if (sign) { + *sg = -1; + x = -x; + } + return -logl(x); + } + if (sign) { + x = -x; + t = sin_pi(x); + if (t == 0.0) + return 1.0 / (x-x); /* -integer */ + if (t > 0.0) + *sg = -1; + else + t = -t; + nadj = logl(pi / (t * x)); + } + + /* purge off 1 and 2 (so the sign is ok with downward rounding) */ + if ((ix == 0x3fff8000 || ix == 0x40008000) && u.i.m == 0) { + r = 0; + } else if (ix < 0x40008000) { /* x < 2.0 */ + if (ix <= 0x3ffee666) { /* 8.99993896484375e-1 */ + /* lgamma(x) = lgamma(x+1) - log(x) */ + r = -logl(x); + if (ix >= 0x3ffebb4a) { /* 7.31597900390625e-1 */ + y = x - 1.0; + i = 0; + } else if (ix >= 0x3ffced33) { /* 2.31639862060546875e-1 */ + y = x - (tc - 1.0); + i = 1; + } else { /* x < 0.23 */ + y = x; + i = 2; + } + } else { + r = 0.0; + if (ix >= 0x3fffdda6) { /* 1.73162841796875 */ + /* [1.7316,2] */ + y = x - 2.0; + i = 0; + } else if (ix >= 0x3fff9da6) { /* 1.23162841796875 */ + /* [1.23,1.73] */ + y = x - tc; + i = 1; + } else { + /* [0.9, 1.23] */ + y = x - 1.0; + i = 2; + } + } + switch (i) { + case 0: + p1 = a0 + y * (a1 + y * (a2 + y * (a3 + y * (a4 + y * a5)))); + p2 = b0 + y * (b1 + y * (b2 + y * (b3 + y * (b4 + y)))); + r += 0.5 * y + y * p1/p2; + break; + case 1: + p1 = g0 + y * (g1 + y * (g2 + y * (g3 + y * (g4 + y * (g5 + y * g6))))); + p2 = h0 + y * (h1 + y * (h2 + y * (h3 + y * (h4 + y * (h5 + y))))); + p = tt + y * p1/p2; + r += (tf + p); + break; + case 2: + p1 = y * (u0 + y * (u1 + y * (u2 + y * (u3 + y * (u4 + y * (u5 + y * u6)))))); + p2 = v0 + y * (v1 + y * (v2 + y * (v3 + y * (v4 + y * (v5 + y))))); + r += (-0.5 * y + p1 / p2); + } + } else if (ix < 0x40028000) { /* 8.0 */ + /* x < 8.0 */ + i = (int)x; + y = x - (double)i; + p = y * (s0 + y * (s1 + y * (s2 + y * (s3 + y * (s4 + y * (s5 + y * s6)))))); + q = r0 + y * (r1 + y * (r2 + y * (r3 + y * (r4 + y * (r5 + y * (r6 + y)))))); + r = 0.5 * y + p / q; + z = 1.0; + /* lgamma(1+s) = log(s) + lgamma(s) */ + switch (i) { + case 7: + z *= (y + 6.0); /* FALLTHRU */ + case 6: + z *= (y + 5.0); /* FALLTHRU */ + case 5: + z *= (y + 4.0); /* FALLTHRU */ + case 4: + z *= (y + 3.0); /* FALLTHRU */ + case 3: + z *= (y + 2.0); /* FALLTHRU */ + r += logl(z); + break; + } + } else if (ix < 0x40418000) { /* 2^66 */ + /* 8.0 <= x < 2**66 */ + t = logl(x); + z = 1.0 / x; + y = z * z; + w = w0 + z * (w1 + y * (w2 + y * (w3 + y * (w4 + y * (w5 + y * (w6 + y * w7)))))); + r = (x - 0.5) * (t - 1.0) + w; + } else /* 2**66 <= x <= inf */ + r = x * (logl(x) - 1.0); + if (sign) + r = nadj - r; + return r; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double __lgammal_r(long double x, int *sg) +{ + return __lgamma_r(x, sg); +} +#endif + +long double lgammal(long double x) +{ + return __lgammal_r(x, &__signgam); +} + +weak_alias(__lgammal_r, lgammal_r); diff --git a/src/orca-libc/src/math/llrint.c b/src/orca-libc/src/math/llrint.c new file mode 100644 index 00000000..4f583ae5 --- /dev/null +++ b/src/orca-libc/src/math/llrint.c @@ -0,0 +1,8 @@ +#include + +/* uses LLONG_MAX > 2^53, see comments in lrint.c */ + +long long llrint(double x) +{ + return rint(x); +} diff --git a/src/orca-libc/src/math/llrintf.c b/src/orca-libc/src/math/llrintf.c new file mode 100644 index 00000000..96949a00 --- /dev/null +++ b/src/orca-libc/src/math/llrintf.c @@ -0,0 +1,8 @@ +#include + +/* uses LLONG_MAX > 2^24, see comments in lrint.c */ + +long long llrintf(float x) +{ + return rintf(x); +} diff --git a/src/orca-libc/src/math/llrintl.c b/src/orca-libc/src/math/llrintl.c new file mode 100644 index 00000000..3449f6f2 --- /dev/null +++ b/src/orca-libc/src/math/llrintl.c @@ -0,0 +1,36 @@ +#include +#include +#include "libm.h" + + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long long llrintl(long double x) +{ + return llrint(x); +} +#elif defined(FE_INEXACT) +/* +see comments in lrint.c + +Note that if LLONG_MAX == 0x7fffffffffffffff && LDBL_MANT_DIG == 64 +then x == 2**63 - 0.5 is the only input that overflows and +raises inexact (with tonearest or upward rounding mode) +*/ +long long llrintl(long double x) +{ + #pragma STDC FENV_ACCESS ON + int e; + + e = fetestexcept(FE_INEXACT); + x = rintl(x); + if (!e && (x > LLONG_MAX || x < LLONG_MIN)) + feclearexcept(FE_INEXACT); + /* conversion */ + return x; +} +#else +long long llrintl(long double x) +{ + return rintl(x); +} +#endif diff --git a/src/orca-libc/src/math/llround.c b/src/orca-libc/src/math/llround.c new file mode 100644 index 00000000..4d94787d --- /dev/null +++ b/src/orca-libc/src/math/llround.c @@ -0,0 +1,6 @@ +#include + +long long llround(double x) +{ + return round(x); +} diff --git a/src/orca-libc/src/math/llroundf.c b/src/orca-libc/src/math/llroundf.c new file mode 100644 index 00000000..19eb77ee --- /dev/null +++ b/src/orca-libc/src/math/llroundf.c @@ -0,0 +1,6 @@ +#include + +long long llroundf(float x) +{ + return roundf(x); +} diff --git a/src/orca-libc/src/math/llroundl.c b/src/orca-libc/src/math/llroundl.c new file mode 100644 index 00000000..2c2ee5ec --- /dev/null +++ b/src/orca-libc/src/math/llroundl.c @@ -0,0 +1,6 @@ +#include + +long long llroundl(long double x) +{ + return roundl(x); +} diff --git a/src/libc-shim/src/log.c b/src/orca-libc/src/math/log.c similarity index 100% rename from src/libc-shim/src/log.c rename to src/orca-libc/src/math/log.c diff --git a/src/orca-libc/src/math/log10.c b/src/orca-libc/src/math/log10.c new file mode 100644 index 00000000..81026876 --- /dev/null +++ b/src/orca-libc/src/math/log10.c @@ -0,0 +1,101 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log10.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Return the base 10 logarithm of x. See log.c for most comments. + * + * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 + * as in log.c, then combine and scale in extra precision: + * log10(x) = (f - f*f/2 + r)/log(10) + k*log10(2) + */ + +#include +#include + +static const double +ivln10hi = 4.34294481878168880939e-01, /* 0x3fdbcb7b, 0x15200000 */ +ivln10lo = 2.50829467116452752298e-11, /* 0x3dbb9438, 0xca9aadd5 */ +log10_2hi = 3.01029995663611771306e-01, /* 0x3FD34413, 0x509F6000 */ +log10_2lo = 3.69423907715893078616e-13, /* 0x3D59FEF3, 0x11F12B36 */ +Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ +Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ +Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ +Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ +Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ +Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ +Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +double log10(double x) +{ + union {double f; uint64_t i;} u = {x}; + double_t hfsq,f,s,z,R,w,t1,t2,dk,y,hi,lo,val_hi,val_lo; + uint32_t hx; + int k; + + hx = u.i>>32; + k = 0; + if (hx < 0x00100000 || hx>>31) { + if (u.i<<1 == 0) + return -1/(x*x); /* log(+-0)=-inf */ + if (hx>>31) + return (x-x)/0.0; /* log(-#) = NaN */ + /* subnormal number, scale x up */ + k -= 54; + x *= 0x1p54; + u.f = x; + hx = u.i>>32; + } else if (hx >= 0x7ff00000) { + return x; + } else if (hx == 0x3ff00000 && u.i<<32 == 0) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += (int)(hx>>20) - 0x3ff; + hx = (hx&0x000fffff) + 0x3fe6a09e; + u.i = (uint64_t)hx<<32 | (u.i&0xffffffff); + x = u.f; + + f = x - 1.0; + hfsq = 0.5*f*f; + s = f/(2.0+f); + z = s*s; + w = z*z; + t1 = w*(Lg2+w*(Lg4+w*Lg6)); + t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); + R = t2 + t1; + + /* See log2.c for details. */ + /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ + hi = f - hfsq; + u.f = hi; + u.i &= (uint64_t)-1<<32; + hi = u.f; + lo = f - hi - hfsq + s*(hfsq+R); + + /* val_hi+val_lo ~ log10(1+f) + k*log10(2) */ + val_hi = hi*ivln10hi; + dk = k; + y = dk*log10_2hi; + val_lo = dk*log10_2lo + (lo+hi)*ivln10lo + lo*ivln10hi; + + /* + * Extra precision in for adding y is not strictly needed + * since there is no very large cancellation near x = sqrt(2) or + * x = 1/sqrt(2), but we do it anyway since it costs little on CPUs + * with some parallelism and it reduces the error for many args. + */ + w = y + val_hi; + val_lo += (y - w) + val_hi; + val_hi = w; + + return val_lo + val_hi; +} diff --git a/src/orca-libc/src/math/log10f.c b/src/orca-libc/src/math/log10f.c new file mode 100644 index 00000000..9ca2f017 --- /dev/null +++ b/src/orca-libc/src/math/log10f.c @@ -0,0 +1,77 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log10f.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in log10.c. + */ + +#include +#include + +static const float +ivln10hi = 4.3432617188e-01, /* 0x3ede6000 */ +ivln10lo = -3.1689971365e-05, /* 0xb804ead9 */ +log10_2hi = 3.0102920532e-01, /* 0x3e9a2080 */ +log10_2lo = 7.9034151668e-07, /* 0x355427db */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */ +Lg2 = 0xccce13.0p-25, /* 0.40000972152 */ +Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */ +Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */ + +float log10f(float x) +{ + union {float f; uint32_t i;} u = {x}; + float_t hfsq,f,s,z,R,w,t1,t2,dk,hi,lo; + uint32_t ix; + int k; + + ix = u.i; + k = 0; + if (ix < 0x00800000 || ix>>31) { /* x < 2**-126 */ + if (ix<<1 == 0) + return -1/(x*x); /* log(+-0)=-inf */ + if (ix>>31) + return (x-x)/0.0f; /* log(-#) = NaN */ + /* subnormal number, scale up x */ + k -= 25; + x *= 0x1p25f; + u.f = x; + ix = u.i; + } else if (ix >= 0x7f800000) { + return x; + } else if (ix == 0x3f800000) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += (int)(ix>>23) - 0x7f; + ix = (ix&0x007fffff) + 0x3f3504f3; + u.i = ix; + x = u.f; + + f = x - 1.0f; + s = f/(2.0f + f); + z = s*s; + w = z*z; + t1= w*(Lg2+w*Lg4); + t2= z*(Lg1+w*Lg3); + R = t2 + t1; + hfsq = 0.5f*f*f; + + hi = f - hfsq; + u.f = hi; + u.i &= 0xfffff000; + hi = u.f; + lo = f - hi - hfsq + s*(hfsq+R); + dk = k; + return dk*log10_2lo + (lo+hi)*ivln10lo + lo*ivln10hi + hi*ivln10hi + dk*log10_2hi; +} diff --git a/src/orca-libc/src/math/log10l.c b/src/orca-libc/src/math/log10l.c new file mode 100644 index 00000000..63dcc286 --- /dev/null +++ b/src/orca-libc/src/math/log10l.c @@ -0,0 +1,191 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_log10l.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Common logarithm, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, log10l(); + * + * y = log10l( x ); + * + * + * DESCRIPTION: + * + * Returns the base 10 logarithm of x. + * + * The argument is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the logarithm + * of the fraction is approximated by + * + * log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/x+1), + * + * log(x) = z + z**3 P(z)/Q(z). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0.5, 2.0 30000 9.0e-20 2.6e-20 + * IEEE exp(+-10000) 30000 6.0e-20 2.3e-20 + * + * In the tests over the interval exp(+-10000), the logarithms + * of the random arguments were uniformly distributed over + * [-10000, +10000]. + * + * ERROR MESSAGES: + * + * log singularity: x = 0; returns MINLOG + * log domain: x < 0; returns MINLOG + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double log10l(long double x) +{ + return log10(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.2e-22 + */ +static const long double P[] = { + 4.9962495940332550844739E-1L, + 1.0767376367209449010438E1L, + 7.7671073698359539859595E1L, + 2.5620629828144409632571E2L, + 4.2401812743503691187826E2L, + 3.4258224542413922935104E2L, + 1.0747524399916215149070E2L, +}; +static const long double Q[] = { +/* 1.0000000000000000000000E0,*/ + 2.3479774160285863271658E1L, + 1.9444210022760132894510E2L, + 7.7952888181207260646090E2L, + 1.6911722418503949084863E3L, + 2.0307734695595183428202E3L, + 1.2695660352705325274404E3L, + 3.2242573199748645407652E2L, +}; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.16e-22 + */ +static const long double R[4] = { + 1.9757429581415468984296E-3L, +-7.1990767473014147232598E-1L, + 1.0777257190312272158094E1L, +-3.5717684488096787370998E1L, +}; +static const long double S[4] = { +/* 1.00000000000000000000E0L,*/ +-2.6201045551331104417768E1L, + 1.9361891836232102174846E2L, +-4.2861221385716144629696E2L, +}; +/* log10(2) */ +#define L102A 0.3125L +#define L102B -1.1470004336018804786261e-2L +/* log10(e) */ +#define L10EA 0.5L +#define L10EB -6.5705518096748172348871e-2L + +#define SQRTH 0.70710678118654752440L + +long double log10l(long double x) +{ + long double y, z; + int e; + + if (isnan(x)) + return x; + if(x <= 0.0) { + if(x == 0.0) + return -1.0 / (x*x); + return (x - x) / 0.0; + } + if (x == INFINITY) + return INFINITY; + /* separate mantissa from exponent */ + /* Note, frexp is used so that denormal numbers + * will be handled properly. + */ + x = frexpl(x, &e); + + /* logarithm using log(x) = z + z**3 P(z)/Q(z), + * where z = 2(x-1)/x+1) + */ + if (e > 2 || e < -2) { + if (x < SQRTH) { /* 2(2x-1)/(2x+1) */ + e -= 1; + z = x - 0.5; + y = 0.5 * z + 0.5; + } else { /* 2 (x-1)/(x+1) */ + z = x - 0.5; + z -= 0.5; + y = 0.5 * x + 0.5; + } + x = z / y; + z = x*x; + y = x * (z * __polevll(z, R, 3) / __p1evll(z, S, 3)); + goto done; + } + + /* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + if (x < SQRTH) { + e -= 1; + x = 2.0*x - 1.0; + } else { + x = x - 1.0; + } + z = x*x; + y = x * (z * __polevll(x, P, 6) / __p1evll(x, Q, 7)); + y = y - 0.5*z; + +done: + /* Multiply log of fraction by log10(e) + * and base 2 exponent by log10(2). + * + * ***CAUTION*** + * + * This sequence of operations is critical and it may + * be horribly defeated by some compiler optimizers. + */ + z = y * (L10EB); + z += x * (L10EB); + z += e * (L102B); + z += y * (L10EA); + z += x * (L10EA); + z += e * (L102A); + return z; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double log10l(long double x) +{ + return log10(x); +} +#endif diff --git a/src/orca-libc/src/math/log1p.c b/src/orca-libc/src/math/log1p.c new file mode 100644 index 00000000..00971349 --- /dev/null +++ b/src/orca-libc/src/math/log1p.c @@ -0,0 +1,122 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_log1p.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* double log1p(double x) + * Return the natural logarithm of 1+x. + * + * Method : + * 1. Argument Reduction: find k and f such that + * 1+x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * Note. If k=0, then f=x is exact. However, if k!=0, then f + * may not be representable exactly. In that case, a correction + * term is need. Let u=1+x rounded. Let c = (1+x)-u, then + * log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u), + * and add back the correction term c/u. + * (Note: when x > 2**53, one can simply return log(x)) + * + * 2. Approximation of log(1+f): See log.c + * + * 3. Finally, log1p(x) = k*ln2 + log(1+f) + c/u. See log.c + * + * Special cases: + * log1p(x) is NaN with signal if x < -1 (including -INF) ; + * log1p(+INF) is +INF; log1p(-1) is -INF with signal; + * log1p(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + * + * Note: Assuming log() return accurate answer, the following + * algorithm can be used to compute log1p(x) to within a few ULP: + * + * u = 1+x; + * if(u==1.0) return x ; else + * return log(u)*(x/(u-1.0)); + * + * See HP-15C Advanced Functions Handbook, p.193. + */ + +#include "libm.h" + +static const double +ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */ +ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */ +Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ +Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ +Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ +Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ +Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ +Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ +Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +double log1p(double x) +{ + union {double f; uint64_t i;} u = {x}; + double_t hfsq,f,c,s,z,R,w,t1,t2,dk; + uint32_t hx,hu; + int k; + + hx = u.i>>32; + k = 1; + if (hx < 0x3fda827a || hx>>31) { /* 1+x < sqrt(2)+ */ + if (hx >= 0xbff00000) { /* x <= -1.0 */ + if (x == -1) + return x/0.0; /* log1p(-1) = -inf */ + return (x-x)/0.0; /* log1p(x<-1) = NaN */ + } + if (hx<<1 < 0x3ca00000<<1) { /* |x| < 2**-53 */ + /* underflow if subnormal */ + if ((hx&0x7ff00000) == 0) + FORCE_EVAL((float)x); + return x; + } + if (hx <= 0xbfd2bec4) { /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + k = 0; + c = 0; + f = x; + } + } else if (hx >= 0x7ff00000) + return x; + if (k) { + u.f = 1 + x; + hu = u.i>>32; + hu += 0x3ff00000 - 0x3fe6a09e; + k = (int)(hu>>20) - 0x3ff; + /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ + if (k < 54) { + c = k >= 2 ? 1-(u.f-x) : x-(u.f-1); + c /= u.f; + } else + c = 0; + /* reduce u into [sqrt(2)/2, sqrt(2)] */ + hu = (hu&0x000fffff) + 0x3fe6a09e; + u.i = (uint64_t)hu<<32 | (u.i&0xffffffff); + f = u.f - 1; + } + hfsq = 0.5*f*f; + s = f/(2.0+f); + z = s*s; + w = z*z; + t1 = w*(Lg2+w*(Lg4+w*Lg6)); + t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); + R = t2 + t1; + dk = k; + return s*(hfsq+R) + (dk*ln2_lo+c) - hfsq + f + dk*ln2_hi; +} diff --git a/src/orca-libc/src/math/log1pf.c b/src/orca-libc/src/math/log1pf.c new file mode 100644 index 00000000..23985c35 --- /dev/null +++ b/src/orca-libc/src/math/log1pf.c @@ -0,0 +1,77 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_log1pf.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float +ln2_hi = 6.9313812256e-01, /* 0x3f317180 */ +ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */ +Lg2 = 0xccce13.0p-25, /* 0.40000972152 */ +Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */ +Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */ + +float log1pf(float x) +{ + union {float f; uint32_t i;} u = {x}; + float_t hfsq,f,c,s,z,R,w,t1,t2,dk; + uint32_t ix,iu; + int k; + + ix = u.i; + k = 1; + if (ix < 0x3ed413d0 || ix>>31) { /* 1+x < sqrt(2)+ */ + if (ix >= 0xbf800000) { /* x <= -1.0 */ + if (x == -1) + return x/0.0f; /* log1p(-1)=+inf */ + return (x-x)/0.0f; /* log1p(x<-1)=NaN */ + } + if (ix<<1 < 0x33800000<<1) { /* |x| < 2**-24 */ + /* underflow if subnormal */ + if ((ix&0x7f800000) == 0) + FORCE_EVAL(x*x); + return x; + } + if (ix <= 0xbe95f619) { /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + k = 0; + c = 0; + f = x; + } + } else if (ix >= 0x7f800000) + return x; + if (k) { + u.f = 1 + x; + iu = u.i; + iu += 0x3f800000 - 0x3f3504f3; + k = (int)(iu>>23) - 0x7f; + /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ + if (k < 25) { + c = k >= 2 ? 1-(u.f-x) : x-(u.f-1); + c /= u.f; + } else + c = 0; + /* reduce u into [sqrt(2)/2, sqrt(2)] */ + iu = (iu&0x007fffff) + 0x3f3504f3; + u.i = iu; + f = u.f - 1; + } + s = f/(2.0f + f); + z = s*s; + w = z*z; + t1= w*(Lg2+w*Lg4); + t2= z*(Lg1+w*Lg3); + R = t2 + t1; + hfsq = 0.5f*f*f; + dk = k; + return s*(hfsq+R) + (dk*ln2_lo+c) - hfsq + f + dk*ln2_hi; +} diff --git a/src/orca-libc/src/math/log1pl.c b/src/orca-libc/src/math/log1pl.c new file mode 100644 index 00000000..141b5f0b --- /dev/null +++ b/src/orca-libc/src/math/log1pl.c @@ -0,0 +1,177 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/s_log1pl.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Relative error logarithm + * Natural logarithm of 1+x, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, log1pl(); + * + * y = log1pl( x ); + * + * + * DESCRIPTION: + * + * Returns the base e (2.718...) logarithm of 1+x. + * + * The argument 1+x is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the logarithm + * of the fraction is approximated by + * + * log(1+x) = x - 0.5 x^2 + x^3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/x+1), + * + * log(x) = z + z^3 P(z)/Q(z). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -1.0, 9.0 100000 8.2e-20 2.5e-20 + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double log1pl(long double x) +{ + return log1p(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* Coefficients for log(1+x) = x - x^2 / 2 + x^3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 2.32e-20 + */ +static const long double P[] = { + 4.5270000862445199635215E-5L, + 4.9854102823193375972212E-1L, + 6.5787325942061044846969E0L, + 2.9911919328553073277375E1L, + 6.0949667980987787057556E1L, + 5.7112963590585538103336E1L, + 2.0039553499201281259648E1L, +}; +static const long double Q[] = { +/* 1.0000000000000000000000E0,*/ + 1.5062909083469192043167E1L, + 8.3047565967967209469434E1L, + 2.2176239823732856465394E2L, + 3.0909872225312059774938E2L, + 2.1642788614495947685003E2L, + 6.0118660497603843919306E1L, +}; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.16e-22 + */ +static const long double R[4] = { + 1.9757429581415468984296E-3L, +-7.1990767473014147232598E-1L, + 1.0777257190312272158094E1L, +-3.5717684488096787370998E1L, +}; +static const long double S[4] = { +/* 1.00000000000000000000E0L,*/ +-2.6201045551331104417768E1L, + 1.9361891836232102174846E2L, +-4.2861221385716144629696E2L, +}; +static const long double C1 = 6.9314575195312500000000E-1L; +static const long double C2 = 1.4286068203094172321215E-6L; + +#define SQRTH 0.70710678118654752440L + +long double log1pl(long double xm1) +{ + long double x, y, z; + int e; + + if (isnan(xm1)) + return xm1; + if (xm1 == INFINITY) + return xm1; + if (xm1 == 0.0) + return xm1; + + x = xm1 + 1.0; + + /* Test for domain errors. */ + if (x <= 0.0) { + if (x == 0.0) + return -1/(x*x); /* -inf with divbyzero */ + return 0/0.0f; /* nan with invalid */ + } + + /* Separate mantissa from exponent. + Use frexp so that denormal numbers will be handled properly. */ + x = frexpl(x, &e); + + /* logarithm using log(x) = z + z^3 P(z)/Q(z), + where z = 2(x-1)/x+1) */ + if (e > 2 || e < -2) { + if (x < SQRTH) { /* 2(2x-1)/(2x+1) */ + e -= 1; + z = x - 0.5; + y = 0.5 * z + 0.5; + } else { /* 2 (x-1)/(x+1) */ + z = x - 0.5; + z -= 0.5; + y = 0.5 * x + 0.5; + } + x = z / y; + z = x*x; + z = x * (z * __polevll(z, R, 3) / __p1evll(z, S, 3)); + z = z + e * C2; + z = z + x; + z = z + e * C1; + return z; + } + + /* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + if (x < SQRTH) { + e -= 1; + if (e != 0) + x = 2.0 * x - 1.0; + else + x = xm1; + } else { + if (e != 0) + x = x - 1.0; + else + x = xm1; + } + z = x*x; + y = x * (z * __polevll(x, P, 6) / __p1evll(x, Q, 6)); + y = y + e * C2; + z = y - 0.5 * z; + z = z + x; + z = z + e * C1; + return z; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double log1pl(long double x) +{ + return log1p(x); +} +#endif diff --git a/src/libc-shim/src/log2.c b/src/orca-libc/src/math/log2.c similarity index 100% rename from src/libc-shim/src/log2.c rename to src/orca-libc/src/math/log2.c diff --git a/src/libc-shim/src/log2_data.c b/src/orca-libc/src/math/log2_data.c similarity index 100% rename from src/libc-shim/src/log2_data.c rename to src/orca-libc/src/math/log2_data.c diff --git a/src/libc-shim/src/log2_data.h b/src/orca-libc/src/math/log2_data.h similarity index 92% rename from src/libc-shim/src/log2_data.h rename to src/orca-libc/src/math/log2_data.h index 5ac3ac40..276a786d 100644 --- a/src/libc-shim/src/log2_data.h +++ b/src/orca-libc/src/math/log2_data.h @@ -10,7 +10,7 @@ #define LOG2_TABLE_BITS 6 #define LOG2_POLY_ORDER 7 #define LOG2_POLY1_ORDER 11 -extern const struct log2_data { +extern hidden const struct log2_data { double invln2hi; double invln2lo; double poly[LOG2_POLY_ORDER - 1]; diff --git a/src/libc-shim/src/log2f.c b/src/orca-libc/src/math/log2f.c similarity index 100% rename from src/libc-shim/src/log2f.c rename to src/orca-libc/src/math/log2f.c diff --git a/src/libc-shim/src/log2f_data.c b/src/orca-libc/src/math/log2f_data.c similarity index 100% rename from src/libc-shim/src/log2f_data.c rename to src/orca-libc/src/math/log2f_data.c diff --git a/src/libc-shim/src/log2f_data.h b/src/orca-libc/src/math/log2f_data.h similarity index 88% rename from src/libc-shim/src/log2f_data.h rename to src/orca-libc/src/math/log2f_data.h index a173563a..4fa48956 100644 --- a/src/libc-shim/src/log2f_data.h +++ b/src/orca-libc/src/math/log2f_data.h @@ -9,7 +9,7 @@ #define LOG2F_TABLE_BITS 4 #define LOG2F_POLY_ORDER 4 -extern const struct log2f_data { +extern hidden const struct log2f_data { struct { double invc, logc; } tab[1 << LOG2F_TABLE_BITS]; diff --git a/src/orca-libc/src/math/log2l.c b/src/orca-libc/src/math/log2l.c new file mode 100644 index 00000000..722b451a --- /dev/null +++ b/src/orca-libc/src/math/log2l.c @@ -0,0 +1,182 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_log2l.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Base 2 logarithm, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, log2l(); + * + * y = log2l( x ); + * + * + * DESCRIPTION: + * + * Returns the base 2 logarithm of x. + * + * The argument is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the (natural) + * logarithm of the fraction is approximated by + * + * log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/x+1), + * + * log(x) = z + z**3 P(z)/Q(z). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0.5, 2.0 30000 9.8e-20 2.7e-20 + * IEEE exp(+-10000) 70000 5.4e-20 2.3e-20 + * + * In the tests over the interval exp(+-10000), the logarithms + * of the random arguments were uniformly distributed over + * [-10000, +10000]. + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double log2l(long double x) +{ + return log2(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* Coefficients for ln(1+x) = x - x**2/2 + x**3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.2e-22 + */ +static const long double P[] = { + 4.9962495940332550844739E-1L, + 1.0767376367209449010438E1L, + 7.7671073698359539859595E1L, + 2.5620629828144409632571E2L, + 4.2401812743503691187826E2L, + 3.4258224542413922935104E2L, + 1.0747524399916215149070E2L, +}; +static const long double Q[] = { +/* 1.0000000000000000000000E0,*/ + 2.3479774160285863271658E1L, + 1.9444210022760132894510E2L, + 7.7952888181207260646090E2L, + 1.6911722418503949084863E3L, + 2.0307734695595183428202E3L, + 1.2695660352705325274404E3L, + 3.2242573199748645407652E2L, +}; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.16e-22 + */ +static const long double R[4] = { + 1.9757429581415468984296E-3L, +-7.1990767473014147232598E-1L, + 1.0777257190312272158094E1L, +-3.5717684488096787370998E1L, +}; +static const long double S[4] = { +/* 1.00000000000000000000E0L,*/ +-2.6201045551331104417768E1L, + 1.9361891836232102174846E2L, +-4.2861221385716144629696E2L, +}; +/* log2(e) - 1 */ +#define LOG2EA 4.4269504088896340735992e-1L + +#define SQRTH 0.70710678118654752440L + +long double log2l(long double x) +{ + long double y, z; + int e; + + if (isnan(x)) + return x; + if (x == INFINITY) + return x; + if (x <= 0.0) { + if (x == 0.0) + return -1/(x*x); /* -inf with divbyzero */ + return 0/0.0f; /* nan with invalid */ + } + + /* separate mantissa from exponent */ + /* Note, frexp is used so that denormal numbers + * will be handled properly. + */ + x = frexpl(x, &e); + + /* logarithm using log(x) = z + z**3 P(z)/Q(z), + * where z = 2(x-1)/x+1) + */ + if (e > 2 || e < -2) { + if (x < SQRTH) { /* 2(2x-1)/(2x+1) */ + e -= 1; + z = x - 0.5; + y = 0.5 * z + 0.5; + } else { /* 2 (x-1)/(x+1) */ + z = x - 0.5; + z -= 0.5; + y = 0.5 * x + 0.5; + } + x = z / y; + z = x*x; + y = x * (z * __polevll(z, R, 3) / __p1evll(z, S, 3)); + goto done; + } + + /* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + if (x < SQRTH) { + e -= 1; + x = 2.0*x - 1.0; + } else { + x = x - 1.0; + } + z = x*x; + y = x * (z * __polevll(x, P, 6) / __p1evll(x, Q, 7)); + y = y - 0.5*z; + +done: + /* Multiply log of fraction by log2(e) + * and base 2 exponent by 1 + * + * ***CAUTION*** + * + * This sequence of operations is critical and it may + * be horribly defeated by some compiler optimizers. + */ + z = y * LOG2EA; + z += x * LOG2EA; + z += y; + z += x; + z += e; + return z; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double log2l(long double x) +{ + return log2(x); +} +#endif diff --git a/src/libc-shim/src/log_data.c b/src/orca-libc/src/math/log_data.c similarity index 100% rename from src/libc-shim/src/log_data.c rename to src/orca-libc/src/math/log_data.c diff --git a/src/libc-shim/src/log_data.h b/src/orca-libc/src/math/log_data.h similarity index 93% rename from src/libc-shim/src/log_data.h rename to src/orca-libc/src/math/log_data.h index d8675236..1be22ab2 100644 --- a/src/libc-shim/src/log_data.h +++ b/src/orca-libc/src/math/log_data.h @@ -10,7 +10,7 @@ #define LOG_TABLE_BITS 7 #define LOG_POLY_ORDER 6 #define LOG_POLY1_ORDER 12 -extern const struct log_data { +extern hidden const struct log_data { double ln2hi; double ln2lo; double poly[LOG_POLY_ORDER - 1]; /* First coefficient is 1. */ diff --git a/src/orca-libc/src/math/logb.c b/src/orca-libc/src/math/logb.c new file mode 100644 index 00000000..7f8bdfae --- /dev/null +++ b/src/orca-libc/src/math/logb.c @@ -0,0 +1,17 @@ +#include + +/* +special cases: + logb(+-0) = -inf, and raise divbyzero + logb(+-inf) = +inf + logb(nan) = nan +*/ + +double logb(double x) +{ + if (!isfinite(x)) + return x * x; + if (x == 0) + return -1/(x*x); + return ilogb(x); +} diff --git a/src/orca-libc/src/math/logbf.c b/src/orca-libc/src/math/logbf.c new file mode 100644 index 00000000..a0a0b5ed --- /dev/null +++ b/src/orca-libc/src/math/logbf.c @@ -0,0 +1,10 @@ +#include + +float logbf(float x) +{ + if (!isfinite(x)) + return x * x; + if (x == 0) + return -1/(x*x); + return ilogbf(x); +} diff --git a/src/orca-libc/src/math/logbl.c b/src/orca-libc/src/math/logbl.c new file mode 100644 index 00000000..962973a7 --- /dev/null +++ b/src/orca-libc/src/math/logbl.c @@ -0,0 +1,16 @@ +#include +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double logbl(long double x) +{ + return logb(x); +} +#else +long double logbl(long double x) +{ + if (!isfinite(x)) + return x * x; + if (x == 0) + return -1/(x*x); + return ilogbl(x); +} +#endif diff --git a/src/libc-shim/src/logf.c b/src/orca-libc/src/math/logf.c similarity index 98% rename from src/libc-shim/src/logf.c rename to src/orca-libc/src/math/logf.c index e4c2237c..7ee5d7fe 100644 --- a/src/libc-shim/src/logf.c +++ b/src/orca-libc/src/math/logf.c @@ -53,7 +53,7 @@ float logf(float x) tmp = ix - OFF; i = (tmp >> (23 - LOGF_TABLE_BITS)) % N; k = (int32_t)tmp >> 23; /* arithmetic shift */ - iz = ix - (tmp & 0xff800000); + iz = ix - (tmp & 0x1ff << 23); invc = T[i].invc; logc = T[i].logc; z = (double_t)asfloat(iz); diff --git a/src/libc-shim/src/logf_data.c b/src/orca-libc/src/math/logf_data.c similarity index 100% rename from src/libc-shim/src/logf_data.c rename to src/orca-libc/src/math/logf_data.c diff --git a/src/libc-shim/src/logf_data.h b/src/orca-libc/src/math/logf_data.h similarity index 90% rename from src/libc-shim/src/logf_data.h rename to src/orca-libc/src/math/logf_data.h index 6fc1d644..00cff6f8 100644 --- a/src/libc-shim/src/logf_data.h +++ b/src/orca-libc/src/math/logf_data.h @@ -9,7 +9,7 @@ #define LOGF_TABLE_BITS 4 #define LOGF_POLY_ORDER 4 -extern const struct logf_data { +extern hidden const struct logf_data { struct { double invc, logc; } tab[1 << LOGF_TABLE_BITS]; diff --git a/src/orca-libc/src/math/logl.c b/src/orca-libc/src/math/logl.c new file mode 100644 index 00000000..5d536592 --- /dev/null +++ b/src/orca-libc/src/math/logl.c @@ -0,0 +1,175 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_logl.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Natural logarithm, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, logl(); + * + * y = logl( x ); + * + * + * DESCRIPTION: + * + * Returns the base e (2.718...) logarithm of x. + * + * The argument is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the logarithm + * of the fraction is approximated by + * + * log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/(x+1), + * + * log(x) = log(1+z/2) - log(1-z/2) = z + z**3 P(z)/Q(z). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0.5, 2.0 150000 8.71e-20 2.75e-20 + * IEEE exp(+-10000) 100000 5.39e-20 2.34e-20 + * + * In the tests over the interval exp(+-10000), the logarithms + * of the random arguments were uniformly distributed over + * [-10000, +10000]. + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double logl(long double x) +{ + return log(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 2.32e-20 + */ +static const long double P[] = { + 4.5270000862445199635215E-5L, + 4.9854102823193375972212E-1L, + 6.5787325942061044846969E0L, + 2.9911919328553073277375E1L, + 6.0949667980987787057556E1L, + 5.7112963590585538103336E1L, + 2.0039553499201281259648E1L, +}; +static const long double Q[] = { +/* 1.0000000000000000000000E0,*/ + 1.5062909083469192043167E1L, + 8.3047565967967209469434E1L, + 2.2176239823732856465394E2L, + 3.0909872225312059774938E2L, + 2.1642788614495947685003E2L, + 6.0118660497603843919306E1L, +}; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.16e-22 + */ +static const long double R[4] = { + 1.9757429581415468984296E-3L, +-7.1990767473014147232598E-1L, + 1.0777257190312272158094E1L, +-3.5717684488096787370998E1L, +}; +static const long double S[4] = { +/* 1.00000000000000000000E0L,*/ +-2.6201045551331104417768E1L, + 1.9361891836232102174846E2L, +-4.2861221385716144629696E2L, +}; +static const long double C1 = 6.9314575195312500000000E-1L; +static const long double C2 = 1.4286068203094172321215E-6L; + +#define SQRTH 0.70710678118654752440L + +long double logl(long double x) +{ + long double y, z; + int e; + + if (isnan(x)) + return x; + if (x == INFINITY) + return x; + if (x <= 0.0) { + if (x == 0.0) + return -1/(x*x); /* -inf with divbyzero */ + return 0/0.0f; /* nan with invalid */ + } + + /* separate mantissa from exponent */ + /* Note, frexp is used so that denormal numbers + * will be handled properly. + */ + x = frexpl(x, &e); + + /* logarithm using log(x) = z + z**3 P(z)/Q(z), + * where z = 2(x-1)/(x+1) + */ + if (e > 2 || e < -2) { + if (x < SQRTH) { /* 2(2x-1)/(2x+1) */ + e -= 1; + z = x - 0.5; + y = 0.5 * z + 0.5; + } else { /* 2 (x-1)/(x+1) */ + z = x - 0.5; + z -= 0.5; + y = 0.5 * x + 0.5; + } + x = z / y; + z = x*x; + z = x * (z * __polevll(z, R, 3) / __p1evll(z, S, 3)); + z = z + e * C2; + z = z + x; + z = z + e * C1; + return z; + } + + /* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + if (x < SQRTH) { + e -= 1; + x = 2.0*x - 1.0; + } else { + x = x - 1.0; + } + z = x*x; + y = x * (z * __polevll(x, P, 6) / __p1evll(x, Q, 6)); + y = y + e * C2; + z = y - 0.5*z; + /* Note, the sum of above terms does not exceed x/4, + * so it contributes at most about 1/4 lsb to the error. + */ + z = z + x; + z = z + e * C1; /* This sum has an error of 1/2 lsb. */ + return z; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double logl(long double x) +{ + return log(x); +} +#endif diff --git a/src/orca-libc/src/math/lrint.c b/src/orca-libc/src/math/lrint.c new file mode 100644 index 00000000..ddee7a0d --- /dev/null +++ b/src/orca-libc/src/math/lrint.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include "libm.h" + +/* +If the result cannot be represented (overflow, nan), then +lrint raises the invalid exception. + +Otherwise if the input was not an integer then the inexact +exception is raised. + +C99 is a bit vague about whether inexact exception is +allowed to be raised when invalid is raised. +(F.9 explicitly allows spurious inexact exceptions, F.9.6.5 +does not make it clear if that rule applies to lrint, but +IEEE 754r 7.8 seems to forbid spurious inexact exception in +the ineger conversion functions) + +So we try to make sure that no spurious inexact exception is +raised in case of an overflow. + +If the bit size of long > precision of double, then there +cannot be inexact rounding in case the result overflows, +otherwise LONG_MAX and LONG_MIN can be represented exactly +as a double. +*/ + +#if LONG_MAX < 1U<<53 && defined(FE_INEXACT) +#include +#include +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +#ifdef __GNUC__ +/* avoid stack frame in lrint */ +__attribute__((noinline)) +#endif +static long lrint_slow(double x) +{ + #pragma STDC FENV_ACCESS ON + int e; + + e = fetestexcept(FE_INEXACT); + x = rint(x); + if (!e && (x > LONG_MAX || x < LONG_MIN)) + feclearexcept(FE_INEXACT); + /* conversion */ + return x; +} + +long lrint(double x) +{ + uint32_t abstop = asuint64(x)>>32 & 0x7fffffff; + uint64_t sign = asuint64(x) & (1ULL << 63); + + if (abstop < 0x41dfffff) { + /* |x| < 0x7ffffc00, no overflow */ + double_t toint = asdouble(asuint64(1/EPS) | sign); + double_t y = x + toint - toint; + return (long)y; + } + return lrint_slow(x); +} +#else +long lrint(double x) +{ + return rint(x); +} +#endif diff --git a/src/orca-libc/src/math/lrintf.c b/src/orca-libc/src/math/lrintf.c new file mode 100644 index 00000000..ca0b6a46 --- /dev/null +++ b/src/orca-libc/src/math/lrintf.c @@ -0,0 +1,8 @@ +#include + +/* uses LONG_MAX > 2^24, see comments in lrint.c */ + +long lrintf(float x) +{ + return rintf(x); +} diff --git a/src/orca-libc/src/math/lrintl.c b/src/orca-libc/src/math/lrintl.c new file mode 100644 index 00000000..b2a8106d --- /dev/null +++ b/src/orca-libc/src/math/lrintl.c @@ -0,0 +1,36 @@ +#include +#include +#include "libm.h" + + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long lrintl(long double x) +{ + return lrint(x); +} +#elif defined(FE_INEXACT) +/* +see comments in lrint.c + +Note that if LONG_MAX == 0x7fffffffffffffff && LDBL_MANT_DIG == 64 +then x == 2**63 - 0.5 is the only input that overflows and +raises inexact (with tonearest or upward rounding mode) +*/ +long lrintl(long double x) +{ + #pragma STDC FENV_ACCESS ON + int e; + + e = fetestexcept(FE_INEXACT); + x = rintl(x); + if (!e && (x > LONG_MAX || x < LONG_MIN)) + feclearexcept(FE_INEXACT); + /* conversion */ + return x; +} +#else +long lrintl(long double x) +{ + return rintl(x); +} +#endif diff --git a/src/orca-libc/src/math/lround.c b/src/orca-libc/src/math/lround.c new file mode 100644 index 00000000..b8b79547 --- /dev/null +++ b/src/orca-libc/src/math/lround.c @@ -0,0 +1,6 @@ +#include + +long lround(double x) +{ + return round(x); +} diff --git a/src/orca-libc/src/math/lroundf.c b/src/orca-libc/src/math/lroundf.c new file mode 100644 index 00000000..c4707e7d --- /dev/null +++ b/src/orca-libc/src/math/lroundf.c @@ -0,0 +1,6 @@ +#include + +long lroundf(float x) +{ + return roundf(x); +} diff --git a/src/orca-libc/src/math/lroundl.c b/src/orca-libc/src/math/lroundl.c new file mode 100644 index 00000000..094fdf64 --- /dev/null +++ b/src/orca-libc/src/math/lroundl.c @@ -0,0 +1,6 @@ +#include + +long lroundl(long double x) +{ + return roundl(x); +} diff --git a/src/orca-libc/src/math/modf.c b/src/orca-libc/src/math/modf.c new file mode 100644 index 00000000..1c8a1db9 --- /dev/null +++ b/src/orca-libc/src/math/modf.c @@ -0,0 +1,34 @@ +#include "libm.h" + +double modf(double x, double *iptr) +{ + union {double f; uint64_t i;} u = {x}; + uint64_t mask; + int e = (int)(u.i>>52 & 0x7ff) - 0x3ff; + + /* no fractional part */ + if (e >= 52) { + *iptr = x; + if (e == 0x400 && u.i<<12 != 0) /* nan */ + return x; + u.i &= 1ULL<<63; + return u.f; + } + + /* no integral part*/ + if (e < 0) { + u.i &= 1ULL<<63; + *iptr = u.f; + return x; + } + + mask = -1ULL>>12>>e; + if ((u.i & mask) == 0) { + *iptr = x; + u.i &= 1ULL<<63; + return u.f; + } + u.i &= ~mask; + *iptr = u.f; + return x - u.f; +} diff --git a/src/orca-libc/src/math/modff.c b/src/orca-libc/src/math/modff.c new file mode 100644 index 00000000..639514ef --- /dev/null +++ b/src/orca-libc/src/math/modff.c @@ -0,0 +1,34 @@ +#include "libm.h" + +float modff(float x, float *iptr) +{ + union {float f; uint32_t i;} u = {x}; + uint32_t mask; + int e = (int)(u.i>>23 & 0xff) - 0x7f; + + /* no fractional part */ + if (e >= 23) { + *iptr = x; + if (e == 0x80 && u.i<<9 != 0) { /* nan */ + return x; + } + u.i &= 0x80000000; + return u.f; + } + /* no integral part */ + if (e < 0) { + u.i &= 0x80000000; + *iptr = u.f; + return x; + } + + mask = 0x007fffff>>e; + if ((u.i & mask) == 0) { + *iptr = x; + u.i &= 0x80000000; + return u.f; + } + u.i &= ~mask; + *iptr = u.f; + return x - u.f; +} diff --git a/src/orca-libc/src/math/modfl.c b/src/orca-libc/src/math/modfl.c new file mode 100644 index 00000000..a47b1924 --- /dev/null +++ b/src/orca-libc/src/math/modfl.c @@ -0,0 +1,53 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double modfl(long double x, long double *iptr) +{ + double d; + long double r; + + r = modf(x, &d); + *iptr = d; + return r; +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +static const long double toint = 1/LDBL_EPSILON; + +long double modfl(long double x, long double *iptr) +{ + union ldshape u = {x}; + int e = (u.i.se & 0x7fff) - 0x3fff; + int s = u.i.se >> 15; + long double absx; + long double y; + + /* no fractional part */ + if (e >= LDBL_MANT_DIG-1) { + *iptr = x; + if (isnan(x)) + return x; + return s ? -0.0 : 0.0; + } + + /* no integral part*/ + if (e < 0) { + *iptr = s ? -0.0 : 0.0; + return x; + } + + /* raises spurious inexact */ + absx = s ? -x : x; + y = absx + toint - toint - absx; + if (y == 0) { + *iptr = x; + return s ? -0.0 : 0.0; + } + if (y > 0) + y -= 1; + if (s) + y = -y; + *iptr = x + y; + return -y; +} +#endif diff --git a/src/orca-libc/src/math/nan.c b/src/orca-libc/src/math/nan.c new file mode 100644 index 00000000..9e0826c7 --- /dev/null +++ b/src/orca-libc/src/math/nan.c @@ -0,0 +1,6 @@ +#include + +double nan(const char *s) +{ + return NAN; +} diff --git a/src/orca-libc/src/math/nanf.c b/src/orca-libc/src/math/nanf.c new file mode 100644 index 00000000..752ce546 --- /dev/null +++ b/src/orca-libc/src/math/nanf.c @@ -0,0 +1,6 @@ +#include + +float nanf(const char *s) +{ + return NAN; +} diff --git a/src/orca-libc/src/math/nanl.c b/src/orca-libc/src/math/nanl.c new file mode 100644 index 00000000..969af564 --- /dev/null +++ b/src/orca-libc/src/math/nanl.c @@ -0,0 +1,6 @@ +#include + +long double nanl(const char *s) +{ + return NAN; +} diff --git a/src/orca-libc/src/math/nearbyint.c b/src/orca-libc/src/math/nearbyint.c new file mode 100644 index 00000000..f4e8aac4 --- /dev/null +++ b/src/orca-libc/src/math/nearbyint.c @@ -0,0 +1,20 @@ +#include +#include + +/* nearbyint is the same as rint, but it must not raise the inexact exception */ + +double nearbyint(double x) +{ +#ifdef FE_INEXACT + #pragma STDC FENV_ACCESS ON + int e; + + e = fetestexcept(FE_INEXACT); +#endif + x = rint(x); +#ifdef FE_INEXACT + if (!e) + feclearexcept(FE_INEXACT); +#endif + return x; +} diff --git a/src/orca-libc/src/math/nearbyintf.c b/src/orca-libc/src/math/nearbyintf.c new file mode 100644 index 00000000..092e9ffa --- /dev/null +++ b/src/orca-libc/src/math/nearbyintf.c @@ -0,0 +1,18 @@ +#include +#include + +float nearbyintf(float x) +{ +#ifdef FE_INEXACT + #pragma STDC FENV_ACCESS ON + int e; + + e = fetestexcept(FE_INEXACT); +#endif + x = rintf(x); +#ifdef FE_INEXACT + if (!e) + feclearexcept(FE_INEXACT); +#endif + return x; +} diff --git a/src/orca-libc/src/math/nearbyintl.c b/src/orca-libc/src/math/nearbyintl.c new file mode 100644 index 00000000..82852492 --- /dev/null +++ b/src/orca-libc/src/math/nearbyintl.c @@ -0,0 +1,26 @@ +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double nearbyintl(long double x) +{ + return nearbyint(x); +} +#else +#include +long double nearbyintl(long double x) +{ +#ifdef FE_INEXACT + #pragma STDC FENV_ACCESS ON + int e; + + e = fetestexcept(FE_INEXACT); +#endif + x = rintl(x); +#ifdef FE_INEXACT + if (!e) + feclearexcept(FE_INEXACT); +#endif + return x; +} +#endif diff --git a/src/orca-libc/src/math/nextafter.c b/src/orca-libc/src/math/nextafter.c new file mode 100644 index 00000000..ab5795a4 --- /dev/null +++ b/src/orca-libc/src/math/nextafter.c @@ -0,0 +1,31 @@ +#include "libm.h" + +double nextafter(double x, double y) +{ + union {double f; uint64_t i;} ux={x}, uy={y}; + uint64_t ax, ay; + int e; + + if (isnan(x) || isnan(y)) + return x + y; + if (ux.i == uy.i) + return y; + ax = ux.i & -1ULL/2; + ay = uy.i & -1ULL/2; + if (ax == 0) { + if (ay == 0) + return y; + ux.i = (uy.i & 1ULL<<63) | 1; + } else if (ax > ay || ((ux.i ^ uy.i) & 1ULL<<63)) + ux.i--; + else + ux.i++; + e = ux.i >> 52 & 0x7ff; + /* raise overflow if ux.f is infinite and x is finite */ + if (e == 0x7ff) + FORCE_EVAL(x+x); + /* raise underflow if ux.f is subnormal or zero */ + if (e == 0) + FORCE_EVAL(x*x + ux.f*ux.f); + return ux.f; +} diff --git a/src/orca-libc/src/math/nextafterf.c b/src/orca-libc/src/math/nextafterf.c new file mode 100644 index 00000000..75a09f7d --- /dev/null +++ b/src/orca-libc/src/math/nextafterf.c @@ -0,0 +1,30 @@ +#include "libm.h" + +float nextafterf(float x, float y) +{ + union {float f; uint32_t i;} ux={x}, uy={y}; + uint32_t ax, ay, e; + + if (isnan(x) || isnan(y)) + return x + y; + if (ux.i == uy.i) + return y; + ax = ux.i & 0x7fffffff; + ay = uy.i & 0x7fffffff; + if (ax == 0) { + if (ay == 0) + return y; + ux.i = (uy.i & 0x80000000) | 1; + } else if (ax > ay || ((ux.i ^ uy.i) & 0x80000000)) + ux.i--; + else + ux.i++; + e = ux.i & 0x7f800000; + /* raise overflow if ux.f is infinite and x is finite */ + if (e == 0x7f800000) + FORCE_EVAL(x+x); + /* raise underflow if ux.f is subnormal or zero */ + if (e == 0) + FORCE_EVAL(x*x + ux.f*ux.f); + return ux.f; +} diff --git a/src/orca-libc/src/math/nextafterl.c b/src/orca-libc/src/math/nextafterl.c new file mode 100644 index 00000000..37e858fb --- /dev/null +++ b/src/orca-libc/src/math/nextafterl.c @@ -0,0 +1,75 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double nextafterl(long double x, long double y) +{ + return nextafter(x, y); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +long double nextafterl(long double x, long double y) +{ + union ldshape ux, uy; + + if (isnan(x) || isnan(y)) + return x + y; + if (x == y) + return y; + ux.f = x; + if (x == 0) { + uy.f = y; + ux.i.m = 1; + ux.i.se = uy.i.se & 0x8000; + } else if ((x < y) == !(ux.i.se & 0x8000)) { + ux.i.m++; + if (ux.i.m << 1 == 0) { + ux.i.m = 1ULL << 63; + ux.i.se++; + } + } else { + if (ux.i.m << 1 == 0) { + ux.i.se--; + if (ux.i.se) + ux.i.m = 0; + } + ux.i.m--; + } + /* raise overflow if ux is infinite and x is finite */ + if ((ux.i.se & 0x7fff) == 0x7fff) + return x + x; + /* raise underflow if ux is subnormal or zero */ + if ((ux.i.se & 0x7fff) == 0) + FORCE_EVAL(x*x + ux.f*ux.f); + return ux.f; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +long double nextafterl(long double x, long double y) +{ + union ldshape ux, uy; + + if (isnan(x) || isnan(y)) + return x + y; + if (x == y) + return y; + ux.f = x; + if (x == 0) { + uy.f = y; + ux.i.lo = 1; + ux.i.se = uy.i.se & 0x8000; + } else if ((x < y) == !(ux.i.se & 0x8000)) { + ux.i2.lo++; + if (ux.i2.lo == 0) + ux.i2.hi++; + } else { + if (ux.i2.lo == 0) + ux.i2.hi--; + ux.i2.lo--; + } + /* raise overflow if ux is infinite and x is finite */ + if ((ux.i.se & 0x7fff) == 0x7fff) + return x + x; + /* raise underflow if ux is subnormal or zero */ + if ((ux.i.se & 0x7fff) == 0) + FORCE_EVAL(x*x + ux.f*ux.f); + return ux.f; +} +#endif diff --git a/src/orca-libc/src/math/nexttoward.c b/src/orca-libc/src/math/nexttoward.c new file mode 100644 index 00000000..827ee5c3 --- /dev/null +++ b/src/orca-libc/src/math/nexttoward.c @@ -0,0 +1,42 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +double nexttoward(double x, long double y) +{ + return nextafter(x, y); +} +#else +double nexttoward(double x, long double y) +{ + union {double f; uint64_t i;} ux = {x}; + int e; + + if (isnan(x) || isnan(y)) + return x + y; + if (x == y) + return y; + if (x == 0) { + ux.i = 1; + if (signbit(y)) + ux.i |= 1ULL<<63; + } else if (x < y) { + if (signbit(x)) + ux.i--; + else + ux.i++; + } else { + if (signbit(x)) + ux.i++; + else + ux.i--; + } + e = ux.i>>52 & 0x7ff; + /* raise overflow if ux.f is infinite and x is finite */ + if (e == 0x7ff) + FORCE_EVAL(x+x); + /* raise underflow if ux.f is subnormal or zero */ + if (e == 0) + FORCE_EVAL(x*x + ux.f*ux.f); + return ux.f; +} +#endif diff --git a/src/orca-libc/src/math/nexttowardf.c b/src/orca-libc/src/math/nexttowardf.c new file mode 100644 index 00000000..bbf172f9 --- /dev/null +++ b/src/orca-libc/src/math/nexttowardf.c @@ -0,0 +1,35 @@ +#include "libm.h" + +float nexttowardf(float x, long double y) +{ + union {float f; uint32_t i;} ux = {x}; + uint32_t e; + + if (isnan(x) || isnan(y)) + return x + y; + if (x == y) + return y; + if (x == 0) { + ux.i = 1; + if (signbit(y)) + ux.i |= 0x80000000; + } else if (x < y) { + if (signbit(x)) + ux.i--; + else + ux.i++; + } else { + if (signbit(x)) + ux.i++; + else + ux.i--; + } + e = ux.i & 0x7f800000; + /* raise overflow if ux.f is infinite and x is finite */ + if (e == 0x7f800000) + FORCE_EVAL(x+x); + /* raise underflow if ux.f is subnormal or zero */ + if (e == 0) + FORCE_EVAL(x*x + ux.f*ux.f); + return ux.f; +} diff --git a/src/orca-libc/src/math/nexttowardl.c b/src/orca-libc/src/math/nexttowardl.c new file mode 100644 index 00000000..67a63403 --- /dev/null +++ b/src/orca-libc/src/math/nexttowardl.c @@ -0,0 +1,6 @@ +#include + +long double nexttowardl(long double x, long double y) +{ + return nextafterl(x, y); +} diff --git a/src/orca-libc/src/math/pow.c b/src/orca-libc/src/math/pow.c new file mode 100644 index 00000000..694c2ef6 --- /dev/null +++ b/src/orca-libc/src/math/pow.c @@ -0,0 +1,343 @@ +/* + * Double-precision x^y function. + * + * Copyright (c) 2018, Arm Limited. + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include "libm.h" +#include "exp_data.h" +#include "pow_data.h" + +/* +Worst-case error: 0.54 ULP (~= ulperr_exp + 1024*Ln2*relerr_log*2^53) +relerr_log: 1.3 * 2^-68 (Relative error of log, 1.5 * 2^-68 without fma) +ulperr_exp: 0.509 ULP (ULP error of exp, 0.511 ULP without fma) +*/ + +#define T __pow_log_data.tab +#define A __pow_log_data.poly +#define Ln2hi __pow_log_data.ln2hi +#define Ln2lo __pow_log_data.ln2lo +#define N (1 << POW_LOG_TABLE_BITS) +#define OFF 0x3fe6955500000000 + +/* Top 12 bits of a double (sign and exponent bits). */ +static inline uint32_t top12(double x) +{ + return asuint64(x) >> 52; +} + +/* Compute y+TAIL = log(x) where the rounded result is y and TAIL has about + additional 15 bits precision. IX is the bit representation of x, but + normalized in the subnormal range using the sign bit for the exponent. */ +static inline double_t log_inline(uint64_t ix, double_t *tail) +{ + /* double_t for better performance on targets with FLT_EVAL_METHOD==2. */ + double_t z, r, y, invc, logc, logctail, kd, hi, t1, t2, lo, lo1, lo2, p; + uint64_t iz, tmp; + int k, i; + + /* x = 2^k z; where z is in range [OFF,2*OFF) and exact. + The range is split into N subintervals. + The ith subinterval contains z and c is near its center. */ + tmp = ix - OFF; + i = (tmp >> (52 - POW_LOG_TABLE_BITS)) % N; + k = (int64_t)tmp >> 52; /* arithmetic shift */ + iz = ix - (tmp & 0xfffULL << 52); + z = asdouble(iz); + kd = (double_t)k; + + /* log(x) = k*Ln2 + log(c) + log1p(z/c-1). */ + invc = T[i].invc; + logc = T[i].logc; + logctail = T[i].logctail; + + /* Note: 1/c is j/N or j/N/2 where j is an integer in [N,2N) and + |z/c - 1| < 1/N, so r = z/c - 1 is exactly representible. */ +#if __FP_FAST_FMA + r = __builtin_fma(z, invc, -1.0); +#else + /* Split z such that rhi, rlo and rhi*rhi are exact and |rlo| <= |r|. */ + double_t zhi = asdouble((iz + (1ULL << 31)) & (-1ULL << 32)); + double_t zlo = z - zhi; + double_t rhi = zhi * invc - 1.0; + double_t rlo = zlo * invc; + r = rhi + rlo; +#endif + + /* k*Ln2 + log(c) + r. */ + t1 = kd * Ln2hi + logc; + t2 = t1 + r; + lo1 = kd * Ln2lo + logctail; + lo2 = t1 - t2 + r; + + /* Evaluation is optimized assuming superscalar pipelined execution. */ + double_t ar, ar2, ar3, lo3, lo4; + ar = A[0] * r; /* A[0] = -0.5. */ + ar2 = r * ar; + ar3 = r * ar2; + /* k*Ln2 + log(c) + r + A[0]*r*r. */ +#if __FP_FAST_FMA + hi = t2 + ar2; + lo3 = __builtin_fma(ar, r, -ar2); + lo4 = t2 - hi + ar2; +#else + double_t arhi = A[0] * rhi; + double_t arhi2 = rhi * arhi; + hi = t2 + arhi2; + lo3 = rlo * (ar + arhi); + lo4 = t2 - hi + arhi2; +#endif + /* p = log1p(r) - r - A[0]*r*r. */ + p = (ar3 * (A[1] + r * A[2] + + ar2 * (A[3] + r * A[4] + ar2 * (A[5] + r * A[6])))); + lo = lo1 + lo2 + lo3 + lo4 + p; + y = hi + lo; + *tail = hi - y + lo; + return y; +} + +#undef N +#undef T +#define N (1 << EXP_TABLE_BITS) +#define InvLn2N __exp_data.invln2N +#define NegLn2hiN __exp_data.negln2hiN +#define NegLn2loN __exp_data.negln2loN +#define Shift __exp_data.shift +#define T __exp_data.tab +#define C2 __exp_data.poly[5 - EXP_POLY_ORDER] +#define C3 __exp_data.poly[6 - EXP_POLY_ORDER] +#define C4 __exp_data.poly[7 - EXP_POLY_ORDER] +#define C5 __exp_data.poly[8 - EXP_POLY_ORDER] +#define C6 __exp_data.poly[9 - EXP_POLY_ORDER] + +/* Handle cases that may overflow or underflow when computing the result that + is scale*(1+TMP) without intermediate rounding. The bit representation of + scale is in SBITS, however it has a computed exponent that may have + overflown into the sign bit so that needs to be adjusted before using it as + a double. (int32_t)KI is the k used in the argument reduction and exponent + adjustment of scale, positive k here means the result may overflow and + negative k means the result may underflow. */ +static inline double specialcase(double_t tmp, uint64_t sbits, uint64_t ki) +{ + double_t scale, y; + + if ((ki & 0x80000000) == 0) { + /* k > 0, the exponent of scale might have overflowed by <= 460. */ + sbits -= 1009ull << 52; + scale = asdouble(sbits); + y = 0x1p1009 * (scale + scale * tmp); + return eval_as_double(y); + } + /* k < 0, need special care in the subnormal range. */ + sbits += 1022ull << 52; + /* Note: sbits is signed scale. */ + scale = asdouble(sbits); + y = scale + scale * tmp; + if (fabs(y) < 1.0) { + /* Round y to the right precision before scaling it into the subnormal + range to avoid double rounding that can cause 0.5+E/2 ulp error where + E is the worst-case ulp error outside the subnormal range. So this + is only useful if the goal is better than 1 ulp worst-case error. */ + double_t hi, lo, one = 1.0; + if (y < 0.0) + one = -1.0; + lo = scale - y + scale * tmp; + hi = one + y; + lo = one - hi + y + lo; + y = eval_as_double(hi + lo) - one; + /* Fix the sign of 0. */ + if (y == 0.0) + y = asdouble(sbits & 0x8000000000000000); + /* The underflow exception needs to be signaled explicitly. */ + fp_force_eval(fp_barrier(0x1p-1022) * 0x1p-1022); + } + y = 0x1p-1022 * y; + return eval_as_double(y); +} + +#define SIGN_BIAS (0x800 << EXP_TABLE_BITS) + +/* Computes sign*exp(x+xtail) where |xtail| < 2^-8/N and |xtail| <= |x|. + The sign_bias argument is SIGN_BIAS or 0 and sets the sign to -1 or 1. */ +static inline double exp_inline(double_t x, double_t xtail, uint32_t sign_bias) +{ + uint32_t abstop; + uint64_t ki, idx, top, sbits; + /* double_t for better performance on targets with FLT_EVAL_METHOD==2. */ + double_t kd, z, r, r2, scale, tail, tmp; + + abstop = top12(x) & 0x7ff; + if (predict_false(abstop - top12(0x1p-54) >= + top12(512.0) - top12(0x1p-54))) { + if (abstop - top12(0x1p-54) >= 0x80000000) { + /* Avoid spurious underflow for tiny x. */ + /* Note: 0 is common input. */ + double_t one = WANT_ROUNDING ? 1.0 + x : 1.0; + return sign_bias ? -one : one; + } + if (abstop >= top12(1024.0)) { + /* Note: inf and nan are already handled. */ + if (asuint64(x) >> 63) + return __math_uflow(sign_bias); + else + return __math_oflow(sign_bias); + } + /* Large x is special cased below. */ + abstop = 0; + } + + /* exp(x) = 2^(k/N) * exp(r), with exp(r) in [2^(-1/2N),2^(1/2N)]. */ + /* x = ln2/N*k + r, with int k and r in [-ln2/2N, ln2/2N]. */ + z = InvLn2N * x; +#if TOINT_INTRINSICS + kd = roundtoint(z); + ki = converttoint(z); +#elif EXP_USE_TOINT_NARROW + /* z - kd is in [-0.5-2^-16, 0.5] in all rounding modes. */ + kd = eval_as_double(z + Shift); + ki = asuint64(kd) >> 16; + kd = (double_t)(int32_t)ki; +#else + /* z - kd is in [-1, 1] in non-nearest rounding modes. */ + kd = eval_as_double(z + Shift); + ki = asuint64(kd); + kd -= Shift; +#endif + r = x + kd * NegLn2hiN + kd * NegLn2loN; + /* The code assumes 2^-200 < |xtail| < 2^-8/N. */ + r += xtail; + /* 2^(k/N) ~= scale * (1 + tail). */ + idx = 2 * (ki % N); + top = (ki + sign_bias) << (52 - EXP_TABLE_BITS); + tail = asdouble(T[idx]); + /* This is only a valid scale when -1023*N < k < 1024*N. */ + sbits = T[idx + 1] + top; + /* exp(x) = 2^(k/N) * exp(r) ~= scale + scale * (tail + exp(r) - 1). */ + /* Evaluation is optimized assuming superscalar pipelined execution. */ + r2 = r * r; + /* Without fma the worst case error is 0.25/N ulp larger. */ + /* Worst case error is less than 0.5+1.11/N+(abs poly error * 2^53) ulp. */ + tmp = tail + r + r2 * (C2 + r * C3) + r2 * r2 * (C4 + r * C5); + if (predict_false(abstop == 0)) + return specialcase(tmp, sbits, ki); + scale = asdouble(sbits); + /* Note: tmp == 0 or |tmp| > 2^-200 and scale > 2^-739, so there + is no spurious underflow here even without fma. */ + return eval_as_double(scale + scale * tmp); +} + +/* Returns 0 if not int, 1 if odd int, 2 if even int. The argument is + the bit representation of a non-zero finite floating-point value. */ +static inline int checkint(uint64_t iy) +{ + int e = iy >> 52 & 0x7ff; + if (e < 0x3ff) + return 0; + if (e > 0x3ff + 52) + return 2; + if (iy & ((1ULL << (0x3ff + 52 - e)) - 1)) + return 0; + if (iy & (1ULL << (0x3ff + 52 - e))) + return 1; + return 2; +} + +/* Returns 1 if input is the bit representation of 0, infinity or nan. */ +static inline int zeroinfnan(uint64_t i) +{ + return 2 * i - 1 >= 2 * asuint64(INFINITY) - 1; +} + +double pow(double x, double y) +{ + uint32_t sign_bias = 0; + uint64_t ix, iy; + uint32_t topx, topy; + + ix = asuint64(x); + iy = asuint64(y); + topx = top12(x); + topy = top12(y); + if (predict_false(topx - 0x001 >= 0x7ff - 0x001 || + (topy & 0x7ff) - 0x3be >= 0x43e - 0x3be)) { + /* Note: if |y| > 1075 * ln2 * 2^53 ~= 0x1.749p62 then pow(x,y) = inf/0 + and if |y| < 2^-54 / 1075 ~= 0x1.e7b6p-65 then pow(x,y) = +-1. */ + /* Special cases: (x < 0x1p-126 or inf or nan) or + (|y| < 0x1p-65 or |y| >= 0x1p63 or nan). */ + if (predict_false(zeroinfnan(iy))) { + if (2 * iy == 0) + return issignaling_inline(x) ? x + y : 1.0; + if (ix == asuint64(1.0)) + return issignaling_inline(y) ? x + y : 1.0; + if (2 * ix > 2 * asuint64(INFINITY) || + 2 * iy > 2 * asuint64(INFINITY)) + return x + y; + if (2 * ix == 2 * asuint64(1.0)) + return 1.0; + if ((2 * ix < 2 * asuint64(1.0)) == !(iy >> 63)) + return 0.0; /* |x|<1 && y==inf or |x|>1 && y==-inf. */ + return y * y; + } + if (predict_false(zeroinfnan(ix))) { + double_t x2 = x * x; + if (ix >> 63 && checkint(iy) == 1) + x2 = -x2; + /* Without the barrier some versions of clang hoist the 1/x2 and + thus division by zero exception can be signaled spuriously. */ + return iy >> 63 ? fp_barrier(1 / x2) : x2; + } + /* Here x and y are non-zero finite. */ + if (ix >> 63) { + /* Finite x < 0. */ + int yint = checkint(iy); + if (yint == 0) + return __math_invalid(x); + if (yint == 1) + sign_bias = SIGN_BIAS; + ix &= 0x7fffffffffffffff; + topx &= 0x7ff; + } + if ((topy & 0x7ff) - 0x3be >= 0x43e - 0x3be) { + /* Note: sign_bias == 0 here because y is not odd. */ + if (ix == asuint64(1.0)) + return 1.0; + if ((topy & 0x7ff) < 0x3be) { + /* |y| < 2^-65, x^y ~= 1 + y*log(x). */ + if (WANT_ROUNDING) + return ix > asuint64(1.0) ? 1.0 + y : + 1.0 - y; + else + return 1.0; + } + return (ix > asuint64(1.0)) == (topy < 0x800) ? + __math_oflow(0) : + __math_uflow(0); + } + if (topx == 0) { + /* Normalize subnormal x so exponent becomes negative. */ + ix = asuint64(x * 0x1p52); + ix &= 0x7fffffffffffffff; + ix -= 52ULL << 52; + } + } + + double_t lo; + double_t hi = log_inline(ix, &lo); + double_t ehi, elo; +#if __FP_FAST_FMA + ehi = y * hi; + elo = y * lo + __builtin_fma(y, hi, -ehi); +#else + double_t yhi = asdouble(iy & -1ULL << 27); + double_t ylo = y - yhi; + double_t lhi = asdouble(asuint64(hi) & -1ULL << 27); + double_t llo = hi - lhi + lo; + ehi = yhi * lhi; + elo = ylo * lhi + y * llo; /* |elo| < |ehi| * 2^-25. */ +#endif + return exp_inline(ehi, elo, sign_bias); +} diff --git a/src/orca-libc/src/math/pow_data.c b/src/orca-libc/src/math/pow_data.c new file mode 100644 index 00000000..81e760de --- /dev/null +++ b/src/orca-libc/src/math/pow_data.c @@ -0,0 +1,180 @@ +/* + * Data for the log part of pow. + * + * Copyright (c) 2018, Arm Limited. + * SPDX-License-Identifier: MIT + */ + +#include "pow_data.h" + +#define N (1 << POW_LOG_TABLE_BITS) + +const struct pow_log_data __pow_log_data = { +.ln2hi = 0x1.62e42fefa3800p-1, +.ln2lo = 0x1.ef35793c76730p-45, +.poly = { +// relative error: 0x1.11922ap-70 +// in -0x1.6bp-8 0x1.6bp-8 +// Coefficients are scaled to match the scaling during evaluation. +-0x1p-1, +0x1.555555555556p-2 * -2, +-0x1.0000000000006p-2 * -2, +0x1.999999959554ep-3 * 4, +-0x1.555555529a47ap-3 * 4, +0x1.2495b9b4845e9p-3 * -8, +-0x1.0002b8b263fc3p-3 * -8, +}, +/* Algorithm: + + x = 2^k z + log(x) = k ln2 + log(c) + log(z/c) + log(z/c) = poly(z/c - 1) + +where z is in [0x1.69555p-1; 0x1.69555p0] which is split into N subintervals +and z falls into the ith one, then table entries are computed as + + tab[i].invc = 1/c + tab[i].logc = round(0x1p43*log(c))/0x1p43 + tab[i].logctail = (double)(log(c) - logc) + +where c is chosen near the center of the subinterval such that 1/c has only a +few precision bits so z/c - 1 is exactly representible as double: + + 1/c = center < 1 ? round(N/center)/N : round(2*N/center)/N/2 + +Note: |z/c - 1| < 1/N for the chosen c, |log(c) - logc - logctail| < 0x1p-97, +the last few bits of logc are rounded away so k*ln2hi + logc has no rounding +error and the interval for z is selected such that near x == 1, where log(x) +is tiny, large cancellation error is avoided in logc + poly(z/c - 1). */ +.tab = { +#define A(a, b, c) {a, 0, b, c}, +A(0x1.6a00000000000p+0, -0x1.62c82f2b9c800p-2, 0x1.ab42428375680p-48) +A(0x1.6800000000000p+0, -0x1.5d1bdbf580800p-2, -0x1.ca508d8e0f720p-46) +A(0x1.6600000000000p+0, -0x1.5767717455800p-2, -0x1.362a4d5b6506dp-45) +A(0x1.6400000000000p+0, -0x1.51aad872df800p-2, -0x1.684e49eb067d5p-49) +A(0x1.6200000000000p+0, -0x1.4be5f95777800p-2, -0x1.41b6993293ee0p-47) +A(0x1.6000000000000p+0, -0x1.4618bc21c6000p-2, 0x1.3d82f484c84ccp-46) +A(0x1.5e00000000000p+0, -0x1.404308686a800p-2, 0x1.c42f3ed820b3ap-50) +A(0x1.5c00000000000p+0, -0x1.3a64c55694800p-2, 0x1.0b1c686519460p-45) +A(0x1.5a00000000000p+0, -0x1.347dd9a988000p-2, 0x1.5594dd4c58092p-45) +A(0x1.5800000000000p+0, -0x1.2e8e2bae12000p-2, 0x1.67b1e99b72bd8p-45) +A(0x1.5600000000000p+0, -0x1.2895a13de8800p-2, 0x1.5ca14b6cfb03fp-46) +A(0x1.5600000000000p+0, -0x1.2895a13de8800p-2, 0x1.5ca14b6cfb03fp-46) +A(0x1.5400000000000p+0, -0x1.22941fbcf7800p-2, -0x1.65a242853da76p-46) +A(0x1.5200000000000p+0, -0x1.1c898c1699800p-2, -0x1.fafbc68e75404p-46) +A(0x1.5000000000000p+0, -0x1.1675cababa800p-2, 0x1.f1fc63382a8f0p-46) +A(0x1.4e00000000000p+0, -0x1.1058bf9ae4800p-2, -0x1.6a8c4fd055a66p-45) +A(0x1.4c00000000000p+0, -0x1.0a324e2739000p-2, -0x1.c6bee7ef4030ep-47) +A(0x1.4a00000000000p+0, -0x1.0402594b4d000p-2, -0x1.036b89ef42d7fp-48) +A(0x1.4a00000000000p+0, -0x1.0402594b4d000p-2, -0x1.036b89ef42d7fp-48) +A(0x1.4800000000000p+0, -0x1.fb9186d5e4000p-3, 0x1.d572aab993c87p-47) +A(0x1.4600000000000p+0, -0x1.ef0adcbdc6000p-3, 0x1.b26b79c86af24p-45) +A(0x1.4400000000000p+0, -0x1.e27076e2af000p-3, -0x1.72f4f543fff10p-46) +A(0x1.4200000000000p+0, -0x1.d5c216b4fc000p-3, 0x1.1ba91bbca681bp-45) +A(0x1.4000000000000p+0, -0x1.c8ff7c79aa000p-3, 0x1.7794f689f8434p-45) +A(0x1.4000000000000p+0, -0x1.c8ff7c79aa000p-3, 0x1.7794f689f8434p-45) +A(0x1.3e00000000000p+0, -0x1.bc286742d9000p-3, 0x1.94eb0318bb78fp-46) +A(0x1.3c00000000000p+0, -0x1.af3c94e80c000p-3, 0x1.a4e633fcd9066p-52) +A(0x1.3a00000000000p+0, -0x1.a23bc1fe2b000p-3, -0x1.58c64dc46c1eap-45) +A(0x1.3a00000000000p+0, -0x1.a23bc1fe2b000p-3, -0x1.58c64dc46c1eap-45) +A(0x1.3800000000000p+0, -0x1.9525a9cf45000p-3, -0x1.ad1d904c1d4e3p-45) +A(0x1.3600000000000p+0, -0x1.87fa06520d000p-3, 0x1.bbdbf7fdbfa09p-45) +A(0x1.3400000000000p+0, -0x1.7ab890210e000p-3, 0x1.bdb9072534a58p-45) +A(0x1.3400000000000p+0, -0x1.7ab890210e000p-3, 0x1.bdb9072534a58p-45) +A(0x1.3200000000000p+0, -0x1.6d60fe719d000p-3, -0x1.0e46aa3b2e266p-46) +A(0x1.3000000000000p+0, -0x1.5ff3070a79000p-3, -0x1.e9e439f105039p-46) +A(0x1.3000000000000p+0, -0x1.5ff3070a79000p-3, -0x1.e9e439f105039p-46) +A(0x1.2e00000000000p+0, -0x1.526e5e3a1b000p-3, -0x1.0de8b90075b8fp-45) +A(0x1.2c00000000000p+0, -0x1.44d2b6ccb8000p-3, 0x1.70cc16135783cp-46) +A(0x1.2c00000000000p+0, -0x1.44d2b6ccb8000p-3, 0x1.70cc16135783cp-46) +A(0x1.2a00000000000p+0, -0x1.371fc201e9000p-3, 0x1.178864d27543ap-48) +A(0x1.2800000000000p+0, -0x1.29552f81ff000p-3, -0x1.48d301771c408p-45) +A(0x1.2600000000000p+0, -0x1.1b72ad52f6000p-3, -0x1.e80a41811a396p-45) +A(0x1.2600000000000p+0, -0x1.1b72ad52f6000p-3, -0x1.e80a41811a396p-45) +A(0x1.2400000000000p+0, -0x1.0d77e7cd09000p-3, 0x1.a699688e85bf4p-47) +A(0x1.2400000000000p+0, -0x1.0d77e7cd09000p-3, 0x1.a699688e85bf4p-47) +A(0x1.2200000000000p+0, -0x1.fec9131dbe000p-4, -0x1.575545ca333f2p-45) +A(0x1.2000000000000p+0, -0x1.e27076e2b0000p-4, 0x1.a342c2af0003cp-45) +A(0x1.2000000000000p+0, -0x1.e27076e2b0000p-4, 0x1.a342c2af0003cp-45) +A(0x1.1e00000000000p+0, -0x1.c5e548f5bc000p-4, -0x1.d0c57585fbe06p-46) +A(0x1.1c00000000000p+0, -0x1.a926d3a4ae000p-4, 0x1.53935e85baac8p-45) +A(0x1.1c00000000000p+0, -0x1.a926d3a4ae000p-4, 0x1.53935e85baac8p-45) +A(0x1.1a00000000000p+0, -0x1.8c345d631a000p-4, 0x1.37c294d2f5668p-46) +A(0x1.1a00000000000p+0, -0x1.8c345d631a000p-4, 0x1.37c294d2f5668p-46) +A(0x1.1800000000000p+0, -0x1.6f0d28ae56000p-4, -0x1.69737c93373dap-45) +A(0x1.1600000000000p+0, -0x1.51b073f062000p-4, 0x1.f025b61c65e57p-46) +A(0x1.1600000000000p+0, -0x1.51b073f062000p-4, 0x1.f025b61c65e57p-46) +A(0x1.1400000000000p+0, -0x1.341d7961be000p-4, 0x1.c5edaccf913dfp-45) +A(0x1.1400000000000p+0, -0x1.341d7961be000p-4, 0x1.c5edaccf913dfp-45) +A(0x1.1200000000000p+0, -0x1.16536eea38000p-4, 0x1.47c5e768fa309p-46) +A(0x1.1000000000000p+0, -0x1.f0a30c0118000p-5, 0x1.d599e83368e91p-45) +A(0x1.1000000000000p+0, -0x1.f0a30c0118000p-5, 0x1.d599e83368e91p-45) +A(0x1.0e00000000000p+0, -0x1.b42dd71198000p-5, 0x1.c827ae5d6704cp-46) +A(0x1.0e00000000000p+0, -0x1.b42dd71198000p-5, 0x1.c827ae5d6704cp-46) +A(0x1.0c00000000000p+0, -0x1.77458f632c000p-5, -0x1.cfc4634f2a1eep-45) +A(0x1.0c00000000000p+0, -0x1.77458f632c000p-5, -0x1.cfc4634f2a1eep-45) +A(0x1.0a00000000000p+0, -0x1.39e87b9fec000p-5, 0x1.502b7f526feaap-48) +A(0x1.0a00000000000p+0, -0x1.39e87b9fec000p-5, 0x1.502b7f526feaap-48) +A(0x1.0800000000000p+0, -0x1.f829b0e780000p-6, -0x1.980267c7e09e4p-45) +A(0x1.0800000000000p+0, -0x1.f829b0e780000p-6, -0x1.980267c7e09e4p-45) +A(0x1.0600000000000p+0, -0x1.7b91b07d58000p-6, -0x1.88d5493faa639p-45) +A(0x1.0400000000000p+0, -0x1.fc0a8b0fc0000p-7, -0x1.f1e7cf6d3a69cp-50) +A(0x1.0400000000000p+0, -0x1.fc0a8b0fc0000p-7, -0x1.f1e7cf6d3a69cp-50) +A(0x1.0200000000000p+0, -0x1.fe02a6b100000p-8, -0x1.9e23f0dda40e4p-46) +A(0x1.0200000000000p+0, -0x1.fe02a6b100000p-8, -0x1.9e23f0dda40e4p-46) +A(0x1.0000000000000p+0, 0x0.0000000000000p+0, 0x0.0000000000000p+0) +A(0x1.0000000000000p+0, 0x0.0000000000000p+0, 0x0.0000000000000p+0) +A(0x1.fc00000000000p-1, 0x1.0101575890000p-7, -0x1.0c76b999d2be8p-46) +A(0x1.f800000000000p-1, 0x1.0205658938000p-6, -0x1.3dc5b06e2f7d2p-45) +A(0x1.f400000000000p-1, 0x1.8492528c90000p-6, -0x1.aa0ba325a0c34p-45) +A(0x1.f000000000000p-1, 0x1.0415d89e74000p-5, 0x1.111c05cf1d753p-47) +A(0x1.ec00000000000p-1, 0x1.466aed42e0000p-5, -0x1.c167375bdfd28p-45) +A(0x1.e800000000000p-1, 0x1.894aa149fc000p-5, -0x1.97995d05a267dp-46) +A(0x1.e400000000000p-1, 0x1.ccb73cdddc000p-5, -0x1.a68f247d82807p-46) +A(0x1.e200000000000p-1, 0x1.eea31c006c000p-5, -0x1.e113e4fc93b7bp-47) +A(0x1.de00000000000p-1, 0x1.1973bd1466000p-4, -0x1.5325d560d9e9bp-45) +A(0x1.da00000000000p-1, 0x1.3bdf5a7d1e000p-4, 0x1.cc85ea5db4ed7p-45) +A(0x1.d600000000000p-1, 0x1.5e95a4d97a000p-4, -0x1.c69063c5d1d1ep-45) +A(0x1.d400000000000p-1, 0x1.700d30aeac000p-4, 0x1.c1e8da99ded32p-49) +A(0x1.d000000000000p-1, 0x1.9335e5d594000p-4, 0x1.3115c3abd47dap-45) +A(0x1.cc00000000000p-1, 0x1.b6ac88dad6000p-4, -0x1.390802bf768e5p-46) +A(0x1.ca00000000000p-1, 0x1.c885801bc4000p-4, 0x1.646d1c65aacd3p-45) +A(0x1.c600000000000p-1, 0x1.ec739830a2000p-4, -0x1.dc068afe645e0p-45) +A(0x1.c400000000000p-1, 0x1.fe89139dbe000p-4, -0x1.534d64fa10afdp-45) +A(0x1.c000000000000p-1, 0x1.1178e8227e000p-3, 0x1.1ef78ce2d07f2p-45) +A(0x1.be00000000000p-1, 0x1.1aa2b7e23f000p-3, 0x1.ca78e44389934p-45) +A(0x1.ba00000000000p-1, 0x1.2d1610c868000p-3, 0x1.39d6ccb81b4a1p-47) +A(0x1.b800000000000p-1, 0x1.365fcb0159000p-3, 0x1.62fa8234b7289p-51) +A(0x1.b400000000000p-1, 0x1.4913d8333b000p-3, 0x1.5837954fdb678p-45) +A(0x1.b200000000000p-1, 0x1.527e5e4a1b000p-3, 0x1.633e8e5697dc7p-45) +A(0x1.ae00000000000p-1, 0x1.6574ebe8c1000p-3, 0x1.9cf8b2c3c2e78p-46) +A(0x1.ac00000000000p-1, 0x1.6f0128b757000p-3, -0x1.5118de59c21e1p-45) +A(0x1.aa00000000000p-1, 0x1.7898d85445000p-3, -0x1.c661070914305p-46) +A(0x1.a600000000000p-1, 0x1.8beafeb390000p-3, -0x1.73d54aae92cd1p-47) +A(0x1.a400000000000p-1, 0x1.95a5adcf70000p-3, 0x1.7f22858a0ff6fp-47) +A(0x1.a000000000000p-1, 0x1.a93ed3c8ae000p-3, -0x1.8724350562169p-45) +A(0x1.9e00000000000p-1, 0x1.b31d8575bd000p-3, -0x1.c358d4eace1aap-47) +A(0x1.9c00000000000p-1, 0x1.bd087383be000p-3, -0x1.d4bc4595412b6p-45) +A(0x1.9a00000000000p-1, 0x1.c6ffbc6f01000p-3, -0x1.1ec72c5962bd2p-48) +A(0x1.9600000000000p-1, 0x1.db13db0d49000p-3, -0x1.aff2af715b035p-45) +A(0x1.9400000000000p-1, 0x1.e530effe71000p-3, 0x1.212276041f430p-51) +A(0x1.9200000000000p-1, 0x1.ef5ade4dd0000p-3, -0x1.a211565bb8e11p-51) +A(0x1.9000000000000p-1, 0x1.f991c6cb3b000p-3, 0x1.bcbecca0cdf30p-46) +A(0x1.8c00000000000p-1, 0x1.07138604d5800p-2, 0x1.89cdb16ed4e91p-48) +A(0x1.8a00000000000p-1, 0x1.0c42d67616000p-2, 0x1.7188b163ceae9p-45) +A(0x1.8800000000000p-1, 0x1.1178e8227e800p-2, -0x1.c210e63a5f01cp-45) +A(0x1.8600000000000p-1, 0x1.16b5ccbacf800p-2, 0x1.b9acdf7a51681p-45) +A(0x1.8400000000000p-1, 0x1.1bf99635a6800p-2, 0x1.ca6ed5147bdb7p-45) +A(0x1.8200000000000p-1, 0x1.214456d0eb800p-2, 0x1.a87deba46baeap-47) +A(0x1.7e00000000000p-1, 0x1.2bef07cdc9000p-2, 0x1.a9cfa4a5004f4p-45) +A(0x1.7c00000000000p-1, 0x1.314f1e1d36000p-2, -0x1.8e27ad3213cb8p-45) +A(0x1.7a00000000000p-1, 0x1.36b6776be1000p-2, 0x1.16ecdb0f177c8p-46) +A(0x1.7800000000000p-1, 0x1.3c25277333000p-2, 0x1.83b54b606bd5cp-46) +A(0x1.7600000000000p-1, 0x1.419b423d5e800p-2, 0x1.8e436ec90e09dp-47) +A(0x1.7400000000000p-1, 0x1.4718dc271c800p-2, -0x1.f27ce0967d675p-45) +A(0x1.7200000000000p-1, 0x1.4c9e09e173000p-2, -0x1.e20891b0ad8a4p-45) +A(0x1.7000000000000p-1, 0x1.522ae0738a000p-2, 0x1.ebe708164c759p-45) +A(0x1.6e00000000000p-1, 0x1.57bf753c8d000p-2, 0x1.fadedee5d40efp-46) +A(0x1.6c00000000000p-1, 0x1.5d5bddf596000p-2, -0x1.a0b2a08a465dcp-47) +}, +}; diff --git a/src/orca-libc/src/math/pow_data.h b/src/orca-libc/src/math/pow_data.h new file mode 100644 index 00000000..5d609ae8 --- /dev/null +++ b/src/orca-libc/src/math/pow_data.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018, Arm Limited. + * SPDX-License-Identifier: MIT + */ +#ifndef _POW_DATA_H +#define _POW_DATA_H + +#include + +#define POW_LOG_TABLE_BITS 7 +#define POW_LOG_POLY_ORDER 8 +extern hidden const struct pow_log_data { + double ln2hi; + double ln2lo; + double poly[POW_LOG_POLY_ORDER - 1]; /* First coefficient is 1. */ + /* Note: the pad field is unused, but allows slightly faster indexing. */ + struct { + double invc, pad, logc, logctail; + } tab[1 << POW_LOG_TABLE_BITS]; +} __pow_log_data; + +#endif diff --git a/src/libc-shim/src/powf.c b/src/orca-libc/src/math/powf.c similarity index 97% rename from src/libc-shim/src/powf.c rename to src/orca-libc/src/math/powf.c index 2356811a..de8fab54 100644 --- a/src/libc-shim/src/powf.c +++ b/src/orca-libc/src/math/powf.c @@ -152,9 +152,7 @@ float powf(float x, float y) x2 = -x2; /* Without the barrier some versions of clang hoist the 1/x2 and thus division by zero exception can be signaled spuriously. */ - // NOTE(orca): no fp barriers - //return iy & 0x80000000 ? fp_barrierf(1 / x2) : x2; - return iy & 0x80000000 ? (1 / x2) : x2; + return iy & 0x80000000 ? fp_barrierf(1 / x2) : x2; } /* x and y are non-zero finite. */ if (ix & 0x80000000) { diff --git a/src/libc-shim/src/powf_data.c b/src/orca-libc/src/math/powf_data.c similarity index 100% rename from src/libc-shim/src/powf_data.c rename to src/orca-libc/src/math/powf_data.c diff --git a/src/libc-shim/src/powf_data.h b/src/orca-libc/src/math/powf_data.h similarity index 92% rename from src/libc-shim/src/powf_data.h rename to src/orca-libc/src/math/powf_data.h index a7b997a6..5b136e28 100644 --- a/src/libc-shim/src/powf_data.h +++ b/src/orca-libc/src/math/powf_data.h @@ -16,7 +16,7 @@ #define POWF_SCALE_BITS 0 #endif #define POWF_SCALE ((double)(1 << POWF_SCALE_BITS)) -extern const struct powf_log2_data { +extern hidden const struct powf_log2_data { struct { double invc, logc; } tab[1 << POWF_LOG2_TABLE_BITS]; diff --git a/src/orca-libc/src/math/powl.c b/src/orca-libc/src/math/powl.c new file mode 100644 index 00000000..c8463b7a --- /dev/null +++ b/src/orca-libc/src/math/powl.c @@ -0,0 +1,526 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_powl.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* powl.c + * + * Power function, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, z, powl(); + * + * z = powl( x, y ); + * + * + * DESCRIPTION: + * + * Computes x raised to the yth power. Analytically, + * + * x**y = exp( y log(x) ). + * + * Following Cody and Waite, this program uses a lookup table + * of 2**-i/32 and pseudo extended precision arithmetic to + * obtain several extra bits of accuracy in both the logarithm + * and the exponential. + * + * + * ACCURACY: + * + * The relative error of pow(x,y) can be estimated + * by y dl ln(2), where dl is the absolute error of + * the internally computed base 2 logarithm. At the ends + * of the approximation interval the logarithm equal 1/32 + * and its relative error is about 1 lsb = 1.1e-19. Hence + * the predicted relative error in the result is 2.3e-21 y . + * + * Relative error: + * arithmetic domain # trials peak rms + * + * IEEE +-1000 40000 2.8e-18 3.7e-19 + * .001 < x < 1000, with log(x) uniformly distributed. + * -1000 < y < 1000, y uniformly distributed. + * + * IEEE 0,8700 60000 6.5e-18 1.0e-18 + * 0.99 < x < 1.01, 0 < y < 8700, uniformly distributed. + * + * + * ERROR MESSAGES: + * + * message condition value returned + * pow overflow x**y > MAXNUM INFINITY + * pow underflow x**y < 1/MAXNUM 0.0 + * pow domain x<0 and y noninteger 0.0 + * + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double powl(long double x, long double y) +{ + return pow(x, y); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 + +/* Table size */ +#define NXT 32 + +/* log(1+x) = x - .5x^2 + x^3 * P(z)/Q(z) + * on the domain 2^(-1/32) - 1 <= x <= 2^(1/32) - 1 + */ +static const long double P[] = { + 8.3319510773868690346226E-4L, + 4.9000050881978028599627E-1L, + 1.7500123722550302671919E0L, + 1.4000100839971580279335E0L, +}; +static const long double Q[] = { +/* 1.0000000000000000000000E0L,*/ + 5.2500282295834889175431E0L, + 8.4000598057587009834666E0L, + 4.2000302519914740834728E0L, +}; +/* A[i] = 2^(-i/32), rounded to IEEE long double precision. + * If i is even, A[i] + B[i/2] gives additional accuracy. + */ +static const long double A[33] = { + 1.0000000000000000000000E0L, + 9.7857206208770013448287E-1L, + 9.5760328069857364691013E-1L, + 9.3708381705514995065011E-1L, + 9.1700404320467123175367E-1L, + 8.9735453750155359320742E-1L, + 8.7812608018664974155474E-1L, + 8.5930964906123895780165E-1L, + 8.4089641525371454301892E-1L, + 8.2287773907698242225554E-1L, + 8.0524516597462715409607E-1L, + 7.8799042255394324325455E-1L, + 7.7110541270397041179298E-1L, + 7.5458221379671136985669E-1L, + 7.3841307296974965571198E-1L, + 7.2259040348852331001267E-1L, + 7.0710678118654752438189E-1L, + 6.9195494098191597746178E-1L, + 6.7712777346844636413344E-1L, + 6.6261832157987064729696E-1L, + 6.4841977732550483296079E-1L, + 6.3452547859586661129850E-1L, + 6.2092890603674202431705E-1L, + 6.0762367999023443907803E-1L, + 5.9460355750136053334378E-1L, + 5.8186242938878875689693E-1L, + 5.6939431737834582684856E-1L, + 5.5719337129794626814472E-1L, + 5.4525386633262882960438E-1L, + 5.3357020033841180906486E-1L, + 5.2213689121370692017331E-1L, + 5.1094857432705833910408E-1L, + 5.0000000000000000000000E-1L, +}; +static const long double B[17] = { + 0.0000000000000000000000E0L, + 2.6176170809902549338711E-20L, +-1.0126791927256478897086E-20L, + 1.3438228172316276937655E-21L, + 1.2207982955417546912101E-20L, +-6.3084814358060867200133E-21L, + 1.3164426894366316434230E-20L, +-1.8527916071632873716786E-20L, + 1.8950325588932570796551E-20L, + 1.5564775779538780478155E-20L, + 6.0859793637556860974380E-21L, +-2.0208749253662532228949E-20L, + 1.4966292219224761844552E-20L, + 3.3540909728056476875639E-21L, +-8.6987564101742849540743E-22L, +-1.2327176863327626135542E-20L, + 0.0000000000000000000000E0L, +}; + +/* 2^x = 1 + x P(x), + * on the interval -1/32 <= x <= 0 + */ +static const long double R[] = { + 1.5089970579127659901157E-5L, + 1.5402715328927013076125E-4L, + 1.3333556028915671091390E-3L, + 9.6181291046036762031786E-3L, + 5.5504108664798463044015E-2L, + 2.4022650695910062854352E-1L, + 6.9314718055994530931447E-1L, +}; + +#define MEXP (NXT*16384.0L) +/* The following if denormal numbers are supported, else -MEXP: */ +#define MNEXP (-NXT*(16384.0L+64.0L)) +/* log2(e) - 1 */ +#define LOG2EA 0.44269504088896340735992L + +#define F W +#define Fa Wa +#define Fb Wb +#define G W +#define Ga Wa +#define Gb u +#define H W +#define Ha Wb +#define Hb Wb + +static const long double MAXLOGL = 1.1356523406294143949492E4L; +static const long double MINLOGL = -1.13994985314888605586758E4L; +static const long double LOGE2L = 6.9314718055994530941723E-1L; +static const long double huge = 0x1p10000L; +/* XXX Prevent gcc from erroneously constant folding this. */ +#ifdef __wasilibc_unmodified_upstream // WASI doesn't need old GCC workarounds +static const volatile long double twom10000 = 0x1p-10000L; +#else +static const long double twom10000 = 0x1p-10000L; +#endif + +static long double reducl(long double); +static long double powil(long double, int); + +long double powl(long double x, long double y) +{ + /* double F, Fa, Fb, G, Ga, Gb, H, Ha, Hb */ + int i, nflg, iyflg, yoddint; + long e; + volatile long double z=0; + long double w=0, W=0, Wa=0, Wb=0, ya=0, yb=0, u=0; + + /* make sure no invalid exception is raised by nan comparision */ + if (isnan(x)) { + if (!isnan(y) && y == 0.0) + return 1.0; + return x; + } + if (isnan(y)) { + if (x == 1.0) + return 1.0; + return y; + } + if (x == 1.0) + return 1.0; /* 1**y = 1, even if y is nan */ + if (x == -1.0 && !isfinite(y)) + return 1.0; /* -1**inf = 1 */ + if (y == 0.0) + return 1.0; /* x**0 = 1, even if x is nan */ + if (y == 1.0) + return x; + if (y >= LDBL_MAX) { + if (x > 1.0 || x < -1.0) + return INFINITY; + if (x != 0.0) + return 0.0; + } + if (y <= -LDBL_MAX) { + if (x > 1.0 || x < -1.0) + return 0.0; + if (x != 0.0 || y == -INFINITY) + return INFINITY; + } + if (x >= LDBL_MAX) { + if (y > 0.0) + return INFINITY; + return 0.0; + } + + w = floorl(y); + + /* Set iyflg to 1 if y is an integer. */ + iyflg = 0; + if (w == y) + iyflg = 1; + + /* Test for odd integer y. */ + yoddint = 0; + if (iyflg) { + ya = fabsl(y); + ya = floorl(0.5 * ya); + yb = 0.5 * fabsl(w); + if( ya != yb ) + yoddint = 1; + } + + if (x <= -LDBL_MAX) { + if (y > 0.0) { + if (yoddint) + return -INFINITY; + return INFINITY; + } + if (y < 0.0) { + if (yoddint) + return -0.0; + return 0.0; + } + } + nflg = 0; /* (x<0)**(odd int) */ + if (x <= 0.0) { + if (x == 0.0) { + if (y < 0.0) { + if (signbit(x) && yoddint) + /* (-0.0)**(-odd int) = -inf, divbyzero */ + return -1.0/0.0; + /* (+-0.0)**(negative) = inf, divbyzero */ + return 1.0/0.0; + } + if (signbit(x) && yoddint) + return -0.0; + return 0.0; + } + if (iyflg == 0) + return (x - x) / (x - x); /* (x<0)**(non-int) is NaN */ + /* (x<0)**(integer) */ + if (yoddint) + nflg = 1; /* negate result */ + x = -x; + } + /* (+integer)**(integer) */ + if (iyflg && floorl(x) == x && fabsl(y) < 32768.0) { + w = powil(x, (int)y); + return nflg ? -w : w; + } + + /* separate significand from exponent */ + x = frexpl(x, &i); + e = i; + + /* find significand in antilog table A[] */ + i = 1; + if (x <= A[17]) + i = 17; + if (x <= A[i+8]) + i += 8; + if (x <= A[i+4]) + i += 4; + if (x <= A[i+2]) + i += 2; + if (x >= A[1]) + i = -1; + i += 1; + + /* Find (x - A[i])/A[i] + * in order to compute log(x/A[i]): + * + * log(x) = log( a x/a ) = log(a) + log(x/a) + * + * log(x/a) = log(1+v), v = x/a - 1 = (x-a)/a + */ + x -= A[i]; + x -= B[i/2]; + x /= A[i]; + + /* rational approximation for log(1+v): + * + * log(1+v) = v - v**2/2 + v**3 P(v) / Q(v) + */ + z = x*x; + w = x * (z * __polevll(x, P, 3) / __p1evll(x, Q, 3)); + w = w - 0.5*z; + + /* Convert to base 2 logarithm: + * multiply by log2(e) = 1 + LOG2EA + */ + z = LOG2EA * w; + z += w; + z += LOG2EA * x; + z += x; + + /* Compute exponent term of the base 2 logarithm. */ + w = -i; + w /= NXT; + w += e; + /* Now base 2 log of x is w + z. */ + + /* Multiply base 2 log by y, in extended precision. */ + + /* separate y into large part ya + * and small part yb less than 1/NXT + */ + ya = reducl(y); + yb = y - ya; + + /* (w+z)(ya+yb) + * = w*ya + w*yb + z*y + */ + F = z * y + w * yb; + Fa = reducl(F); + Fb = F - Fa; + + G = Fa + w * ya; + Ga = reducl(G); + Gb = G - Ga; + + H = Fb + Gb; + Ha = reducl(H); + w = (Ga + Ha) * NXT; + + /* Test the power of 2 for overflow */ + if (w > MEXP) + return huge * huge; /* overflow */ + if (w < MNEXP) + return twom10000 * twom10000; /* underflow */ + + e = w; + Hb = H - Ha; + + if (Hb > 0.0) { + e += 1; + Hb -= 1.0/NXT; /*0.0625L;*/ + } + + /* Now the product y * log2(x) = Hb + e/NXT. + * + * Compute base 2 exponential of Hb, + * where -0.0625 <= Hb <= 0. + */ + z = Hb * __polevll(Hb, R, 6); /* z = 2**Hb - 1 */ + + /* Express e/NXT as an integer plus a negative number of (1/NXT)ths. + * Find lookup table entry for the fractional power of 2. + */ + if (e < 0) + i = 0; + else + i = 1; + i = e/NXT + i; + e = NXT*i - e; + w = A[e]; + z = w * z; /* 2**-e * ( 1 + (2**Hb-1) ) */ + z = z + w; + z = scalbnl(z, i); /* multiply by integer power of 2 */ + + if (nflg) + z = -z; + return z; +} + + +/* Find a multiple of 1/NXT that is within 1/NXT of x. */ +static long double reducl(long double x) +{ + long double t; + + t = x * NXT; + t = floorl(t); + t = t / NXT; + return t; +} + +/* + * Positive real raised to integer power, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, powil(); + * int n; + * + * y = powil( x, n ); + * + * + * DESCRIPTION: + * + * Returns argument x>0 raised to the nth power. + * The routine efficiently decomposes n as a sum of powers of + * two. The desired power is a product of two-to-the-kth + * powers of x. Thus to compute the 32767 power of x requires + * 28 multiplications instead of 32767 multiplications. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic x domain n domain # trials peak rms + * IEEE .001,1000 -1022,1023 50000 4.3e-17 7.8e-18 + * IEEE 1,2 -1022,1023 20000 3.9e-17 7.6e-18 + * IEEE .99,1.01 0,8700 10000 3.6e-16 7.2e-17 + * + * Returns MAXNUM on overflow, zero on underflow. + */ + +static long double powil(long double x, int nn) +{ + long double ww, y; + long double s; + int n, e, sign, lx; + + if (nn == 0) + return 1.0; + + if (nn < 0) { + sign = -1; + n = -nn; + } else { + sign = 1; + n = nn; + } + + /* Overflow detection */ + + /* Calculate approximate logarithm of answer */ + s = x; + s = frexpl( s, &lx); + e = (lx - 1)*n; + if ((e == 0) || (e > 64) || (e < -64)) { + s = (s - 7.0710678118654752e-1L) / (s + 7.0710678118654752e-1L); + s = (2.9142135623730950L * s - 0.5 + lx) * nn * LOGE2L; + } else { + s = LOGE2L * e; + } + + if (s > MAXLOGL) + return huge * huge; /* overflow */ + + if (s < MINLOGL) + return twom10000 * twom10000; /* underflow */ + /* Handle tiny denormal answer, but with less accuracy + * since roundoff error in 1.0/x will be amplified. + * The precise demarcation should be the gradual underflow threshold. + */ + if (s < -MAXLOGL+2.0) { + x = 1.0/x; + sign = -sign; + } + + /* First bit of the power */ + if (n & 1) + y = x; + else + y = 1.0; + + ww = x; + n >>= 1; + while (n) { + ww = ww * ww; /* arg to the 2-to-the-kth power */ + if (n & 1) /* if that bit is set, then include in product */ + y *= ww; + n >>= 1; + } + + if (sign < 0) + y = 1.0/y; + return y; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double powl(long double x, long double y) +{ + return pow(x, y); +} +#endif diff --git a/src/orca-libc/src/math/remainder.c b/src/orca-libc/src/math/remainder.c new file mode 100644 index 00000000..612155fe --- /dev/null +++ b/src/orca-libc/src/math/remainder.c @@ -0,0 +1,9 @@ +#include + +double remainder(double x, double y) +{ + int q; + return remquo(x, y, &q); +} + +weak_alias(remainder, drem); diff --git a/src/orca-libc/src/math/remainderf.c b/src/orca-libc/src/math/remainderf.c new file mode 100644 index 00000000..bf1d7b28 --- /dev/null +++ b/src/orca-libc/src/math/remainderf.c @@ -0,0 +1,9 @@ +#include + +float remainderf(float x, float y) +{ + int q; + return remquof(x, y, &q); +} + +weak_alias(remainderf, dremf); diff --git a/src/orca-libc/src/math/remainderl.c b/src/orca-libc/src/math/remainderl.c new file mode 100644 index 00000000..2a13c1d5 --- /dev/null +++ b/src/orca-libc/src/math/remainderl.c @@ -0,0 +1,15 @@ +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double remainderl(long double x, long double y) +{ + return remainder(x, y); +} +#else +long double remainderl(long double x, long double y) +{ + int q; + return remquol(x, y, &q); +} +#endif diff --git a/src/orca-libc/src/math/remquo.c b/src/orca-libc/src/math/remquo.c new file mode 100644 index 00000000..59d5ad57 --- /dev/null +++ b/src/orca-libc/src/math/remquo.c @@ -0,0 +1,82 @@ +#include +#include + +double remquo(double x, double y, int *quo) +{ + union {double f; uint64_t i;} ux = {x}, uy = {y}; + int ex = ux.i>>52 & 0x7ff; + int ey = uy.i>>52 & 0x7ff; + int sx = ux.i>>63; + int sy = uy.i>>63; + uint32_t q; + uint64_t i; + uint64_t uxi = ux.i; + + *quo = 0; + if (uy.i<<1 == 0 || isnan(y) || ex == 0x7ff) + return (x*y)/(x*y); + if (ux.i<<1 == 0) + return x; + + /* normalize x and y */ + if (!ex) { + for (i = uxi<<12; i>>63 == 0; ex--, i <<= 1); + uxi <<= -ex + 1; + } else { + uxi &= -1ULL >> 12; + uxi |= 1ULL << 52; + } + if (!ey) { + for (i = uy.i<<12; i>>63 == 0; ey--, i <<= 1); + uy.i <<= -ey + 1; + } else { + uy.i &= -1ULL >> 12; + uy.i |= 1ULL << 52; + } + + q = 0; + if (ex < ey) { + if (ex+1 == ey) + goto end; + return x; + } + + /* x mod y */ + for (; ex > ey; ex--) { + i = uxi - uy.i; + if (i >> 63 == 0) { + uxi = i; + q++; + } + uxi <<= 1; + q <<= 1; + } + i = uxi - uy.i; + if (i >> 63 == 0) { + uxi = i; + q++; + } + if (uxi == 0) + ex = -60; + else + for (; uxi>>52 == 0; uxi <<= 1, ex--); +end: + /* scale result and decide between |x| and |x|-|y| */ + if (ex > 0) { + uxi -= 1ULL << 52; + uxi |= (uint64_t)ex << 52; + } else { + uxi >>= -ex + 1; + } + ux.i = uxi; + x = ux.f; + if (sy) + y = -y; + if (ex == ey || (ex+1 == ey && (2*x > y || (2*x == y && q%2)))) { + x -= y; + q++; + } + q &= 0x7fffffff; + *quo = sx^sy ? -(int)q : (int)q; + return sx ? -x : x; +} diff --git a/src/orca-libc/src/math/remquof.c b/src/orca-libc/src/math/remquof.c new file mode 100644 index 00000000..2f41ff70 --- /dev/null +++ b/src/orca-libc/src/math/remquof.c @@ -0,0 +1,82 @@ +#include +#include + +float remquof(float x, float y, int *quo) +{ + union {float f; uint32_t i;} ux = {x}, uy = {y}; + int ex = ux.i>>23 & 0xff; + int ey = uy.i>>23 & 0xff; + int sx = ux.i>>31; + int sy = uy.i>>31; + uint32_t q; + uint32_t i; + uint32_t uxi = ux.i; + + *quo = 0; + if (uy.i<<1 == 0 || isnan(y) || ex == 0xff) + return (x*y)/(x*y); + if (ux.i<<1 == 0) + return x; + + /* normalize x and y */ + if (!ex) { + for (i = uxi<<9; i>>31 == 0; ex--, i <<= 1); + uxi <<= -ex + 1; + } else { + uxi &= -1U >> 9; + uxi |= 1U << 23; + } + if (!ey) { + for (i = uy.i<<9; i>>31 == 0; ey--, i <<= 1); + uy.i <<= -ey + 1; + } else { + uy.i &= -1U >> 9; + uy.i |= 1U << 23; + } + + q = 0; + if (ex < ey) { + if (ex+1 == ey) + goto end; + return x; + } + + /* x mod y */ + for (; ex > ey; ex--) { + i = uxi - uy.i; + if (i >> 31 == 0) { + uxi = i; + q++; + } + uxi <<= 1; + q <<= 1; + } + i = uxi - uy.i; + if (i >> 31 == 0) { + uxi = i; + q++; + } + if (uxi == 0) + ex = -30; + else + for (; uxi>>23 == 0; uxi <<= 1, ex--); +end: + /* scale result and decide between |x| and |x|-|y| */ + if (ex > 0) { + uxi -= 1U << 23; + uxi |= (uint32_t)ex << 23; + } else { + uxi >>= -ex + 1; + } + ux.i = uxi; + x = ux.f; + if (sy) + y = -y; + if (ex == ey || (ex+1 == ey && (2*x > y || (2*x == y && q%2)))) { + x -= y; + q++; + } + q &= 0x7fffffff; + *quo = sx^sy ? -(int)q : (int)q; + return sx ? -x : x; +} diff --git a/src/orca-libc/src/math/remquol.c b/src/orca-libc/src/math/remquol.c new file mode 100644 index 00000000..9b065c00 --- /dev/null +++ b/src/orca-libc/src/math/remquol.c @@ -0,0 +1,124 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double remquol(long double x, long double y, int *quo) +{ + return remquo(x, y, quo); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double remquol(long double x, long double y, int *quo) +{ + union ldshape ux = {x}, uy = {y}; + int ex = ux.i.se & 0x7fff; + int ey = uy.i.se & 0x7fff; + int sx = ux.i.se >> 15; + int sy = uy.i.se >> 15; + uint32_t q; + + *quo = 0; + if (y == 0 || isnan(y) || ex == 0x7fff) + return (x*y)/(x*y); + if (x == 0) + return x; + + /* normalize x and y */ + if (!ex) { + ux.i.se = ex; + ux.f *= 0x1p120f; + ex = ux.i.se - 120; + } + if (!ey) { + uy.i.se = ey; + uy.f *= 0x1p120f; + ey = uy.i.se - 120; + } + + q = 0; + if (ex >= ey) { + /* x mod y */ +#if LDBL_MANT_DIG == 64 + uint64_t i, mx, my; + mx = ux.i.m; + my = uy.i.m; + for (; ex > ey; ex--) { + i = mx - my; + if (mx >= my) { + mx = 2*i; + q++; + q <<= 1; + } else if (2*mx < mx) { + mx = 2*mx - my; + q <<= 1; + q++; + } else { + mx = 2*mx; + q <<= 1; + } + } + i = mx - my; + if (mx >= my) { + mx = i; + q++; + } + if (mx == 0) + ex = -120; + else + for (; mx >> 63 == 0; mx *= 2, ex--); + ux.i.m = mx; +#elif LDBL_MANT_DIG == 113 + uint64_t hi, lo, xhi, xlo, yhi, ylo; + xhi = (ux.i2.hi & -1ULL>>16) | 1ULL<<48; + yhi = (uy.i2.hi & -1ULL>>16) | 1ULL<<48; + xlo = ux.i2.lo; + ylo = ux.i2.lo; + for (; ex > ey; ex--) { + hi = xhi - yhi; + lo = xlo - ylo; + if (xlo < ylo) + hi -= 1; + if (hi >> 63 == 0) { + xhi = 2*hi + (lo>>63); + xlo = 2*lo; + q++; + } else { + xhi = 2*xhi + (xlo>>63); + xlo = 2*xlo; + } + q <<= 1; + } + hi = xhi - yhi; + lo = xlo - ylo; + if (xlo < ylo) + hi -= 1; + if (hi >> 63 == 0) { + xhi = hi; + xlo = lo; + q++; + } + if ((xhi|xlo) == 0) + ex = -120; + else + for (; xhi >> 48 == 0; xhi = 2*xhi + (xlo>>63), xlo = 2*xlo, ex--); + ux.i2.hi = xhi; + ux.i2.lo = xlo; +#endif + } + + /* scale result and decide between |x| and |x|-|y| */ + if (ex <= 0) { + ux.i.se = ex + 120; + ux.f *= 0x1p-120f; + } else + ux.i.se = ex; + x = ux.f; + if (sy) + y = -y; + if (ex == ey || (ex+1 == ey && (2*x > y || (2*x == y && q%2)))) { + x -= y; + q++; + } + q &= 0x7fffffff; + *quo = sx^sy ? -(int)q : (int)q; + return sx ? -x : x; +} +#endif diff --git a/src/orca-libc/src/math/rint.c b/src/orca-libc/src/math/rint.c new file mode 100644 index 00000000..fbba390e --- /dev/null +++ b/src/orca-libc/src/math/rint.c @@ -0,0 +1,28 @@ +#include +#include +#include + +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const double_t toint = 1/EPS; + +double rint(double x) +{ + union {double f; uint64_t i;} u = {x}; + int e = u.i>>52 & 0x7ff; + int s = u.i>>63; + double_t y; + + if (e >= 0x3ff+52) + return x; + if (s) + y = x - toint + toint; + else + y = x + toint - toint; + if (y == 0) + return s ? -0.0 : 0; + return y; +} diff --git a/src/orca-libc/src/math/rintf.c b/src/orca-libc/src/math/rintf.c new file mode 100644 index 00000000..9047688d --- /dev/null +++ b/src/orca-libc/src/math/rintf.c @@ -0,0 +1,30 @@ +#include +#include +#include + +#if FLT_EVAL_METHOD==0 +#define EPS FLT_EPSILON +#elif FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const float_t toint = 1/EPS; + +float rintf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = u.i>>23 & 0xff; + int s = u.i>>31; + float_t y; + + if (e >= 0x7f+23) + return x; + if (s) + y = x - toint + toint; + else + y = x + toint - toint; + if (y == 0) + return s ? -0.0f : 0.0f; + return y; +} diff --git a/src/orca-libc/src/math/rintl.c b/src/orca-libc/src/math/rintl.c new file mode 100644 index 00000000..374327db --- /dev/null +++ b/src/orca-libc/src/math/rintl.c @@ -0,0 +1,29 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double rintl(long double x) +{ + return rint(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +static const long double toint = 1/LDBL_EPSILON; + +long double rintl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + int s = u.i.se >> 15; + long double y; + + if (e >= 0x3fff+LDBL_MANT_DIG-1) + return x; + if (s) + y = x - toint + toint; + else + y = x + toint - toint; + if (y == 0) + return 0*x; + return y; +} +#endif diff --git a/src/orca-libc/src/math/round.c b/src/orca-libc/src/math/round.c new file mode 100644 index 00000000..130d58d2 --- /dev/null +++ b/src/orca-libc/src/math/round.c @@ -0,0 +1,35 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const double_t toint = 1/EPS; + +double round(double x) +{ + union {double f; uint64_t i;} u = {x}; + int e = u.i >> 52 & 0x7ff; + double_t y; + + if (e >= 0x3ff+52) + return x; + if (u.i >> 63) + x = -x; + if (e < 0x3ff-1) { + /* raise inexact if x!=0 */ + FORCE_EVAL(x + toint); + return 0*u.f; + } + y = x + toint - toint - x; + if (y > 0.5) + y = y + x - 1; + else if (y <= -0.5) + y = y + x + 1; + else + y = y + x; + if (u.i >> 63) + y = -y; + return y; +} diff --git a/src/orca-libc/src/math/roundf.c b/src/orca-libc/src/math/roundf.c new file mode 100644 index 00000000..e8210af5 --- /dev/null +++ b/src/orca-libc/src/math/roundf.c @@ -0,0 +1,36 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD==0 +#define EPS FLT_EPSILON +#elif FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const float_t toint = 1/EPS; + +float roundf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = u.i >> 23 & 0xff; + float_t y; + + if (e >= 0x7f+23) + return x; + if (u.i >> 31) + x = -x; + if (e < 0x7f-1) { + FORCE_EVAL(x + toint); + return 0*u.f; + } + y = x + toint - toint - x; + if (y > 0.5f) + y = y + x - 1; + else if (y <= -0.5f) + y = y + x + 1; + else + y = y + x; + if (u.i >> 31) + y = -y; + return y; +} diff --git a/src/orca-libc/src/math/roundl.c b/src/orca-libc/src/math/roundl.c new file mode 100644 index 00000000..f4ff6820 --- /dev/null +++ b/src/orca-libc/src/math/roundl.c @@ -0,0 +1,37 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double roundl(long double x) +{ + return round(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +static const long double toint = 1/LDBL_EPSILON; + +long double roundl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + long double y; + + if (e >= 0x3fff+LDBL_MANT_DIG-1) + return x; + if (u.i.se >> 15) + x = -x; + if (e < 0x3fff-1) { + FORCE_EVAL(x + toint); + return 0*u.f; + } + y = x + toint - toint - x; + if (y > 0.5) + y = y + x - 1; + else if (y <= -0.5) + y = y + x + 1; + else + y = y + x; + if (u.i.se >> 15) + y = -y; + return y; +} +#endif diff --git a/src/orca-libc/src/math/scalb.c b/src/orca-libc/src/math/scalb.c new file mode 100644 index 00000000..efe69e60 --- /dev/null +++ b/src/orca-libc/src/math/scalb.c @@ -0,0 +1,35 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_scalb.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * scalb(x, fn) is provide for + * passing various standard test suite. One + * should use scalbn() instead. + */ + +#define _GNU_SOURCE +#include + +double scalb(double x, double fn) +{ + if (isnan(x) || isnan(fn)) + return x*fn; + if (!isfinite(fn)) { + if (fn > 0.0) + return x*fn; + else + return x/(-fn); + } + if (rint(fn) != fn) return (fn-fn)/(fn-fn); + if ( fn > 65000.0) return scalbn(x, 65000); + if (-fn > 65000.0) return scalbn(x,-65000); + return scalbn(x,(int)fn); +} diff --git a/src/orca-libc/src/math/scalbf.c b/src/orca-libc/src/math/scalbf.c new file mode 100644 index 00000000..f44ed5b6 --- /dev/null +++ b/src/orca-libc/src/math/scalbf.c @@ -0,0 +1,32 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_scalbf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#define _GNU_SOURCE +#include + +float scalbf(float x, float fn) +{ + if (isnan(x) || isnan(fn)) return x*fn; + if (!isfinite(fn)) { + if (fn > 0.0f) + return x*fn; + else + return x/(-fn); + } + if (rintf(fn) != fn) return (fn-fn)/(fn-fn); + if ( fn > 65000.0f) return scalbnf(x, 65000); + if (-fn > 65000.0f) return scalbnf(x,-65000); + return scalbnf(x,(int)fn); +} diff --git a/src/orca-libc/src/math/scalbln.c b/src/orca-libc/src/math/scalbln.c new file mode 100644 index 00000000..e6f3f195 --- /dev/null +++ b/src/orca-libc/src/math/scalbln.c @@ -0,0 +1,11 @@ +#include +#include + +double scalbln(double x, long n) +{ + if (n > INT_MAX) + n = INT_MAX; + else if (n < INT_MIN) + n = INT_MIN; + return scalbn(x, n); +} diff --git a/src/orca-libc/src/math/scalblnf.c b/src/orca-libc/src/math/scalblnf.c new file mode 100644 index 00000000..d8e8166b --- /dev/null +++ b/src/orca-libc/src/math/scalblnf.c @@ -0,0 +1,11 @@ +#include +#include + +float scalblnf(float x, long n) +{ + if (n > INT_MAX) + n = INT_MAX; + else if (n < INT_MIN) + n = INT_MIN; + return scalbnf(x, n); +} diff --git a/src/orca-libc/src/math/scalblnl.c b/src/orca-libc/src/math/scalblnl.c new file mode 100644 index 00000000..854c51c4 --- /dev/null +++ b/src/orca-libc/src/math/scalblnl.c @@ -0,0 +1,19 @@ +#include +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double scalblnl(long double x, long n) +{ + return scalbln(x, n); +} +#else +long double scalblnl(long double x, long n) +{ + if (n > INT_MAX) + n = INT_MAX; + else if (n < INT_MIN) + n = INT_MIN; + return scalbnl(x, n); +} +#endif diff --git a/src/orca-libc/src/math/scalbn.c b/src/orca-libc/src/math/scalbn.c new file mode 100644 index 00000000..182f5610 --- /dev/null +++ b/src/orca-libc/src/math/scalbn.c @@ -0,0 +1,33 @@ +#include +#include + +double scalbn(double x, int n) +{ + union {double f; uint64_t i;} u; + double_t y = x; + + if (n > 1023) { + y *= 0x1p1023; + n -= 1023; + if (n > 1023) { + y *= 0x1p1023; + n -= 1023; + if (n > 1023) + n = 1023; + } + } else if (n < -1022) { + /* make sure final n < -53 to avoid double + rounding in the subnormal range */ + y *= 0x1p-1022 * 0x1p53; + n += 1022 - 53; + if (n < -1022) { + y *= 0x1p-1022 * 0x1p53; + n += 1022 - 53; + if (n < -1022) + n = -1022; + } + } + u.i = (uint64_t)(0x3ff+n)<<52; + x = y * u.f; + return x; +} diff --git a/src/orca-libc/src/math/scalbnf.c b/src/orca-libc/src/math/scalbnf.c new file mode 100644 index 00000000..a5ad208b --- /dev/null +++ b/src/orca-libc/src/math/scalbnf.c @@ -0,0 +1,31 @@ +#include +#include + +float scalbnf(float x, int n) +{ + union {float f; uint32_t i;} u; + float_t y = x; + + if (n > 127) { + y *= 0x1p127f; + n -= 127; + if (n > 127) { + y *= 0x1p127f; + n -= 127; + if (n > 127) + n = 127; + } + } else if (n < -126) { + y *= 0x1p-126f * 0x1p24f; + n += 126 - 24; + if (n < -126) { + y *= 0x1p-126f * 0x1p24f; + n += 126 - 24; + if (n < -126) + n = -126; + } + } + u.i = (uint32_t)(0x7f+n)<<23; + x = y * u.f; + return x; +} diff --git a/src/orca-libc/src/math/scalbnl.c b/src/orca-libc/src/math/scalbnl.c new file mode 100644 index 00000000..db44dab0 --- /dev/null +++ b/src/orca-libc/src/math/scalbnl.c @@ -0,0 +1,36 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double scalbnl(long double x, int n) +{ + return scalbn(x, n); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double scalbnl(long double x, int n) +{ + union ldshape u; + + if (n > 16383) { + x *= 0x1p16383L; + n -= 16383; + if (n > 16383) { + x *= 0x1p16383L; + n -= 16383; + if (n > 16383) + n = 16383; + } + } else if (n < -16382) { + x *= 0x1p-16382L * 0x1p113L; + n += 16382 - 113; + if (n < -16382) { + x *= 0x1p-16382L * 0x1p113L; + n += 16382 - 113; + if (n < -16382) + n = -16382; + } + } + u.f = 1.0; + u.i.se = 0x3fff + n; + return x * u.f; +} +#endif diff --git a/src/orca-libc/src/math/signgam.c b/src/orca-libc/src/math/signgam.c new file mode 100644 index 00000000..ee331b27 --- /dev/null +++ b/src/orca-libc/src/math/signgam.c @@ -0,0 +1,6 @@ +#include +#include "libm.h" + +int __signgam = 0; + +weak_alias(__signgam, signgam); diff --git a/src/orca-libc/src/math/significand.c b/src/orca-libc/src/math/significand.c new file mode 100644 index 00000000..40d9aa9f --- /dev/null +++ b/src/orca-libc/src/math/significand.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include + +double significand(double x) +{ + return scalbn(x, -ilogb(x)); +} diff --git a/src/orca-libc/src/math/significandf.c b/src/orca-libc/src/math/significandf.c new file mode 100644 index 00000000..8a697e1a --- /dev/null +++ b/src/orca-libc/src/math/significandf.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include + +float significandf(float x) +{ + return scalbnf(x, -ilogbf(x)); +} diff --git a/src/libc-shim/src/sin.c b/src/orca-libc/src/math/sin.c similarity index 64% rename from src/libc-shim/src/sin.c rename to src/orca-libc/src/math/sin.c index c5b9e394..055e215b 100644 --- a/src/libc-shim/src/sin.c +++ b/src/orca-libc/src/math/sin.c @@ -44,41 +44,35 @@ double sin(double x) { - double y[2]; - uint32_t ix; - unsigned n; + double y[2]; + uint32_t ix; + unsigned n; - /* High word of x. */ - GET_HIGH_WORD(ix, x); - ix &= 0x7fffffff; + /* High word of x. */ + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; - /* |x| ~< pi/4 */ - if(ix <= 0x3fe921fb) - { - if(ix < 0x3e500000) - { /* |x| < 2**-26 */ - /* raise inexact if x != 0 and underflow if subnormal*/ - FORCE_EVAL(ix < 0x00100000 ? x / 0x1p120f : x + 0x1p120f); - return x; - } - return __sin(x, 0.0, 0); - } + /* |x| ~< pi/4 */ + if (ix <= 0x3fe921fb) { + if (ix < 0x3e500000) { /* |x| < 2**-26 */ + /* raise inexact if x != 0 and underflow if subnormal*/ + FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f); + return x; + } + return __sin(x, 0.0, 0); + } - /* sin(Inf or NaN) is NaN */ - if(ix >= 0x7ff00000) - return x - x; + /* sin(Inf or NaN) is NaN */ + if (ix >= 0x7ff00000) + return x - x; - /* argument reduction needed */ - n = __rem_pio2(x, y); - switch(n & 3) - { - case 0: - return __sin(y[0], y[1], 1); - case 1: - return __cos(y[0], y[1]); - case 2: - return -__sin(y[0], y[1], 1); - default: - return -__cos(y[0], y[1]); - } + /* argument reduction needed */ + n = __rem_pio2(x, y); + switch (n&3) { + case 0: return __sin(y[0], y[1], 1); + case 1: return __cos(y[0], y[1]); + case 2: return -__sin(y[0], y[1], 1); + default: + return -__cos(y[0], y[1]); + } } diff --git a/src/orca-libc/src/math/sincos.c b/src/orca-libc/src/math/sincos.c new file mode 100644 index 00000000..35b2d923 --- /dev/null +++ b/src/orca-libc/src/math/sincos.c @@ -0,0 +1,69 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#define _GNU_SOURCE +#include "libm.h" + +void sincos(double x, double *sin, double *cos) +{ + double y[2], s, c; + uint32_t ix; + unsigned n; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + + /* |x| ~< pi/4 */ + if (ix <= 0x3fe921fb) { + /* if |x| < 2**-27 * sqrt(2) */ + if (ix < 0x3e46a09e) { + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f); + *sin = x; + *cos = 1.0; + return; + } + *sin = __sin(x, 0.0, 0); + *cos = __cos(x, 0.0); + return; + } + + /* sincos(Inf or NaN) is NaN */ + if (ix >= 0x7ff00000) { + *sin = *cos = x - x; + return; + } + + /* argument reduction needed */ + n = __rem_pio2(x, y); + s = __sin(y[0], y[1], 1); + c = __cos(y[0], y[1]); + switch (n&3) { + case 0: + *sin = s; + *cos = c; + break; + case 1: + *sin = c; + *cos = -s; + break; + case 2: + *sin = -s; + *cos = -c; + break; + case 3: + default: + *sin = -c; + *cos = s; + break; + } +} diff --git a/src/orca-libc/src/math/sincosf.c b/src/orca-libc/src/math/sincosf.c new file mode 100644 index 00000000..f8ca7232 --- /dev/null +++ b/src/orca-libc/src/math/sincosf.c @@ -0,0 +1,117 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#define _GNU_SOURCE +#include "libm.h" + +/* Small multiples of pi/2 rounded to double precision. */ +static const double +s1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ +s2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ +s3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ +s4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + +void sincosf(float x, float *sin, float *cos) +{ + double y; + float_t s, c; + uint32_t ix; + unsigned n, sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + + /* |x| ~<= pi/4 */ + if (ix <= 0x3f490fda) { + /* |x| < 2**-12 */ + if (ix < 0x39800000) { + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f); + *sin = x; + *cos = 1.0f; + return; + } + *sin = __sindf(x); + *cos = __cosdf(x); + return; + } + + /* |x| ~<= 5*pi/4 */ + if (ix <= 0x407b53d1) { + if (ix <= 0x4016cbe3) { /* |x| ~<= 3pi/4 */ + if (sign) { + *sin = -__cosdf(x + s1pio2); + *cos = __sindf(x + s1pio2); + } else { + *sin = __cosdf(s1pio2 - x); + *cos = __sindf(s1pio2 - x); + } + return; + } + /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ + *sin = -__sindf(sign ? x + s2pio2 : x - s2pio2); + *cos = -__cosdf(sign ? x + s2pio2 : x - s2pio2); + return; + } + + /* |x| ~<= 9*pi/4 */ + if (ix <= 0x40e231d5) { + if (ix <= 0x40afeddf) { /* |x| ~<= 7*pi/4 */ + if (sign) { + *sin = __cosdf(x + s3pio2); + *cos = -__sindf(x + s3pio2); + } else { + *sin = -__cosdf(x - s3pio2); + *cos = __sindf(x - s3pio2); + } + return; + } + *sin = __sindf(sign ? x + s4pio2 : x - s4pio2); + *cos = __cosdf(sign ? x + s4pio2 : x - s4pio2); + return; + } + + /* sin(Inf or NaN) is NaN */ + if (ix >= 0x7f800000) { + *sin = *cos = x - x; + return; + } + + /* general argument reduction needed */ + n = __rem_pio2f(x, &y); + s = __sindf(y); + c = __cosdf(y); + switch (n&3) { + case 0: + *sin = s; + *cos = c; + break; + case 1: + *sin = c; + *cos = -s; + break; + case 2: + *sin = -s; + *cos = -c; + break; + case 3: + default: + *sin = -c; + *cos = s; + break; + } +} diff --git a/src/orca-libc/src/math/sincosl.c b/src/orca-libc/src/math/sincosl.c new file mode 100644 index 00000000..d3ac1c4c --- /dev/null +++ b/src/orca-libc/src/math/sincosl.c @@ -0,0 +1,60 @@ +#define _GNU_SOURCE +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +void sincosl(long double x, long double *sin, long double *cos) +{ + double sind, cosd; + sincos(x, &sind, &cosd); + *sin = sind; + *cos = cosd; +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +void sincosl(long double x, long double *sin, long double *cos) +{ + union ldshape u = {x}; + unsigned n; + long double y[2], s, c; + + u.i.se &= 0x7fff; + if (u.i.se == 0x7fff) { + *sin = *cos = x - x; + return; + } + if (u.f < M_PI_4) { + if (u.i.se < 0x3fff - LDBL_MANT_DIG) { + /* raise underflow if subnormal */ + if (u.i.se == 0) FORCE_EVAL(x*0x1p-120f); + *sin = x; + /* raise inexact if x!=0 */ + *cos = 1.0 + x; + return; + } + *sin = __sinl(x, 0, 0); + *cos = __cosl(x, 0); + return; + } + n = __rem_pio2l(x, y); + s = __sinl(y[0], y[1], 1); + c = __cosl(y[0], y[1]); + switch (n & 3) { + case 0: + *sin = s; + *cos = c; + break; + case 1: + *sin = c; + *cos = -s; + break; + case 2: + *sin = -s; + *cos = -c; + break; + case 3: + default: + *sin = -c; + *cos = s; + break; + } +} +#endif diff --git a/src/orca-libc/src/math/sinf.c b/src/orca-libc/src/math/sinf.c new file mode 100644 index 00000000..64e39f50 --- /dev/null +++ b/src/orca-libc/src/math/sinf.c @@ -0,0 +1,76 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +/* Small multiples of pi/2 rounded to double precision. */ +static const double +s1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ +s2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ +s3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ +s4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + +float sinf(float x) +{ + double y; + uint32_t ix; + int n, sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + + if (ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if (ix < 0x39800000) { /* |x| < 2**-12 */ + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00800000 ? x/0x1p120f : x+0x1p120f); + return x; + } + return __sindf(x); + } + if (ix <= 0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if (ix <= 0x4016cbe3) { /* |x| ~<= 3pi/4 */ + if (sign) + return -__cosdf(x + s1pio2); + else + return __cosdf(x - s1pio2); + } + return __sindf(sign ? -(x + s2pio2) : -(x - s2pio2)); + } + if (ix <= 0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if (ix <= 0x40afeddf) { /* |x| ~<= 7*pi/4 */ + if (sign) + return __cosdf(x + s3pio2); + else + return -__cosdf(x - s3pio2); + } + return __sindf(sign ? x + s4pio2 : x - s4pio2); + } + + /* sin(Inf or NaN) is NaN */ + if (ix >= 0x7f800000) + return x - x; + + /* general argument reduction needed */ + n = __rem_pio2f(x, &y); + switch (n&3) { + case 0: return __sindf(y); + case 1: return __cosdf(y); + case 2: return __sindf(-y); + default: + return -__cosdf(y); + } +} diff --git a/src/orca-libc/src/math/sinh.c b/src/orca-libc/src/math/sinh.c new file mode 100644 index 00000000..c8dda8d6 --- /dev/null +++ b/src/orca-libc/src/math/sinh.c @@ -0,0 +1,43 @@ +#include "libm.h" + +/* sinh(x) = (exp(x) - 1/exp(x))/2 + * = (exp(x)-1 + (exp(x)-1)/exp(x))/2 + * = x + x^3/6 + o(x^5) + */ +double sinh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + uint32_t w; + double t, h, absx; + + h = 0.5; + if (u.i >> 63) + h = -h; + /* |x| */ + u.i &= (uint64_t)-1/2; + absx = u.f; + w = u.i >> 32; + + /* |x| < log(DBL_MAX) */ + if (w < 0x40862e42) { + t = expm1(absx); + if (w < 0x3ff00000) { + if (w < 0x3ff00000 - (26<<20)) + /* note: inexact and underflow are raised by expm1 */ + /* note: this branch avoids spurious underflow */ + return x; + return h*(2*t - t*t/(t+1)); + } + /* note: |x|>log(0x1p26)+eps could be just h*exp(x) */ + return h*(t + t/(t+1)); + } + + /* |x| > log(DBL_MAX) or nan */ + /* note: the result is stored to handle overflow */ +#ifdef __wasilibc_unmodified_upstream // Wasm doesn't have alternate rounding modes + t = __expo2(absx, 2*h); +#else + t = 2*h*__expo2(absx); +#endif + return t; +} diff --git a/src/orca-libc/src/math/sinhf.c b/src/orca-libc/src/math/sinhf.c new file mode 100644 index 00000000..3ac49e21 --- /dev/null +++ b/src/orca-libc/src/math/sinhf.c @@ -0,0 +1,35 @@ +#include "libm.h" + +float sinhf(float x) +{ + union {float f; uint32_t i;} u = {.f = x}; + uint32_t w; + float t, h, absx; + + h = 0.5; + if (u.i >> 31) + h = -h; + /* |x| */ + u.i &= 0x7fffffff; + absx = u.f; + w = u.i; + + /* |x| < log(FLT_MAX) */ + if (w < 0x42b17217) { + t = expm1f(absx); + if (w < 0x3f800000) { + if (w < 0x3f800000 - (12<<23)) + return x; + return h*(2*t - t*t/(t+1)); + } + return h*(t + t/(t+1)); + } + + /* |x| > logf(FLT_MAX) or nan */ +#ifdef __wasilibc_unmodified_upstream // Wasm doesn't have alternate rounding modes + t = __expo2f(absx, 2*h); +#else + t = 2*h*__expo2f(absx); +#endif + return t; +} diff --git a/src/orca-libc/src/math/sinhl.c b/src/orca-libc/src/math/sinhl.c new file mode 100644 index 00000000..b305d4d2 --- /dev/null +++ b/src/orca-libc/src/math/sinhl.c @@ -0,0 +1,43 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double sinhl(long double x) +{ + return sinh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +long double sinhl(long double x) +{ + union ldshape u = {x}; + unsigned ex = u.i.se & 0x7fff; + long double h, t, absx; + + h = 0.5; + if (u.i.se & 0x8000) + h = -h; + /* |x| */ + u.i.se = ex; + absx = u.f; + + /* |x| < log(LDBL_MAX) */ + if (ex < 0x3fff+13 || (ex == 0x3fff+13 && u.i.m>>32 < 0xb17217f7)) { + t = expm1l(absx); + if (ex < 0x3fff) { + if (ex < 0x3fff-32) + return x; + return h*(2*t - t*t/(1+t)); + } + return h*(t + t/(t+1)); + } + + /* |x| > log(LDBL_MAX) or nan */ + t = expl(0.5*absx); + return h*t*t; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double sinhl(long double x) +{ + return sinh(x); +} +#endif diff --git a/src/orca-libc/src/math/sinl.c b/src/orca-libc/src/math/sinl.c new file mode 100644 index 00000000..9c0b16ee --- /dev/null +++ b/src/orca-libc/src/math/sinl.c @@ -0,0 +1,41 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double sinl(long double x) +{ + return sin(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double sinl(long double x) +{ + union ldshape u = {x}; + unsigned n; + long double y[2], hi, lo; + + u.i.se &= 0x7fff; + if (u.i.se == 0x7fff) + return x - x; + if (u.f < M_PI_4) { + if (u.i.se < 0x3fff - LDBL_MANT_DIG/2) { + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(u.i.se == 0 ? x*0x1p-120f : x+0x1p120f); + return x; + } + return __sinl(x, 0.0, 0); + } + n = __rem_pio2l(x, y); + hi = y[0]; + lo = y[1]; + switch (n & 3) { + case 0: + return __sinl(hi, lo, 1); + case 1: + return __cosl(hi, lo); + case 2: + return -__sinl(hi, lo, 1); + case 3: + default: + return -__cosl(hi, lo); + } +} +#endif diff --git a/src/libc-shim/src/sqrt.c b/src/orca-libc/src/math/sqrt.c similarity index 53% rename from src/libc-shim/src/sqrt.c rename to src/orca-libc/src/math/sqrt.c index a17e1010..5ba26559 100644 --- a/src/libc-shim/src/sqrt.c +++ b/src/orca-libc/src/math/sqrt.c @@ -1,59 +1,57 @@ +#include +#include #include "libm.h" #include "sqrt_data.h" -#include -#include #define FENV_SUPPORT 1 /* returns a*b*2^-32 - e, with error 0 <= e < 1. */ static inline uint32_t mul32(uint32_t a, uint32_t b) { - return (uint64_t)a * b >> 32; + return (uint64_t)a*b >> 32; } /* returns a*b*2^-64 - e, with error 0 <= e < 3. */ static inline uint64_t mul64(uint64_t a, uint64_t b) { - uint64_t ahi = a >> 32; - uint64_t alo = a & 0xffffffff; - uint64_t bhi = b >> 32; - uint64_t blo = b & 0xffffffff; - return ahi * bhi + (ahi * blo >> 32) + (alo * bhi >> 32); + uint64_t ahi = a>>32; + uint64_t alo = a&0xffffffff; + uint64_t bhi = b>>32; + uint64_t blo = b&0xffffffff; + return ahi*bhi + (ahi*blo >> 32) + (alo*bhi >> 32); } double sqrt(double x) { - uint64_t ix, top, m; - - /* special case handling. */ - ix = asuint64(x); - top = ix >> 52; - if(predict_false(top - 0x001 >= 0x7ff - 0x001)) - { - /* x < 0x1p-1022 or inf or nan. */ - if(ix * 2 == 0) - return x; - if(ix == 0x7ff0000000000000) - return x; - if(ix > 0x7ff0000000000000) - return __math_invalid(x); - /* x is subnormal, normalize it. */ - ix = asuint64(x * 0x1p52); - top = ix >> 52; - top -= 52; - } - - /* argument reduction: + uint64_t ix, top, m; + + /* special case handling. */ + ix = asuint64(x); + top = ix >> 52; + if (predict_false(top - 0x001 >= 0x7ff - 0x001)) { + /* x < 0x1p-1022 or inf or nan. */ + if (ix * 2 == 0) + return x; + if (ix == 0x7ff0000000000000) + return x; + if (ix > 0x7ff0000000000000) + return __math_invalid(x); + /* x is subnormal, normalize it. */ + ix = asuint64(x * 0x1p52); + top = ix >> 52; + top -= 52; + } + + /* argument reduction: x = 4^e m; with integer e, and m in [1, 4) m: fixed point representation [2.62] 2^e is the exponent part of the result. */ - int even = top & 1; - m = (ix << 11) | 0x8000000000000000; - if(even) - m >>= 1; - top = (top + 0x3ff) >> 1; + int even = top & 1; + m = (ix << 11) | 0x8000000000000000; + if (even) m >>= 1; + top = (top + 0x3ff) >> 1; - /* approximate r ~ 1/sqrt(m) and s ~ sqrt(m) when m in [1,4) + /* approximate r ~ 1/sqrt(m) and s ~ sqrt(m) when m in [1,4) initial estimate: 7bit table lookup (1bit exponent and 6bit significand). @@ -107,55 +105,54 @@ double sqrt(double x) and after switching to 64 bit m: 2.62 r: 0.64, s: 2.62, d: 2.62, u: 2.62, three: 2.62 */ - static const uint64_t three = 0xc0000000; - uint64_t r, s, d, u, i; - - i = (ix >> 46) % 128; - r = (uint32_t)__rsqrt_tab[i] << 16; - /* |r sqrt(m) - 1| < 0x1.fdp-9 */ - s = mul32(m >> 32, r); - /* |s/sqrt(m) - 1| < 0x1.fdp-9 */ - d = mul32(s, r); - u = three - d; - r = mul32(r, u) << 1; - /* |r sqrt(m) - 1| < 0x1.7bp-16 */ - s = mul32(s, u) << 1; - /* |s/sqrt(m) - 1| < 0x1.7bp-16 */ - d = mul32(s, r); - u = three - d; - r = mul32(r, u) << 1; - /* |r sqrt(m) - 1| < 0x1.3704p-29 (measured worst-case) */ - r = r << 32; - s = mul64(m, r); - d = mul64(s, r); - u = (three << 32) - d; - s = mul64(s, u); /* repr: 3.61 */ - /* -0x1p-57 < s - sqrt(m) < 0x1.8001p-61 */ - s = (s - 2) >> 9; /* repr: 12.52 */ - /* -0x1.09p-52 < s - sqrt(m) < -0x1.fffcp-63 */ - - /* s < sqrt(m) < s + 0x1.09p-52, + static const uint64_t three = 0xc0000000; + uint64_t r, s, d, u, i; + + i = (ix >> 46) % 128; + r = (uint32_t)__rsqrt_tab[i] << 16; + /* |r sqrt(m) - 1| < 0x1.fdp-9 */ + s = mul32(m>>32, r); + /* |s/sqrt(m) - 1| < 0x1.fdp-9 */ + d = mul32(s, r); + u = three - d; + r = mul32(r, u) << 1; + /* |r sqrt(m) - 1| < 0x1.7bp-16 */ + s = mul32(s, u) << 1; + /* |s/sqrt(m) - 1| < 0x1.7bp-16 */ + d = mul32(s, r); + u = three - d; + r = mul32(r, u) << 1; + /* |r sqrt(m) - 1| < 0x1.3704p-29 (measured worst-case) */ + r = r << 32; + s = mul64(m, r); + d = mul64(s, r); + u = (three<<32) - d; + s = mul64(s, u); /* repr: 3.61 */ + /* -0x1p-57 < s - sqrt(m) < 0x1.8001p-61 */ + s = (s - 2) >> 9; /* repr: 12.52 */ + /* -0x1.09p-52 < s - sqrt(m) < -0x1.fffcp-63 */ + + /* s < sqrt(m) < s + 0x1.09p-52, compute nearest rounded result: the nearest result to 52 bits is either s or s+0x1p-52, we can decide by comparing (2^52 s + 0.5)^2 to 2^104 m. */ - uint64_t d0, d1, d2; - double y, t; - d0 = (m << 42) - s * s; - d1 = s - d0; - d2 = d1 + s + 1; - s += d1 >> 63; - s &= 0x000fffffffffffff; - s |= top << 52; - y = asdouble(s); - if(FENV_SUPPORT) - { - /* handle rounding modes and inexact exception: + uint64_t d0, d1, d2; + double y, t; + d0 = (m << 42) - s*s; + d1 = s - d0; + d2 = d1 + s + 1; + s += d1 >> 63; + s &= 0x000fffffffffffff; + s |= top << 52; + y = asdouble(s); + if (FENV_SUPPORT) { + /* handle rounding modes and inexact exception: only (s+1)^2 == 2^42 m case is exact otherwise add a tiny value to cause the fenv effects. */ - uint64_t tiny = predict_false(d2 == 0) ? 0 : 0x0010000000000000; - tiny |= (d1 ^ d2) & 0x8000000000000000; - t = asdouble(tiny); - y = eval_as_double(y + t); - } - return y; + uint64_t tiny = predict_false(d2==0) ? 0 : 0x0010000000000000; + tiny |= (d1^d2) & 0x8000000000000000; + t = asdouble(tiny); + y = eval_as_double(y + t); + } + return y; } diff --git a/src/orca-libc/src/math/sqrt_data.c b/src/orca-libc/src/math/sqrt_data.c new file mode 100644 index 00000000..61bc22f4 --- /dev/null +++ b/src/orca-libc/src/math/sqrt_data.c @@ -0,0 +1,19 @@ +#include "sqrt_data.h" +const uint16_t __rsqrt_tab[128] = { +0xb451,0xb2f0,0xb196,0xb044,0xaef9,0xadb6,0xac79,0xab43, +0xaa14,0xa8eb,0xa7c8,0xa6aa,0xa592,0xa480,0xa373,0xa26b, +0xa168,0xa06a,0x9f70,0x9e7b,0x9d8a,0x9c9d,0x9bb5,0x9ad1, +0x99f0,0x9913,0x983a,0x9765,0x9693,0x95c4,0x94f8,0x9430, +0x936b,0x92a9,0x91ea,0x912e,0x9075,0x8fbe,0x8f0a,0x8e59, +0x8daa,0x8cfe,0x8c54,0x8bac,0x8b07,0x8a64,0x89c4,0x8925, +0x8889,0x87ee,0x8756,0x86c0,0x862b,0x8599,0x8508,0x8479, +0x83ec,0x8361,0x82d8,0x8250,0x81c9,0x8145,0x80c2,0x8040, +0xff02,0xfd0e,0xfb25,0xf947,0xf773,0xf5aa,0xf3ea,0xf234, +0xf087,0xeee3,0xed47,0xebb3,0xea27,0xe8a3,0xe727,0xe5b2, +0xe443,0xe2dc,0xe17a,0xe020,0xdecb,0xdd7d,0xdc34,0xdaf1, +0xd9b3,0xd87b,0xd748,0xd61a,0xd4f1,0xd3cd,0xd2ad,0xd192, +0xd07b,0xcf69,0xce5b,0xcd51,0xcc4a,0xcb48,0xca4a,0xc94f, +0xc858,0xc764,0xc674,0xc587,0xc49d,0xc3b7,0xc2d4,0xc1f4, +0xc116,0xc03c,0xbf65,0xbe90,0xbdbe,0xbcef,0xbc23,0xbb59, +0xba91,0xb9cc,0xb90a,0xb84a,0xb78c,0xb6d0,0xb617,0xb560, +}; diff --git a/src/libc-shim/src/sqrt_data.h b/src/orca-libc/src/math/sqrt_data.h similarity index 86% rename from src/libc-shim/src/sqrt_data.h rename to src/orca-libc/src/math/sqrt_data.h index 619193cf..260c7f9c 100644 --- a/src/libc-shim/src/sqrt_data.h +++ b/src/orca-libc/src/math/sqrt_data.h @@ -8,6 +8,6 @@ if x in [2,4): i = (int)(32*x-64); __rsqrt_tab[i]*2^-16 is estimating 1/sqrt(x) with small relative error: |__rsqrt_tab[i]*0x1p-16*sqrt(x) - 1| < -0x1.fdp-9 < 2^-8 */ -extern const uint16_t __rsqrt_tab[128]; +extern hidden const uint16_t __rsqrt_tab[128]; #endif diff --git a/src/orca-libc/src/math/sqrtf.c b/src/orca-libc/src/math/sqrtf.c new file mode 100644 index 00000000..740d81cb --- /dev/null +++ b/src/orca-libc/src/math/sqrtf.c @@ -0,0 +1,83 @@ +#include +#include +#include "libm.h" +#include "sqrt_data.h" + +#define FENV_SUPPORT 1 + +static inline uint32_t mul32(uint32_t a, uint32_t b) +{ + return (uint64_t)a*b >> 32; +} + +/* see sqrt.c for more detailed comments. */ + +float sqrtf(float x) +{ + uint32_t ix, m, m1, m0, even, ey; + + ix = asuint(x); + if (predict_false(ix - 0x00800000 >= 0x7f800000 - 0x00800000)) { + /* x < 0x1p-126 or inf or nan. */ + if (ix * 2 == 0) + return x; + if (ix == 0x7f800000) + return x; + if (ix > 0x7f800000) + return __math_invalidf(x); + /* x is subnormal, normalize it. */ + ix = asuint(x * 0x1p23f); + ix -= 23 << 23; + } + + /* x = 4^e m; with int e and m in [1, 4). */ + even = ix & 0x00800000; + m1 = (ix << 8) | 0x80000000; + m0 = (ix << 7) & 0x7fffffff; + m = even ? m0 : m1; + + /* 2^e is the exponent part of the return value. */ + ey = ix >> 1; + ey += 0x3f800000 >> 1; + ey &= 0x7f800000; + + /* compute r ~ 1/sqrt(m), s ~ sqrt(m) with 2 goldschmidt iterations. */ + static const uint32_t three = 0xc0000000; + uint32_t r, s, d, u, i; + i = (ix >> 17) % 128; + r = (uint32_t)__rsqrt_tab[i] << 16; + /* |r*sqrt(m) - 1| < 0x1p-8 */ + s = mul32(m, r); + /* |s/sqrt(m) - 1| < 0x1p-8 */ + d = mul32(s, r); + u = three - d; + r = mul32(r, u) << 1; + /* |r*sqrt(m) - 1| < 0x1.7bp-16 */ + s = mul32(s, u) << 1; + /* |s/sqrt(m) - 1| < 0x1.7bp-16 */ + d = mul32(s, r); + u = three - d; + s = mul32(s, u); + /* -0x1.03p-28 < s/sqrt(m) - 1 < 0x1.fp-31 */ + s = (s - 1)>>6; + /* s < sqrt(m) < s + 0x1.08p-23 */ + + /* compute nearest rounded result. */ + uint32_t d0, d1, d2; + float y, t; + d0 = (m << 16) - s*s; + d1 = s - d0; + d2 = d1 + s + 1; + s += d1 >> 31; + s &= 0x007fffff; + s |= ey; + y = asfloat(s); + if (FENV_SUPPORT) { + /* handle rounding and inexact exception. */ + uint32_t tiny = predict_false(d2==0) ? 0 : 0x01000000; + tiny |= (d1^d2) & 0x80000000; + t = asfloat(tiny); + y = eval_as_float(y + t); + } + return y; +} diff --git a/src/orca-libc/src/math/sqrtl.c b/src/orca-libc/src/math/sqrtl.c new file mode 100644 index 00000000..1b9f19c7 --- /dev/null +++ b/src/orca-libc/src/math/sqrtl.c @@ -0,0 +1,259 @@ +#include +#include +#include +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double sqrtl(long double x) +{ + return sqrt(x); +} +#elif (LDBL_MANT_DIG == 113 || LDBL_MANT_DIG == 64) && LDBL_MAX_EXP == 16384 +#include "sqrt_data.h" + +#define FENV_SUPPORT 1 + +typedef struct { + uint64_t hi; + uint64_t lo; +} u128; + +/* top: 16 bit sign+exponent, x: significand. */ +static inline long double mkldbl(uint64_t top, u128 x) +{ + union ldshape u; +#if LDBL_MANT_DIG == 113 + u.i2.hi = x.hi; + u.i2.lo = x.lo; + u.i2.hi &= 0x0000ffffffffffff; + u.i2.hi |= top << 48; +#elif LDBL_MANT_DIG == 64 + u.i.se = top; + u.i.m = x.lo; + /* force the top bit on non-zero (and non-subnormal) results. */ + if (top & 0x7fff) + u.i.m |= 0x8000000000000000; +#endif + return u.f; +} + +/* return: top 16 bit is sign+exp and following bits are the significand. */ +static inline u128 asu128(long double x) +{ + union ldshape u = {.f=x}; + u128 r; +#if LDBL_MANT_DIG == 113 + r.hi = u.i2.hi; + r.lo = u.i2.lo; +#elif LDBL_MANT_DIG == 64 + r.lo = u.i.m<<49; + /* ignore the top bit: pseudo numbers are not handled. */ + r.hi = u.i.m>>15; + r.hi &= 0x0000ffffffffffff; + r.hi |= (uint64_t)u.i.se << 48; +#endif + return r; +} + +/* returns a*b*2^-32 - e, with error 0 <= e < 1. */ +static inline uint32_t mul32(uint32_t a, uint32_t b) +{ + return (uint64_t)a*b >> 32; +} + +/* returns a*b*2^-64 - e, with error 0 <= e < 3. */ +static inline uint64_t mul64(uint64_t a, uint64_t b) +{ + uint64_t ahi = a>>32; + uint64_t alo = a&0xffffffff; + uint64_t bhi = b>>32; + uint64_t blo = b&0xffffffff; + return ahi*bhi + (ahi*blo >> 32) + (alo*bhi >> 32); +} + +static inline u128 add64(u128 a, uint64_t b) +{ + u128 r; + r.lo = a.lo + b; + r.hi = a.hi; + if (r.lo < a.lo) + r.hi++; + return r; +} + +static inline u128 add128(u128 a, u128 b) +{ + u128 r; + r.lo = a.lo + b.lo; + r.hi = a.hi + b.hi; + if (r.lo < a.lo) + r.hi++; + return r; +} + +static inline u128 sub64(u128 a, uint64_t b) +{ + u128 r; + r.lo = a.lo - b; + r.hi = a.hi; + if (a.lo < b) + r.hi--; + return r; +} + +static inline u128 sub128(u128 a, u128 b) +{ + u128 r; + r.lo = a.lo - b.lo; + r.hi = a.hi - b.hi; + if (a.lo < b.lo) + r.hi--; + return r; +} + +/* a<= 64) { + a.hi = a.lo<<(n-64); + a.lo = 0; + } else { + a.hi = (a.hi<>(64-n)); + a.lo = a.lo<>n, 0 <= n <= 127 */ +static inline u128 rsh(u128 a, int n) +{ + if (n == 0) + return a; + if (n >= 64) { + a.lo = a.hi>>(n-64); + a.hi = 0; + } else { + a.lo = (a.lo>>n) | (a.hi<<(64-n)); + a.hi = a.hi>>n; + } + return a; +} + +/* returns a*b exactly. */ +static inline u128 mul64_128(uint64_t a, uint64_t b) +{ + u128 r; + uint64_t ahi = a>>32; + uint64_t alo = a&0xffffffff; + uint64_t bhi = b>>32; + uint64_t blo = b&0xffffffff; + uint64_t lo1 = ((ahi*blo)&0xffffffff) + ((alo*bhi)&0xffffffff) + (alo*blo>>32); + uint64_t lo2 = (alo*blo)&0xffffffff; + r.hi = ahi*bhi + (ahi*blo>>32) + (alo*bhi>>32) + (lo1>>32); + r.lo = (lo1<<32) + lo2; + return r; +} + +/* returns a*b*2^-128 - e, with error 0 <= e < 7. */ +static inline u128 mul128(u128 a, u128 b) +{ + u128 hi = mul64_128(a.hi, b.hi); + uint64_t m1 = mul64(a.hi, b.lo); + uint64_t m2 = mul64(a.lo, b.hi); + return add64(add64(hi, m1), m2); +} + +/* returns a*b % 2^128. */ +static inline u128 mul128_tail(u128 a, u128 b) +{ + u128 lo = mul64_128(a.lo, b.lo); + lo.hi += a.hi*b.lo + a.lo*b.hi; + return lo; +} + + +/* see sqrt.c for detailed comments. */ + +long double sqrtl(long double x) +{ + u128 ix, ml; + uint64_t top; + + ix = asu128(x); + top = ix.hi >> 48; + if (predict_false(top - 0x0001 >= 0x7fff - 0x0001)) { + /* x < 0x1p-16382 or inf or nan. */ + if (2*ix.hi == 0 && ix.lo == 0) + return x; + if (ix.hi == 0x7fff000000000000 && ix.lo == 0) + return x; + if (top >= 0x7fff) + return __math_invalidl(x); + /* x is subnormal, normalize it. */ + ix = asu128(x * 0x1p112); + top = ix.hi >> 48; + top -= 112; + } + + /* x = 4^e m; with int e and m in [1, 4) */ + int even = top & 1; + ml = lsh(ix, 15); + ml.hi |= 0x8000000000000000; + if (even) ml = rsh(ml, 1); + top = (top + 0x3fff) >> 1; + + /* r ~ 1/sqrt(m) */ + static const uint64_t three = 0xc0000000; + uint64_t r, s, d, u, i; + i = (ix.hi >> 42) % 128; + r = (uint32_t)__rsqrt_tab[i] << 16; + /* |r sqrt(m) - 1| < 0x1p-8 */ + s = mul32(ml.hi>>32, r); + d = mul32(s, r); + u = three - d; + r = mul32(u, r) << 1; + /* |r sqrt(m) - 1| < 0x1.7bp-16, switch to 64bit */ + r = r<<32; + s = mul64(ml.hi, r); + d = mul64(s, r); + u = (three<<32) - d; + r = mul64(u, r) << 1; + /* |r sqrt(m) - 1| < 0x1.a5p-31 */ + s = mul64(u, s) << 1; + d = mul64(s, r); + u = (three<<32) - d; + r = mul64(u, r) << 1; + /* |r sqrt(m) - 1| < 0x1.c001p-59, switch to 128bit */ + + static const u128 threel = {.hi=three<<32, .lo=0}; + u128 rl, sl, dl, ul; + rl.hi = r; + rl.lo = 0; + sl = mul128(ml, rl); + dl = mul128(sl, rl); + ul = sub128(threel, dl); + sl = mul128(ul, sl); /* repr: 3.125 */ + /* -0x1p-116 < s - sqrt(m) < 0x3.8001p-125 */ + sl = rsh(sub64(sl, 4), 125-(LDBL_MANT_DIG-1)); + /* s < sqrt(m) < s + 1 ULP + tiny */ + + long double y; + u128 d2, d1, d0; + d0 = sub128(lsh(ml, 2*(LDBL_MANT_DIG-1)-126), mul128_tail(sl,sl)); + d1 = sub128(sl, d0); + d2 = add128(add64(sl, 1), d1); + sl = add64(sl, d1.hi >> 63); + y = mkldbl(top, sl); + if (FENV_SUPPORT) { + /* handle rounding modes and inexact exception. */ + top = predict_false((d2.hi|d2.lo)==0) ? 0 : 1; + top |= ((d1.hi^d2.hi)&0x8000000000000000) >> 48; + y += mkldbl(top, (u128){0}); + } + return y; +} +#else +#error unsupported long double format +#endif diff --git a/src/libc-shim/src/tan.c b/src/orca-libc/src/math/tan.c similarity index 97% rename from src/libc-shim/src/tan.c rename to src/orca-libc/src/math/tan.c index 1c1b2971..9c724a45 100644 --- a/src/libc-shim/src/tan.c +++ b/src/orca-libc/src/math/tan.c @@ -41,8 +41,6 @@ #include "libm.h" -double __tan(double x, double y, int odd); - double tan(double x) { double y[2]; diff --git a/src/libc-shim/src/tanf.c b/src/orca-libc/src/math/tanf.c similarity index 98% rename from src/libc-shim/src/tanf.c rename to src/orca-libc/src/math/tanf.c index 5dc1860c..aba19777 100644 --- a/src/libc-shim/src/tanf.c +++ b/src/orca-libc/src/math/tanf.c @@ -23,8 +23,6 @@ t2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ t3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ t4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ -float __tandf(double x, int odd); - float tanf(float x) { double y; diff --git a/src/orca-libc/src/math/tanh.c b/src/orca-libc/src/math/tanh.c new file mode 100644 index 00000000..20d6dbcf --- /dev/null +++ b/src/orca-libc/src/math/tanh.c @@ -0,0 +1,45 @@ +#include "libm.h" + +/* tanh(x) = (exp(x) - exp(-x))/(exp(x) + exp(-x)) + * = (exp(2*x) - 1)/(exp(2*x) - 1 + 2) + * = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2) + */ +double tanh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + uint32_t w; + int sign; + double_t t; + + /* x = |x| */ + sign = u.i >> 63; + u.i &= (uint64_t)-1/2; + x = u.f; + w = u.i >> 32; + + if (w > 0x3fe193ea) { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if (w > 0x40340000) { + /* |x| > 20 or nan */ + /* note: this branch avoids raising overflow */ + t = 1 - 0/x; + } else { + t = expm1(2*x); + t = 1 - 2/(t+2); + } + } else if (w > 0x3fd058ae) { + /* |x| > log(5/3)/2 ~= 0.2554 */ + t = expm1(2*x); + t = t/(t+2); + } else if (w >= 0x00100000) { + /* |x| >= 0x1p-1022, up to 2ulp error in [0.1,0.2554] */ + t = expm1(-2*x); + t = -t/(t+2); + } else { + /* |x| is subnormal */ + /* note: the branch above would not raise underflow in [0x1p-1023,0x1p-1022) */ + FORCE_EVAL((float)x); + t = x; + } + return sign ? -t : t; +} diff --git a/src/orca-libc/src/math/tanhf.c b/src/orca-libc/src/math/tanhf.c new file mode 100644 index 00000000..10636fbd --- /dev/null +++ b/src/orca-libc/src/math/tanhf.c @@ -0,0 +1,39 @@ +#include "libm.h" + +float tanhf(float x) +{ + union {float f; uint32_t i;} u = {.f = x}; + uint32_t w; + int sign; + float t; + + /* x = |x| */ + sign = u.i >> 31; + u.i &= 0x7fffffff; + x = u.f; + w = u.i; + + if (w > 0x3f0c9f54) { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if (w > 0x41200000) { + /* |x| > 10 */ + t = 1 + 0/x; + } else { + t = expm1f(2*x); + t = 1 - 2/(t+2); + } + } else if (w > 0x3e82c578) { + /* |x| > log(5/3)/2 ~= 0.2554 */ + t = expm1f(2*x); + t = t/(t+2); + } else if (w >= 0x00800000) { + /* |x| >= 0x1p-126 */ + t = expm1f(-2*x); + t = -t/(t+2); + } else { + /* |x| is subnormal */ + FORCE_EVAL(x*x); + t = x; + } + return sign ? -t : t; +} diff --git a/src/orca-libc/src/math/tanhl.c b/src/orca-libc/src/math/tanhl.c new file mode 100644 index 00000000..4e1aa9f8 --- /dev/null +++ b/src/orca-libc/src/math/tanhl.c @@ -0,0 +1,48 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double tanhl(long double x) +{ + return tanh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +long double tanhl(long double x) +{ + union ldshape u = {x}; + unsigned ex = u.i.se & 0x7fff; + unsigned sign = u.i.se & 0x8000; + uint32_t w; + long double t; + + /* x = |x| */ + u.i.se = ex; + x = u.f; + w = u.i.m >> 32; + + if (ex > 0x3ffe || (ex == 0x3ffe && w > 0x8c9f53d5)) { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if (ex >= 0x3fff+5) { + /* |x| >= 32 */ + t = 1 + 0/(x + 0x1p-120f); + } else { + t = expm1l(2*x); + t = 1 - 2/(t+2); + } + } else if (ex > 0x3ffd || (ex == 0x3ffd && w > 0x82c577d4)) { + /* |x| > log(5/3)/2 ~= 0.2554 */ + t = expm1l(2*x); + t = t/(t+2); + } else { + /* |x| is small */ + t = expm1l(-2*x); + t = -t/(t+2); + } + return sign ? -t : t; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double tanhl(long double x) +{ + return tanh(x); +} +#endif diff --git a/src/orca-libc/src/math/tanl.c b/src/orca-libc/src/math/tanl.c new file mode 100644 index 00000000..6af06712 --- /dev/null +++ b/src/orca-libc/src/math/tanl.c @@ -0,0 +1,29 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double tanl(long double x) +{ + return tan(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double tanl(long double x) +{ + union ldshape u = {x}; + long double y[2]; + unsigned n; + + u.i.se &= 0x7fff; + if (u.i.se == 0x7fff) + return x - x; + if (u.f < M_PI_4) { + if (u.i.se < 0x3fff - LDBL_MANT_DIG/2) { + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(u.i.se == 0 ? x*0x1p-120f : x+0x1p120f); + return x; + } + return __tanl(x, 0, 0); + } + n = __rem_pio2l(x, y); + return __tanl(y[0], y[1], n&1); +} +#endif diff --git a/src/orca-libc/src/math/tgamma.c b/src/orca-libc/src/math/tgamma.c new file mode 100644 index 00000000..28f6e0f8 --- /dev/null +++ b/src/orca-libc/src/math/tgamma.c @@ -0,0 +1,222 @@ +/* +"A Precision Approximation of the Gamma Function" - Cornelius Lanczos (1964) +"Lanczos Implementation of the Gamma Function" - Paul Godfrey (2001) +"An Analysis of the Lanczos Gamma Approximation" - Glendon Ralph Pugh (2004) + +approximation method: + + (x - 0.5) S(x) +Gamma(x) = (x + g - 0.5) * ---------------- + exp(x + g - 0.5) + +with + a1 a2 a3 aN +S(x) ~= [ a0 + ----- + ----- + ----- + ... + ----- ] + x + 1 x + 2 x + 3 x + N + +with a0, a1, a2, a3,.. aN constants which depend on g. + +for x < 0 the following reflection formula is used: + +Gamma(x)*Gamma(-x) = -pi/(x sin(pi x)) + +most ideas and constants are from boost and python +*/ +#include "libm.h" + +static const double pi = 3.141592653589793238462643383279502884; + +/* sin(pi x) with x > 0x1p-100, if sin(pi*x)==0 the sign is arbitrary */ +static double sinpi(double x) +{ + int n; + + /* argument reduction: x = |x| mod 2 */ + /* spurious inexact when x is odd int */ + x = x * 0.5; + x = 2 * (x - floor(x)); + + /* reduce x into [-.25,.25] */ + n = 4 * x; + n = (n+1)/2; + x -= n * 0.5; + + x *= pi; + switch (n) { + default: /* case 4 */ + case 0: + return __sin(x, 0, 0); + case 1: + return __cos(x, 0); + case 2: + return __sin(-x, 0, 0); + case 3: + return -__cos(x, 0); + } +} + +#define N 12 +//static const double g = 6.024680040776729583740234375; +static const double gmhalf = 5.524680040776729583740234375; +static const double Snum[N+1] = { + 23531376880.410759688572007674451636754734846804940, + 42919803642.649098768957899047001988850926355848959, + 35711959237.355668049440185451547166705960488635843, + 17921034426.037209699919755754458931112671403265390, + 6039542586.3520280050642916443072979210699388420708, + 1439720407.3117216736632230727949123939715485786772, + 248874557.86205415651146038641322942321632125127801, + 31426415.585400194380614231628318205362874684987640, + 2876370.6289353724412254090516208496135991145378768, + 186056.26539522349504029498971604569928220784236328, + 8071.6720023658162106380029022722506138218516325024, + 210.82427775157934587250973392071336271166969580291, + 2.5066282746310002701649081771338373386264310793408, +}; +static const double Sden[N+1] = { + 0, 39916800, 120543840, 150917976, 105258076, 45995730, 13339535, + 2637558, 357423, 32670, 1925, 66, 1, +}; +/* n! for small integer n */ +static const double fact[] = { + 1, 1, 2, 6, 24, 120, 720, 5040.0, 40320.0, 362880.0, 3628800.0, 39916800.0, + 479001600.0, 6227020800.0, 87178291200.0, 1307674368000.0, 20922789888000.0, + 355687428096000.0, 6402373705728000.0, 121645100408832000.0, + 2432902008176640000.0, 51090942171709440000.0, 1124000727777607680000.0, +}; + +/* S(x) rational function for positive x */ +static double S(double x) +{ + double_t num = 0, den = 0; + int i; + + /* to avoid overflow handle large x differently */ + if (x < 8) + for (i = N; i >= 0; i--) { + num = num * x + Snum[i]; + den = den * x + Sden[i]; + } + else + for (i = 0; i <= N; i++) { + num = num / x + Snum[i]; + den = den / x + Sden[i]; + } + return num/den; +} + +double tgamma(double x) +{ + union {double f; uint64_t i;} u = {x}; + double absx, y; + double_t dy, z, r; + uint32_t ix = u.i>>32 & 0x7fffffff; + int sign = u.i>>63; + + /* special cases */ + if (ix >= 0x7ff00000) + /* tgamma(nan)=nan, tgamma(inf)=inf, tgamma(-inf)=nan with invalid */ + return x + INFINITY; + if (ix < (0x3ff-54)<<20) + /* |x| < 2^-54: tgamma(x) ~ 1/x, +-0 raises div-by-zero */ + return 1/x; + + /* integer arguments */ + /* raise inexact when non-integer */ + if (x == floor(x)) { + if (sign) + return 0/0.0; + if (x <= sizeof fact/sizeof *fact) + return fact[(int)x - 1]; + } + + /* x >= 172: tgamma(x)=inf with overflow */ + /* x =< -184: tgamma(x)=+-0 with underflow */ + if (ix >= 0x40670000) { /* |x| >= 184 */ + if (sign) { + FORCE_EVAL((float)(0x1p-126/x)); + if (floor(x) * 0.5 == floor(x * 0.5)) + return 0; + return -0.0; + } + x *= 0x1p1023; + return x; + } + + absx = sign ? -x : x; + + /* handle the error of x + g - 0.5 */ + y = absx + gmhalf; + if (absx > gmhalf) { + dy = y - absx; + dy -= gmhalf; + } else { + dy = y - gmhalf; + dy -= absx; + } + + z = absx - 0.5; + r = S(absx) * exp(-y); + if (x < 0) { + /* reflection formula for negative x */ + /* sinpi(absx) is not 0, integers are already handled */ + r = -pi / (sinpi(absx) * absx * r); + dy = -dy; + z = -z; + } + r += dy * (gmhalf+0.5) * r / y; + z = pow(y, 0.5*z); + y = r * z * z; + return y; +} + +#if 0 +double __lgamma_r(double x, int *sign) +{ + double r, absx; + + *sign = 1; + + /* special cases */ + if (!isfinite(x)) + /* lgamma(nan)=nan, lgamma(+-inf)=inf */ + return x*x; + + /* integer arguments */ + if (x == floor(x) && x <= 2) { + /* n <= 0: lgamma(n)=inf with divbyzero */ + /* n == 1,2: lgamma(n)=0 */ + if (x <= 0) + return 1/0.0; + return 0; + } + + absx = fabs(x); + + /* lgamma(x) ~ -log(|x|) for tiny |x| */ + if (absx < 0x1p-54) { + *sign = 1 - 2*!!signbit(x); + return -log(absx); + } + + /* use tgamma for smaller |x| */ + if (absx < 128) { + x = tgamma(x); + *sign = 1 - 2*!!signbit(x); + return log(fabs(x)); + } + + /* second term (log(S)-g) could be more precise here.. */ + /* or with stirling: (|x|-0.5)*(log(|x|)-1) + poly(1/|x|) */ + r = (absx-0.5)*(log(absx+gmhalf)-1) + (log(S(absx)) - (gmhalf+0.5)); + if (x < 0) { + /* reflection formula for negative x */ + x = sinpi(absx); + *sign = 2*!!signbit(x) - 1; + r = log(pi/(fabs(x)*absx)) - r; + } + return r; +} + +weak_alias(__lgamma_r, lgamma_r); +#endif diff --git a/src/orca-libc/src/math/tgammaf.c b/src/orca-libc/src/math/tgammaf.c new file mode 100644 index 00000000..b4ca51c9 --- /dev/null +++ b/src/orca-libc/src/math/tgammaf.c @@ -0,0 +1,6 @@ +#include + +float tgammaf(float x) +{ + return tgamma(x); +} diff --git a/src/orca-libc/src/math/tgammal.c b/src/orca-libc/src/math/tgammal.c new file mode 100644 index 00000000..5336c5b1 --- /dev/null +++ b/src/orca-libc/src/math/tgammal.c @@ -0,0 +1,281 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_tgammal.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Gamma function + * + * + * SYNOPSIS: + * + * long double x, y, tgammal(); + * + * y = tgammal( x ); + * + * + * DESCRIPTION: + * + * Returns gamma function of the argument. The result is + * correctly signed. + * + * Arguments |x| <= 13 are reduced by recurrence and the function + * approximated by a rational function of degree 7/8 in the + * interval (2,3). Large arguments are handled by Stirling's + * formula. Large negative arguments are made positive using + * a reflection formula. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -40,+40 10000 3.6e-19 7.9e-20 + * IEEE -1755,+1755 10000 4.8e-18 6.5e-19 + * + * Accuracy for large arguments is dominated by error in powl(). + * + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double tgammal(long double x) +{ + return tgamma(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* +tgamma(x+2) = tgamma(x+2) P(x)/Q(x) +0 <= x <= 1 +Relative error +n=7, d=8 +Peak error = 1.83e-20 +Relative error spread = 8.4e-23 +*/ +static const long double P[8] = { + 4.212760487471622013093E-5L, + 4.542931960608009155600E-4L, + 4.092666828394035500949E-3L, + 2.385363243461108252554E-2L, + 1.113062816019361559013E-1L, + 3.629515436640239168939E-1L, + 8.378004301573126728826E-1L, + 1.000000000000000000009E0L, +}; +static const long double Q[9] = { +-1.397148517476170440917E-5L, + 2.346584059160635244282E-4L, +-1.237799246653152231188E-3L, +-7.955933682494738320586E-4L, + 2.773706565840072979165E-2L, +-4.633887671244534213831E-2L, +-2.243510905670329164562E-1L, + 4.150160950588455434583E-1L, + 9.999999999999999999908E-1L, +}; + +/* +static const long double P[] = { +-3.01525602666895735709e0L, +-3.25157411956062339893e1L, +-2.92929976820724030353e2L, +-1.70730828800510297666e3L, +-7.96667499622741999770e3L, +-2.59780216007146401957e4L, +-5.99650230220855581642e4L, +-7.15743521530849602425e4L +}; +static const long double Q[] = { + 1.00000000000000000000e0L, +-1.67955233807178858919e1L, + 8.85946791747759881659e1L, + 5.69440799097468430177e1L, +-1.98526250512761318471e3L, + 3.31667508019495079814e3L, + 1.60577839621734713377e4L, +-2.97045081369399940529e4L, +-7.15743521530849602412e4L +}; +*/ +#define MAXGAML 1755.455L +/*static const long double LOGPI = 1.14472988584940017414L;*/ + +/* Stirling's formula for the gamma function +tgamma(x) = sqrt(2 pi) x^(x-.5) exp(-x) (1 + 1/x P(1/x)) +z(x) = x +13 <= x <= 1024 +Relative error +n=8, d=0 +Peak error = 9.44e-21 +Relative error spread = 8.8e-4 +*/ +static const long double STIR[9] = { + 7.147391378143610789273E-4L, +-2.363848809501759061727E-5L, +-5.950237554056330156018E-4L, + 6.989332260623193171870E-5L, + 7.840334842744753003862E-4L, +-2.294719747873185405699E-4L, +-2.681327161876304418288E-3L, + 3.472222222230075327854E-3L, + 8.333333333333331800504E-2L, +}; + +#define MAXSTIR 1024.0L +static const long double SQTPI = 2.50662827463100050242E0L; + +/* 1/tgamma(x) = z P(z) + * z(x) = 1/x + * 0 < x < 0.03125 + * Peak relative error 4.2e-23 + */ +static const long double S[9] = { +-1.193945051381510095614E-3L, + 7.220599478036909672331E-3L, +-9.622023360406271645744E-3L, +-4.219773360705915470089E-2L, + 1.665386113720805206758E-1L, +-4.200263503403344054473E-2L, +-6.558780715202540684668E-1L, + 5.772156649015328608253E-1L, + 1.000000000000000000000E0L, +}; + +/* 1/tgamma(-x) = z P(z) + * z(x) = 1/x + * 0 < x < 0.03125 + * Peak relative error 5.16e-23 + * Relative error spread = 2.5e-24 + */ +static const long double SN[9] = { + 1.133374167243894382010E-3L, + 7.220837261893170325704E-3L, + 9.621911155035976733706E-3L, +-4.219773343731191721664E-2L, +-1.665386113944413519335E-1L, +-4.200263503402112910504E-2L, + 6.558780715202536547116E-1L, + 5.772156649015328608727E-1L, +-1.000000000000000000000E0L, +}; + +static const long double PIL = 3.1415926535897932384626L; + +/* Gamma function computed by Stirling's formula. + */ +static long double stirf(long double x) +{ + long double y, w, v; + + w = 1.0/x; + /* For large x, use rational coefficients from the analytical expansion. */ + if (x > 1024.0) + w = (((((6.97281375836585777429E-5L * w + + 7.84039221720066627474E-4L) * w + - 2.29472093621399176955E-4L) * w + - 2.68132716049382716049E-3L) * w + + 3.47222222222222222222E-3L) * w + + 8.33333333333333333333E-2L) * w + + 1.0; + else + w = 1.0 + w * __polevll(w, STIR, 8); + y = expl(x); + if (x > MAXSTIR) { /* Avoid overflow in pow() */ + v = powl(x, 0.5L * x - 0.25L); + y = v * (v / y); + } else { + y = powl(x, x - 0.5L) / y; + } + y = SQTPI * y * w; + return y; +} + +long double tgammal(long double x) +{ + long double p, q, z; + + if (!isfinite(x)) + return x + INFINITY; + + q = fabsl(x); + if (q > 13.0) { + if (x < 0.0) { + p = floorl(q); + z = q - p; + if (z == 0) + return 0 / z; + if (q > MAXGAML) { + z = 0; + } else { + if (z > 0.5) { + p += 1.0; + z = q - p; + } + z = q * sinl(PIL * z); + z = fabsl(z) * stirf(q); + z = PIL/z; + } + if (0.5 * p == floorl(q * 0.5)) + z = -z; + } else if (x > MAXGAML) { + z = x * 0x1p16383L; + } else { + z = stirf(x); + } + return z; + } + + z = 1.0; + while (x >= 3.0) { + x -= 1.0; + z *= x; + } + while (x < -0.03125L) { + z /= x; + x += 1.0; + } + if (x <= 0.03125L) + goto small; + while (x < 2.0) { + z /= x; + x += 1.0; + } + if (x == 2.0) + return z; + + x -= 2.0; + p = __polevll(x, P, 7); + q = __polevll(x, Q, 8); + z = z * p / q; + return z; + +small: + /* z==1 if x was originally +-0 */ + if (x == 0 && z != 1) + return x / x; + if (x < 0.0) { + x = -x; + q = z / (x * __polevll(x, SN, 8)); + } else + q = z / (x * __polevll(x, S, 8)); + return q; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double tgammal(long double x) +{ + return tgamma(x); +} +#endif diff --git a/src/orca-libc/src/math/trunc.c b/src/orca-libc/src/math/trunc.c new file mode 100644 index 00000000..d13711b5 --- /dev/null +++ b/src/orca-libc/src/math/trunc.c @@ -0,0 +1,19 @@ +#include "libm.h" + +double trunc(double x) +{ + union {double f; uint64_t i;} u = {x}; + int e = (int)(u.i >> 52 & 0x7ff) - 0x3ff + 12; + uint64_t m; + + if (e >= 52 + 12) + return x; + if (e < 12) + e = 1; + m = -1ULL >> e; + if ((u.i & m) == 0) + return x; + FORCE_EVAL(x + 0x1p120f); + u.i &= ~m; + return u.f; +} diff --git a/src/orca-libc/src/math/truncf.c b/src/orca-libc/src/math/truncf.c new file mode 100644 index 00000000..1a7d03c3 --- /dev/null +++ b/src/orca-libc/src/math/truncf.c @@ -0,0 +1,19 @@ +#include "libm.h" + +float truncf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = (int)(u.i >> 23 & 0xff) - 0x7f + 9; + uint32_t m; + + if (e >= 23 + 9) + return x; + if (e < 9) + e = 1; + m = -1U >> e; + if ((u.i & m) == 0) + return x; + FORCE_EVAL(x + 0x1p120f); + u.i &= ~m; + return u.f; +} diff --git a/src/orca-libc/src/math/truncl.c b/src/orca-libc/src/math/truncl.c new file mode 100644 index 00000000..f07b1934 --- /dev/null +++ b/src/orca-libc/src/math/truncl.c @@ -0,0 +1,34 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double truncl(long double x) +{ + return trunc(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +static const long double toint = 1/LDBL_EPSILON; + +long double truncl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + int s = u.i.se >> 15; + long double y; + + if (e >= 0x3fff+LDBL_MANT_DIG-1) + return x; + if (e <= 0x3fff-1) { + FORCE_EVAL(x + 0x1p120f); + return x*0; + } + /* y = int(|x|) - |x|, where int(|x|) is an integer neighbor of |x| */ + if (s) + x = -x; + y = x + toint - toint - x; + if (y > 0) + y -= 1; + x += y; + return s ? -x : x; +} +#endif diff --git a/src/orca-libc/src/multibyte/internal.c b/src/orca-libc/src/multibyte/internal.c new file mode 100644 index 00000000..2f5aaa91 --- /dev/null +++ b/src/orca-libc/src/multibyte/internal.c @@ -0,0 +1,26 @@ +#include "internal.h" + +#define C(x) ( x<2 ? -1 : ( R(0x80,0xc0) | x ) ) +#define D(x) C((x+16)) +#define E(x) ( ( x==0 ? R(0xa0,0xc0) : \ + x==0xd ? R(0x80,0xa0) : \ + R(0x80,0xc0) ) \ + | ( R(0x80,0xc0) >> 6 ) \ + | x ) +#define F(x) ( ( x>=5 ? 0 : \ + x==0 ? R(0x90,0xc0) : \ + x==4 ? R(0x80,0x90) : \ + R(0x80,0xc0) ) \ + | ( R(0x80,0xc0) >> 6 ) \ + | ( R(0x80,0xc0) >> 12 ) \ + | x ) + +const uint32_t bittab[] = { + C(0x2),C(0x3),C(0x4),C(0x5),C(0x6),C(0x7), + C(0x8),C(0x9),C(0xa),C(0xb),C(0xc),C(0xd),C(0xe),C(0xf), + D(0x0),D(0x1),D(0x2),D(0x3),D(0x4),D(0x5),D(0x6),D(0x7), + D(0x8),D(0x9),D(0xa),D(0xb),D(0xc),D(0xd),D(0xe),D(0xf), + E(0x0),E(0x1),E(0x2),E(0x3),E(0x4),E(0x5),E(0x6),E(0x7), + E(0x8),E(0x9),E(0xa),E(0xb),E(0xc),E(0xd),E(0xe),E(0xf), + F(0x0),F(0x1),F(0x2),F(0x3),F(0x4) +}; diff --git a/src/orca-libc/src/multibyte/internal.h b/src/orca-libc/src/multibyte/internal.h new file mode 100644 index 00000000..ab2cbd3f --- /dev/null +++ b/src/orca-libc/src/multibyte/internal.h @@ -0,0 +1,24 @@ +#define bittab __fsmu8 + +#include +#include + +extern hidden const uint32_t bittab[]; + +/* Upper 6 state bits are a negative integer offset to bound-check next byte */ +/* equivalent to: ( (b-0x80) | (b+offset) ) & ~0x3f */ +#define OOB(c,b) (((((b)>>3)-0x10)|(((b)>>3)+((int32_t)(c)>>26))) & ~7) + +/* Interval [a,b). Either a must be 80 or b must be c0, lower 3 bits clear. */ +#define R(a,b) ((uint32_t)((a==0x80 ? 0x40u-b : 0u-a) << 23)) +#define FAILSTATE R(0x80,0x80) + +#define SA 0xc2u +#define SB 0xf4u + +/* Arbitrary encoding for representing code units instead of characters. */ +#define CODEUNIT(c) (0xdfff & (signed char)(c)) +#define IS_CODEUNIT(c) ((unsigned)(c)-0xdf80 < 0x80) + +//NOTE(martin): we don't have locales, or any wide char support really. Assume max multibye char length is 4 +#define MB_CUR_MAX 4 diff --git a/src/orca-libc/src/multibyte/mbrtowc.c b/src/orca-libc/src/multibyte/mbrtowc.c new file mode 100644 index 00000000..c94819e7 --- /dev/null +++ b/src/orca-libc/src/multibyte/mbrtowc.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include "internal.h" + +size_t mbrtowc(wchar_t *restrict wc, const char *restrict src, size_t n, mbstate_t *restrict st) +{ + static unsigned internal_state; + unsigned c; + const unsigned char *s = (const void *)src; + const unsigned N = n; + wchar_t dummy; + + if (!st) st = (void *)&internal_state; + c = *(unsigned *)st; + + if (!s) { + if (c) goto ilseq; + return 0; + } else if (!wc) wc = &dummy; + + if (!n) return -2; + if (!c) { + if (*s < 0x80) return !!(*wc = *s); + if (MB_CUR_MAX==1) return (*wc = CODEUNIT(*s)), 1; + if (*s-SA > SB-SA) goto ilseq; + c = bittab[*s++-SA]; n--; + } + + if (n) { + if (OOB(c,*s)) goto ilseq; +loop: + c = c<<6 | *s++-0x80; n--; + if (!(c&(1U<<31))) { + *(unsigned *)st = 0; + *wc = c; + return N-n; + } + if (n) { + if (*s-0x80u >= 0x40) goto ilseq; + goto loop; + } + } + + *(unsigned *)st = c; + return -2; +ilseq: + *(unsigned *)st = 0; + errno = EILSEQ; + return -1; +} diff --git a/src/orca-libc/src/multibyte/mbsinit.c b/src/orca-libc/src/multibyte/mbsinit.c new file mode 100644 index 00000000..c608194a --- /dev/null +++ b/src/orca-libc/src/multibyte/mbsinit.c @@ -0,0 +1,6 @@ +#include + +int mbsinit(const mbstate_t *st) +{ + return !st || !*(unsigned *)st; +} diff --git a/src/orca-libc/src/multibyte/wcrtomb.c b/src/orca-libc/src/multibyte/wcrtomb.c new file mode 100644 index 00000000..8e34926e --- /dev/null +++ b/src/orca-libc/src/multibyte/wcrtomb.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include "internal.h" + +size_t wcrtomb(char *restrict s, wchar_t wc, mbstate_t *restrict st) +{ + if (!s) return 1; + if ((unsigned)wc < 0x80) { + *s = wc; + return 1; + } else if (MB_CUR_MAX == 1) { + if (!IS_CODEUNIT(wc)) { + errno = EILSEQ; + return -1; + } + *s = wc; + return 1; + } else if ((unsigned)wc < 0x800) { + *s++ = 0xc0 | (wc>>6); + *s = 0x80 | (wc&0x3f); + return 2; + } else if ((unsigned)wc < 0xd800 || (unsigned)wc-0xe000 < 0x2000) { + *s++ = 0xe0 | (wc>>12); + *s++ = 0x80 | ((wc>>6)&0x3f); + *s = 0x80 | (wc&0x3f); + return 3; + } else if ((unsigned)wc-0x10000 < 0x100000) { + *s++ = 0xf0 | (wc>>18); + *s++ = 0x80 | ((wc>>12)&0x3f); + *s++ = 0x80 | ((wc>>6)&0x3f); + *s = 0x80 | (wc&0x3f); + return 4; + } + errno = EILSEQ; + return -1; +} diff --git a/src/orca-libc/src/multibyte/wctomb.c b/src/orca-libc/src/multibyte/wctomb.c new file mode 100644 index 00000000..bad41c5e --- /dev/null +++ b/src/orca-libc/src/multibyte/wctomb.c @@ -0,0 +1,8 @@ +#include +#include + +int wctomb(char *s, wchar_t wc) +{ + if (!s) return 0; + return wcrtomb(s, wc, 0); +} diff --git a/src/orca-libc/src/prng/rand.c b/src/orca-libc/src/prng/rand.c new file mode 100644 index 00000000..c000cd24 --- /dev/null +++ b/src/orca-libc/src/prng/rand.c @@ -0,0 +1,15 @@ +#include +#include + +static uint64_t seed; + +void srand(unsigned s) +{ + seed = s-1; +} + +int rand(void) +{ + seed = 6364136223846793005ULL*seed + 1; + return seed>>33; +} diff --git a/src/orca-libc/src/prng/rand_r.c b/src/orca-libc/src/prng/rand_r.c new file mode 100644 index 00000000..638614c8 --- /dev/null +++ b/src/orca-libc/src/prng/rand_r.c @@ -0,0 +1,15 @@ +#include + +static unsigned temper(unsigned x) +{ + x ^= x>>11; + x ^= x<<7 & 0x9D2C5680; + x ^= x<<15 & 0xEFC60000; + x ^= x>>18; + return x; +} + +int rand_r(unsigned *seed) +{ + return temper(*seed = *seed * 1103515245 + 12345)/2; +} diff --git a/src/orca-libc/src/prng/random.c b/src/orca-libc/src/prng/random.c new file mode 100644 index 00000000..d4da7781 --- /dev/null +++ b/src/orca-libc/src/prng/random.c @@ -0,0 +1,125 @@ +#include +#include +#include "lock.h" + +/* +this code uses the same lagged fibonacci generator as the +original bsd random implementation except for the seeding +which was broken in the original +*/ + +static uint32_t init[] = { +0x00000000,0x5851f42d,0xc0b18ccf,0xcbb5f646, +0xc7033129,0x30705b04,0x20fd5db4,0x9a8b7f78, +0x502959d8,0xab894868,0x6c0356a7,0x88cdb7ff, +0xb477d43f,0x70a3a52b,0xa8e4baf1,0xfd8341fc, +0x8ae16fd9,0x742d2f7a,0x0d1f0796,0x76035e09, +0x40f7702c,0x6fa72ca5,0xaaa84157,0x58a0df74, +0xc74a0364,0xae533cc4,0x04185faf,0x6de3b115, +0x0cab8628,0xf043bfa4,0x398150e9,0x37521657}; + +static int n = 31; +static int i = 3; +static int j = 0; +static uint32_t *x = init+1; +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) +static volatile int lock[1]; +volatile int *const __random_lockptr = lock; +#endif + +static uint32_t lcg31(uint32_t x) { + return (1103515245*x + 12345) & 0x7fffffff; +} + +static uint64_t lcg64(uint64_t x) { + return 6364136223846793005ull*x + 1; +} + +static void *savestate() { + x[-1] = (n<<16)|(i<<8)|j; + return x-1; +} + +static void loadstate(uint32_t *state) { + x = state+1; + n = x[-1]>>16; + i = (x[-1]>>8)&0xff; + j = x[-1]&0xff; +} + +static void __srandom(unsigned seed) { + int k; + uint64_t s = seed; + + if (n == 0) { + x[0] = s; + return; + } + i = n == 31 || n == 7 ? 3 : 1; + j = 0; + for (k = 0; k < n; k++) { + s = lcg64(s); + x[k] = s>>32; + } + /* make sure x contains at least one odd number */ + x[0] |= 1; +} + +void srandom(unsigned seed) { + LOCK(lock); + __srandom(seed); + UNLOCK(lock); +} + +char *initstate(unsigned seed, char *state, size_t size) { + void *old; + + if (size < 8) + return 0; + LOCK(lock); + old = savestate(); + if (size < 32) + n = 0; + else if (size < 64) + n = 7; + else if (size < 128) + n = 15; + else if (size < 256) + n = 31; + else + n = 63; + x = (uint32_t*)state + 1; + __srandom(seed); + savestate(); + UNLOCK(lock); + return old; +} + +char *setstate(char *state) { + void *old; + + LOCK(lock); + old = savestate(); + loadstate((uint32_t*)state); + UNLOCK(lock); + return old; +} + +long random(void) { + long k; + + LOCK(lock); + if (n == 0) { + k = x[0] = lcg31(x[0]); + goto end; + } + x[i] += x[j]; + k = x[i]>>1; + if (++i == n) + i = 0; + if (++j == n) + j = 0; +end: + UNLOCK(lock); + return k; +} diff --git a/src/orca-libc/src/stdio/__fmodeflags.c b/src/orca-libc/src/stdio/__fmodeflags.c new file mode 100644 index 00000000..da9f23b6 --- /dev/null +++ b/src/orca-libc/src/stdio/__fmodeflags.c @@ -0,0 +1,16 @@ +#include +#include + +int __fmodeflags(const char *mode) +{ + int flags; + if (strchr(mode, '+')) flags = O_RDWR; + else if (*mode == 'r') flags = O_RDONLY; + else flags = O_WRONLY; + if (strchr(mode, 'x')) flags |= O_EXCL; + if (strchr(mode, 'e')) flags |= O_CLOEXEC; + if (*mode != 'r') flags |= O_CREAT; + if (*mode == 'w') flags |= O_TRUNC; + if (*mode == 'a') flags |= O_APPEND; + return flags; +} diff --git a/src/orca-libc/src/stdio/__overflow.c b/src/orca-libc/src/stdio/__overflow.c new file mode 100644 index 00000000..e65a594d --- /dev/null +++ b/src/orca-libc/src/stdio/__overflow.c @@ -0,0 +1,10 @@ +#include "stdio_impl.h" + +int __overflow(FILE *f, int _c) +{ + unsigned char c = _c; + if (!f->wend && __towrite(f)) return EOF; + if (f->wpos != f->wend && c != f->lbf) return *f->wpos++ = c; + if (f->write(f, &c, 1)!=1) return EOF; + return c; +} diff --git a/src/orca-libc/src/stdio/__stdio_exit.c b/src/orca-libc/src/stdio/__stdio_exit.c new file mode 100644 index 00000000..a5e42c67 --- /dev/null +++ b/src/orca-libc/src/stdio/__stdio_exit.c @@ -0,0 +1,25 @@ +#include "stdio_impl.h" + +static FILE *volatile dummy_file = 0; +weak_alias(dummy_file, __stdin_used); +weak_alias(dummy_file, __stdout_used); +weak_alias(dummy_file, __stderr_used); + +static void close_file(FILE *f) +{ + if (!f) return; + FFINALLOCK(f); + if (f->wpos != f->wbase) f->write(f, 0, 0); + if (f->rpos != f->rend) f->seek(f, f->rpos-f->rend, SEEK_CUR); +} + +void __stdio_exit(void) +{ + FILE *f; + for (f=*__ofl_lock(); f; f=f->next) close_file(f); + close_file(__stdin_used); + close_file(__stdout_used); + close_file(__stderr_used); +} + +weak_alias(__stdio_exit, __stdio_exit_needed); diff --git a/src/orca-libc/src/stdio/__toread.c b/src/orca-libc/src/stdio/__toread.c new file mode 100644 index 00000000..f142ff09 --- /dev/null +++ b/src/orca-libc/src/stdio/__toread.c @@ -0,0 +1,19 @@ +#include + +int __toread(FILE *f) +{ + f->mode |= f->mode-1; + if (f->wpos != f->wbase) f->write(f, 0, 0); + f->wpos = f->wbase = f->wend = 0; + if (f->flags & F_NORD) { + f->flags |= F_ERR; + return EOF; + } + f->rpos = f->rend = f->buf + f->buf_size; + return (f->flags & F_EOF) ? EOF : 0; +} + +hidden void __toread_needs_stdio_exit() +{ + __stdio_exit_needed(); +} diff --git a/src/orca-libc/src/stdio/__towrite.c b/src/orca-libc/src/stdio/__towrite.c new file mode 100644 index 00000000..4c9c66ae --- /dev/null +++ b/src/orca-libc/src/stdio/__towrite.c @@ -0,0 +1,23 @@ +#include "stdio_impl.h" + +int __towrite(FILE *f) +{ + f->mode |= f->mode-1; + if (f->flags & F_NOWR) { + f->flags |= F_ERR; + return EOF; + } + /* Clear read buffer (easier than summoning nasal demons) */ + f->rpos = f->rend = 0; + + /* Activate write through the buffer. */ + f->wpos = f->wbase = f->buf; + f->wend = f->buf + f->buf_size; + + return 0; +} + +hidden void __towrite_needs_stdio_exit() +{ + __stdio_exit_needed(); +} diff --git a/src/orca-libc/src/stdio/__uflow.c b/src/orca-libc/src/stdio/__uflow.c new file mode 100644 index 00000000..2a88bca6 --- /dev/null +++ b/src/orca-libc/src/stdio/__uflow.c @@ -0,0 +1,11 @@ +#include "stdio_impl.h" + +/* This function assumes it will never be called if there is already + * data buffered for reading. */ + +int __uflow(FILE *f) +{ + unsigned char c; + if (!__toread(f) && f->read(f, &c, 1)==1) return c; + return EOF; +} diff --git a/src/orca-libc/src/stdio/clearerr.c b/src/orca-libc/src/stdio/clearerr.c new file mode 100644 index 00000000..3bf94d30 --- /dev/null +++ b/src/orca-libc/src/stdio/clearerr.c @@ -0,0 +1,10 @@ +#include "stdio_impl.h" + +void clearerr(FILE *f) +{ + FLOCK(f); + f->flags &= ~(F_EOF|F_ERR); + FUNLOCK(f); +} + +weak_alias(clearerr, clearerr_unlocked); diff --git a/src/orca-libc/src/stdio/fclose.c b/src/orca-libc/src/stdio/fclose.c new file mode 100644 index 00000000..2666ee9d --- /dev/null +++ b/src/orca-libc/src/stdio/fclose.c @@ -0,0 +1,41 @@ +#include "stdio_impl.h" +#include + +static void dummy(FILE *f) { } +weak_alias(dummy, __unlist_locked_file); + +int fclose(FILE *f) +{ + int r; + + FLOCK(f); + r = fflush(f); + r |= f->close(f); + FUNLOCK(f); + + /* Past this point, f is closed and any further explict access + * to it is undefined. However, it still exists as an entry in + * the open file list and possibly in the thread's locked files + * list, if it was closed while explicitly locked. Functions + * which process these lists must tolerate dead FILE objects + * (which necessarily have inactive buffer pointers) without + * producing any side effects. */ + + if (f->flags & F_PERM) return r; + + __unlist_locked_file(f); + + FILE **head = __ofl_lock(); + if (f->prev) f->prev->next = f->next; + if (f->next) f->next->prev = f->prev; + if (*head == f) *head = f->next; + __ofl_unlock(); + + if (f != stdout && f != stderr && f != stdin) + { + free(f->getln_buf); + free(f); + } + + return r; +} diff --git a/src/orca-libc/src/stdio/feof.c b/src/orca-libc/src/stdio/feof.c new file mode 100644 index 00000000..56da6b91 --- /dev/null +++ b/src/orca-libc/src/stdio/feof.c @@ -0,0 +1,14 @@ +#include "stdio_impl.h" + +#undef feof + +int feof(FILE *f) +{ + FLOCK(f); + int ret = !!(f->flags & F_EOF); + FUNLOCK(f); + return ret; +} + +weak_alias(feof, feof_unlocked); +weak_alias(feof, _IO_feof_unlocked); diff --git a/src/orca-libc/src/stdio/ferror.c b/src/orca-libc/src/stdio/ferror.c new file mode 100644 index 00000000..d692eed9 --- /dev/null +++ b/src/orca-libc/src/stdio/ferror.c @@ -0,0 +1,14 @@ +#include "stdio_impl.h" + +#undef ferror + +int ferror(FILE *f) +{ + FLOCK(f); + int ret = !!(f->flags & F_ERR); + FUNLOCK(f); + return ret; +} + +weak_alias(ferror, ferror_unlocked); +weak_alias(ferror, _IO_ferror_unlocked); diff --git a/src/orca-libc/src/stdio/fflush.c b/src/orca-libc/src/stdio/fflush.c new file mode 100644 index 00000000..b0094376 --- /dev/null +++ b/src/orca-libc/src/stdio/fflush.c @@ -0,0 +1,47 @@ +#include "stdio_impl.h" + +/* stdout.c will override this if linked */ +static FILE *volatile dummy = 0; +weak_alias(dummy, __stdout_used); +weak_alias(dummy, __stderr_used); + +int fflush(FILE *f) +{ + if (!f) { + int r = 0; + if (__stdout_used) r |= fflush(__stdout_used); + if (__stderr_used) r |= fflush(__stderr_used); + + for (f=*__ofl_lock(); f; f=f->next) { + FLOCK(f); + if (f->wpos != f->wbase) r |= fflush(f); + FUNLOCK(f); + } + __ofl_unlock(); + + return r; + } + + FLOCK(f); + + /* If writing, flush output */ + if (f->wpos != f->wbase) { + f->write(f, 0, 0); + if (!f->wpos) { + FUNLOCK(f); + return EOF; + } + } + + /* If reading, sync position, per POSIX */ + if (f->rpos != f->rend) f->seek(f, f->rpos-f->rend, SEEK_CUR); + + /* Clear read and write modes */ + f->wpos = f->wbase = f->wend = 0; + f->rpos = f->rend = 0; + + FUNLOCK(f); + return 0; +} + +weak_alias(fflush, fflush_unlocked); diff --git a/src/orca-libc/src/stdio/fgetc.c b/src/orca-libc/src/stdio/fgetc.c new file mode 100644 index 00000000..2578afcc --- /dev/null +++ b/src/orca-libc/src/stdio/fgetc.c @@ -0,0 +1,7 @@ +#include +#include "getc.h" + +int fgetc(FILE *f) +{ + return do_getc(f); +} diff --git a/src/orca-libc/src/stdio/fgetpos.c b/src/orca-libc/src/stdio/fgetpos.c new file mode 100644 index 00000000..50813d2c --- /dev/null +++ b/src/orca-libc/src/stdio/fgetpos.c @@ -0,0 +1,11 @@ +#include "stdio_impl.h" + +int fgetpos(FILE *restrict f, fpos_t *restrict pos) +{ + off_t off = __ftello(f); + if (off < 0) return -1; + *(long long *)pos = off; + return 0; +} + +weak_alias(fgetpos, fgetpos64); diff --git a/src/orca-libc/src/stdio/fgets.c b/src/orca-libc/src/stdio/fgets.c new file mode 100644 index 00000000..6171f398 --- /dev/null +++ b/src/orca-libc/src/stdio/fgets.c @@ -0,0 +1,48 @@ +#include "stdio_impl.h" +#include + +#define MIN(a,b) ((a)<(b) ? (a) : (b)) + +char *fgets(char *restrict s, int n, FILE *restrict f) +{ + char *p = s; + unsigned char *z; + size_t k; + int c; + + FLOCK(f); + + if (n--<=1) { + f->mode |= f->mode-1; + FUNLOCK(f); + if (n) return 0; + *s = 0; + return s; + } + + while (n) { + if (f->rpos != f->rend) { + z = memchr(f->rpos, '\n', f->rend - f->rpos); + k = z ? z - f->rpos + 1 : f->rend - f->rpos; + k = MIN(k, n); + memcpy(p, f->rpos, k); + f->rpos += k; + p += k; + n -= k; + if (z || !n) break; + } + if ((c = getc_unlocked(f)) < 0) { + if (p==s || !feof(f)) s = 0; + break; + } + n--; + if ((*p++ = c) == '\n') break; + } + if (s) *p = 0; + + FUNLOCK(f); + + return s; +} + +weak_alias(fgets, fgets_unlocked); diff --git a/src/orca-libc/src/stdio/fopen.c b/src/orca-libc/src/stdio/fopen.c new file mode 100644 index 00000000..d79884e9 --- /dev/null +++ b/src/orca-libc/src/stdio/fopen.c @@ -0,0 +1,379 @@ +// #ifdef __wasilibc_unmodified_upstream // WASI has no syscall +// #else +// #include +// #include +// #endif +#include "stdio_impl.h" +#include +#include +#include + +// #include +// #include +#include +#include + +int oc_io_err_to_errno(enum oc_io_error_enum error) +{ + switch(error) + { + case OC_IO_OK: + return 0; + case OC_IO_ERR_UNKNOWN: + return EINVAL; + case OC_IO_ERR_OP: + return EOPNOTSUPP; + case OC_IO_ERR_HANDLE: + return EINVAL; + case OC_IO_ERR_PREV: + return EINVAL; + case OC_IO_ERR_ARG: + return EINVAL; + case OC_IO_ERR_PERM: + return EPERM; + case OC_IO_ERR_SPACE: + return ENOSPC; + case OC_IO_ERR_NO_ENTRY: + return ENOENT; + case OC_IO_ERR_EXISTS: + return EEXIST; + case OC_IO_ERR_NOT_DIR: + return ENOTDIR; + case OC_IO_ERR_DIR: + return EISDIR; + case OC_IO_ERR_MAX_FILES: + return EMFILE; + case OC_IO_ERR_MAX_LINKS: + return ELOOP; + case OC_IO_ERR_PATH_LENGTH: + return ENAMETOOLONG; + case OC_IO_ERR_FILE_SIZE: + return EFBIG; + case OC_IO_ERR_OVERFLOW: + return EOVERFLOW; + case OC_IO_ERR_NOT_READY: + return EAGAIN; + case OC_IO_ERR_MEM: + return ENOMEM; + case OC_IO_ERR_INTERRUPT: + return EINTR; + case OC_IO_ERR_PHYSICAL: + return EIO; + case OC_IO_ERR_NO_DEVICE: + return ENXIO; + case OC_IO_ERR_WALKOUT: + return EPERM; + } + return 0; +} + +static size_t file_read_shim(FILE* stream, unsigned char* buffer, size_t size) +{ + oc_file file = { .h = stream->orca_file }; + + // In the wasilibc __stdout_read(), there is this behavior that writes the last character of len + // to the file buffer, and to the output stream as well. This code preserves that behavior as + // it is needed by __uflow(). See original source at: + // https://github.com/WebAssembly/wasi-libc/blob/main/libc-top-half/musl/src/stdout/__stdout_read.c + char* buffers[2] = { (char*)buffer, (char*)stream->buf }; + u64 lengths[2] = { size - !!stream->buf_size, stream->buf_size }; + u64 read_bytes[2] = {0}; + + + for (int i = 0; i < 2; ++i) + { + if (lengths[i]) + { + read_bytes[i] = oc_file_read(file, lengths[i], buffers[i]); + + oc_io_error error = oc_file_last_error(file); + if (error != OC_IO_OK) + { + errno = oc_io_err_to_errno(error); + stream->flags |= F_ERR; + return 0; + } + } + } + + u64 total_read = read_bytes[0] + read_bytes[1]; + + if (total_read == 0) + { + stream->flags |= F_EOF; + return 0; + } + + if (total_read <= lengths[0]) + { + return total_read; + } + + u64 stream_buffer_size = read_bytes[1]; + + stream->rpos = stream->buf; + stream->rend = stream->buf + stream_buffer_size; + if (stream->buf_size) + { + buffer[size - 1] = *stream->rpos; + ++stream->rpos; + } + return size; +} + +static size_t file_write_shim(FILE* stream, const unsigned char* buffer, size_t size) +{ + oc_file file = { .h = stream->orca_file }; + + // write out any data in the internal buffer, then the requested buffer + char* buffers[2] = { (char*)stream->wbase, (char*)buffer }; + u64 lengths[2] = { stream->wpos - stream->wbase, size }; + + for (int i = 0; i < 2; ++i) + { + u64 total = 0; + while (total < lengths[i]) + { + u64 written = oc_file_write(file, lengths[i] - total, buffers[i] + total); + + oc_io_error error = oc_file_last_error(file); + if(error != OC_IO_OK) + { + errno = oc_io_err_to_errno(error); + stream->flags |= F_ERR; + stream->wbase = 0; + stream->wpos = 0; + stream->wend = 0; + return -1; + } + + total += written; + } + } + + // reset the internal buffer now that all the data has been written + stream->wend = stream->buf + stream->buf_size; + stream->wbase = stream->buf; + stream->wpos = stream->wbase; + return size; +} + +static off_t file_seek_shim(FILE* stream, off_t offset, int origin) +{ + static const oc_file_whence LIBC_WHENCE_TO_OC_WHENCE[3] = { + OC_FILE_SEEK_SET, // SEEK_SET + OC_FILE_SEEK_CURRENT, // SEEK_CUR + OC_FILE_SEEK_END, // SEEK_END + }; + oc_file_whence whence = LIBC_WHENCE_TO_OC_WHENCE[origin]; + + oc_file file = { .h = stream->orca_file }; + + i64 result = oc_file_seek(file, offset, whence); + oc_io_error error = oc_file_last_error(file); + if(error != OC_IO_OK) + { + errno = oc_io_err_to_errno(error); + stream->flags |= F_ERR; + result = -1; + } + + return result; +} + +static int file_close_shim(FILE* stream) +{ + oc_file file = { .h = stream->orca_file }; + oc_file_close(file); + return 0; +} + +size_t __file_read_err_shim(FILE* stream, unsigned char* buffer, size_t size) +{ + stream->flags |= F_ERR; + errno = ENOTSUP; + return 0; +} +size_t __file_write_err_shim(FILE* stream, const unsigned char* buffer, size_t size) +{ + stream->flags |= F_ERR; + errno = ENOTSUP; + return 0; +} +off_t __file_seek_err_shim(FILE* stream, off_t offset, int origin) +{ + stream->flags |= F_ERR; + errno = ENOTSUP; + return 0; +} +int __file_close_err_shim(FILE* stream) +{ + stream->flags |= F_ERR; + errno = ENOTSUP; + return 0; +} + +static oc_file fopen_orca_file(const char* restrict filename, const char* restrict mode) +{ + /* Check for valid initial mode character */ + if (!strchr("rwa", *mode)) { + errno = EINVAL; + return oc_file_nil(); + } + + /* Compute the flags to pass to open() */ + int flags = __fmodeflags(mode); + + oc_file_access orca_rights = 0; + if (flags & O_RDWR) + { + orca_rights = OC_FILE_ACCESS_READ | OC_FILE_ACCESS_WRITE; + } + else if (flags & O_WRONLY) + { + orca_rights = OC_FILE_ACCESS_WRITE; + } + else // if (flags & O_RDONLY) - O_RDONLY is 0 + { + orca_rights = OC_FILE_ACCESS_READ; + } + + oc_file_open_flags orca_flags = OC_FILE_OPEN_RESTRICT; + + if (flags & O_CREAT) + { + orca_flags |= OC_FILE_OPEN_CREATE; + } + if (flags & O_TRUNC) + { + orca_flags |= OC_FILE_OPEN_TRUNCATE; + } + if (flags & O_APPEND) + { + orca_flags |= OC_FILE_OPEN_APPEND; + } + + oc_file file = oc_file_open(OC_STR8(filename), orca_rights, orca_flags); + oc_io_error error = oc_file_last_error(file); + if(error != OC_IO_OK) + { + errno = oc_io_err_to_errno(error); + oc_file_close(file); + return oc_file_nil(); + } + + return file; +} + +static FILE* fopen_struct_setup(FILE* f, oc_file file, const char* restrict mode) +{ + int flags = __fmodeflags(mode); + + /* Zero-fill only the struct, not the buffer */ + memset(f, 0, sizeof *f); + + /* Impose mode restrictions */ + if (!strchr(mode, '+')) f->flags = (*mode == 'r') ? F_NOWR : F_NORD; + + /* Set append mode on fd if opened for append */ + if (*mode == 'a') { + f->flags |= F_APP; + } + + f->orca_file = file.h; + f->buf = (unsigned char *)f + sizeof *f + UNGET; + f->buf_size = BUFSIZ; + + /* Initialize op ptrs. No problem if some are unneeded. */ + f->read = file_read_shim; + f->write = file_write_shim; + f->seek = file_seek_shim; + f->close = file_close_shim; + +#if defined(_REENTRANT) + if (!libc.threaded) f->lock = -1; +#endif + + /* Add new FILE to open file list */ + return __ofl_add(f); +} + +FILE* fopen(const char* restrict filename, const char* restrict mode) +{ + oc_file file = fopen_orca_file(filename, mode); + if (oc_file_is_nil(file)) + { + return NULL; + } + + FILE* f; + if (!(f=malloc(sizeof *f + UNGET + BUFSIZ))) return NULL; + return fopen_struct_setup(f, file, mode); +} + +static unsigned char stdout_buf[BUFSIZ+UNGET]; +static unsigned char stderr_buf[BUFSIZ+UNGET]; +static unsigned char stdin_buf[BUFSIZ+UNGET]; + +FILE* freopen(const char* restrict filename, const char* restrict mode, FILE* restrict f) +{ + if (filename == NULL) { + fclose(f); + return NULL; + } + + FLOCK(f); + + fflush(f); + f->close(f); + + oc_file file = fopen_orca_file(filename, mode); + if (oc_file_is_nil(file)) + { + free(f); + return NULL; + } + + f->orca_file = file.h; + + int flags = __fmodeflags(mode); + if (*mode == 'a') { + flags |= F_APP; + } + + f->flags = flags; + + if (f == stdout || f == stderr || f == stdin) + { + if (f == stdout) + { + f->buf = stdout_buf; + } + else if (f == stderr) + { + f->buf = stderr_buf; + } + else if (f == stdin) + { + f->buf = stdin_buf; + } + f->buf_size = BUFSIZ; + + f->rpos = 0; + f->rend = 0; + f->wbase = 0; + f->wpos = 0; + f->wend = 0; + + f->read = file_read_shim; + f->write = file_write_shim; + f->seek = file_seek_shim; + f->close = file_close_shim; + } + + FUNLOCK(f); + return f; +} + +weak_alias(fopen, fopen64); +weak_alias(freopen, freopen64); diff --git a/src/orca-libc/src/stdio/fprintf.c b/src/orca-libc/src/stdio/fprintf.c new file mode 100644 index 00000000..948743f7 --- /dev/null +++ b/src/orca-libc/src/stdio/fprintf.c @@ -0,0 +1,12 @@ +#include +#include + +int fprintf(FILE *restrict f, const char *restrict fmt, ...) +{ + int ret; + va_list ap; + va_start(ap, fmt); + ret = vfprintf(f, fmt, ap); + va_end(ap); + return ret; +} diff --git a/src/orca-libc/src/stdio/fputc.c b/src/orca-libc/src/stdio/fputc.c new file mode 100644 index 00000000..f364ed38 --- /dev/null +++ b/src/orca-libc/src/stdio/fputc.c @@ -0,0 +1,7 @@ +#include +#include "putc.h" + +int fputc(int c, FILE *f) +{ + return do_putc(c, f); +} diff --git a/src/orca-libc/src/stdio/fputs.c b/src/orca-libc/src/stdio/fputs.c new file mode 100644 index 00000000..1cf344f2 --- /dev/null +++ b/src/orca-libc/src/stdio/fputs.c @@ -0,0 +1,10 @@ +#include "stdio_impl.h" +#include + +int fputs(const char *restrict s, FILE *restrict f) +{ + size_t l = strlen(s); + return (fwrite(s, 1, l, f)==l) - 1; +} + +weak_alias(fputs, fputs_unlocked); diff --git a/src/orca-libc/src/stdio/fread.c b/src/orca-libc/src/stdio/fread.c new file mode 100644 index 00000000..a2116da6 --- /dev/null +++ b/src/orca-libc/src/stdio/fread.c @@ -0,0 +1,38 @@ +#include "stdio_impl.h" +#include + +#define MIN(a,b) ((a)<(b) ? (a) : (b)) + +size_t fread(void *restrict destv, size_t size, size_t nmemb, FILE *restrict f) +{ + unsigned char *dest = destv; + size_t len = size*nmemb, l = len, k; + if (!size) nmemb = 0; + + FLOCK(f); + + f->mode |= f->mode-1; + + if (f->rpos != f->rend) { + /* First exhaust the buffer. */ + k = MIN(f->rend - f->rpos, l); + memcpy(dest, f->rpos, k); + f->rpos += k; + dest += k; + l -= k; + } + + /* Read the remainder directly */ + for (; l; l-=k, dest+=k) { + k = __toread(f) ? 0 : f->read(f, dest, l); + if (!k) { + FUNLOCK(f); + return (len-l)/size; + } + } + + FUNLOCK(f); + return nmemb; +} + +weak_alias(fread, fread_unlocked); diff --git a/src/orca-libc/src/stdio/fscanf.c b/src/orca-libc/src/stdio/fscanf.c new file mode 100644 index 00000000..f639e118 --- /dev/null +++ b/src/orca-libc/src/stdio/fscanf.c @@ -0,0 +1,14 @@ +#include +#include + +int fscanf(FILE *restrict f, const char *restrict fmt, ...) +{ + int ret; + va_list ap; + va_start(ap, fmt); + ret = vfscanf(f, fmt, ap); + va_end(ap); + return ret; +} + +weak_alias(fscanf, __isoc99_fscanf); diff --git a/src/orca-libc/src/stdio/fseek.c b/src/orca-libc/src/stdio/fseek.c new file mode 100644 index 00000000..c07f7e95 --- /dev/null +++ b/src/orca-libc/src/stdio/fseek.c @@ -0,0 +1,50 @@ +#include "stdio_impl.h" +#include + +int __fseeko_unlocked(FILE *f, off_t off, int whence) +{ + /* Fail immediately for invalid whence argument. */ + if (whence != SEEK_CUR && whence != SEEK_SET && whence != SEEK_END) { + errno = EINVAL; + return -1; + } + + /* Adjust relative offset for unread data in buffer, if any. */ + if (whence == SEEK_CUR && f->rend) off -= f->rend - f->rpos; + + /* Flush write buffer, and report error on failure. */ + if (f->wpos != f->wbase) { + f->write(f, 0, 0); + if (!f->wpos) return -1; + } + + /* Leave writing mode */ + f->wpos = f->wbase = f->wend = 0; + + /* Perform the underlying seek. */ + if (f->seek(f, off, whence) < 0) return -1; + + /* If seek succeeded, file is seekable and we discard read buffer. */ + f->rpos = f->rend = 0; + f->flags &= ~F_EOF; + + return 0; +} + +int __fseeko(FILE *f, off_t off, int whence) +{ + int result; + FLOCK(f); + result = __fseeko_unlocked(f, off, whence); + FUNLOCK(f); + return result; +} + +int fseek(FILE *f, long off, int whence) +{ + return __fseeko(f, off, whence); +} + +weak_alias(__fseeko, fseeko); + +weak_alias(fseeko, fseeko64); diff --git a/src/orca-libc/src/stdio/fsetpos.c b/src/orca-libc/src/stdio/fsetpos.c new file mode 100644 index 00000000..77ab8d82 --- /dev/null +++ b/src/orca-libc/src/stdio/fsetpos.c @@ -0,0 +1,8 @@ +#include "stdio_impl.h" + +int fsetpos(FILE *f, const fpos_t *pos) +{ + return __fseeko(f, *(const long long *)pos, SEEK_SET); +} + +weak_alias(fsetpos, fsetpos64); diff --git a/src/orca-libc/src/stdio/ftell.c b/src/orca-libc/src/stdio/ftell.c new file mode 100644 index 00000000..1a2afbbc --- /dev/null +++ b/src/orca-libc/src/stdio/ftell.c @@ -0,0 +1,41 @@ +#include "stdio_impl.h" +#include +#include + +off_t __ftello_unlocked(FILE *f) +{ + off_t pos = f->seek(f, 0, + (f->flags & F_APP) && f->wpos != f->wbase + ? SEEK_END : SEEK_CUR); + if (pos < 0) return pos; + + /* Adjust for data in buffer. */ + if (f->rend) + pos += f->rpos - f->rend; + else if (f->wbase) + pos += f->wpos - f->wbase; + return pos; +} + +off_t __ftello(FILE *f) +{ + off_t pos; + FLOCK(f); + pos = __ftello_unlocked(f); + FUNLOCK(f); + return pos; +} + +long ftell(FILE *f) +{ + off_t pos = __ftello(f); + if (pos > LONG_MAX) { + errno = EOVERFLOW; + return -1; + } + return pos; +} + +weak_alias(__ftello, ftello); + +weak_alias(ftello, ftello64); diff --git a/src/orca-libc/src/stdio/fwrite.c b/src/orca-libc/src/stdio/fwrite.c new file mode 100644 index 00000000..7a567b2c --- /dev/null +++ b/src/orca-libc/src/stdio/fwrite.c @@ -0,0 +1,38 @@ +#include "stdio_impl.h" +#include + +size_t __fwritex(const unsigned char *restrict s, size_t l, FILE *restrict f) +{ + size_t i=0; + + if (!f->wend && __towrite(f)) return 0; + + if (l > f->wend - f->wpos) return f->write(f, s, l); + + if (f->lbf >= 0) { + /* Match /^(.*\n|)/ */ + for (i=l; i && s[i-1] != '\n'; i--); + if (i) { + size_t n = f->write(f, s, i); + if (n < i) return n; + s += i; + l -= i; + } + } + + memcpy(f->wpos, s, l); + f->wpos += l; + return l+i; +} + +size_t fwrite(const void *restrict src, size_t size, size_t nmemb, FILE *restrict f) +{ + size_t k, l = size*nmemb; + if (!size) nmemb = 0; + FLOCK(f); + k = __fwritex(src, l, f); + FUNLOCK(f); + return k==l ? nmemb : k/size; +} + +weak_alias(fwrite, fwrite_unlocked); diff --git a/src/orca-libc/src/stdio/getc.h b/src/orca-libc/src/stdio/getc.h new file mode 100644 index 00000000..e62e3f0d --- /dev/null +++ b/src/orca-libc/src/stdio/getc.h @@ -0,0 +1,29 @@ +#include "stdio_impl.h" +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) +#include "pthread_impl.h" + +#ifdef __GNUC__ +__attribute__((__noinline__)) +#endif +static int locking_getc(FILE *f) +{ + if (a_cas(&f->lock, 0, MAYBE_WAITERS-1)) __lockfile(f); + int c = getc_unlocked(f); + if (a_swap(&f->lock, 0) & MAYBE_WAITERS) + __wake(&f->lock, 1, 1); + return c; +} +#endif + +static inline int do_getc(FILE *f) +{ +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) + int l = f->lock; + if (l < 0 || l && (l & ~MAYBE_WAITERS) == __pthread_self()->tid) + return getc_unlocked(f); + return locking_getc(f); +#else + // With no threads, locking is unnecessary. + return getc_unlocked(f); +#endif +} diff --git a/src/orca-libc/src/stdio/getchar.c b/src/orca-libc/src/stdio/getchar.c new file mode 100644 index 00000000..df395ca9 --- /dev/null +++ b/src/orca-libc/src/stdio/getchar.c @@ -0,0 +1,7 @@ +#include +#include "getc.h" + +int getchar(void) +{ + return do_getc(stdin); +} diff --git a/src/orca-libc/src/stdio/ofl.c b/src/orca-libc/src/stdio/ofl.c new file mode 100644 index 00000000..06dbe828 --- /dev/null +++ b/src/orca-libc/src/stdio/ofl.c @@ -0,0 +1,19 @@ +#include "stdio_impl.h" +#include "lock.h" + +static FILE *ofl_head; +#if defined(_REENTRANT) +static volatile int ofl_lock[1]; +volatile int *const __stdio_ofl_lockptr = ofl_lock; +#endif + +FILE **__ofl_lock() +{ + LOCK(ofl_lock); + return &ofl_head; +} + +void __ofl_unlock() +{ + UNLOCK(ofl_lock); +} diff --git a/src/orca-libc/src/stdio/ofl_add.c b/src/orca-libc/src/stdio/ofl_add.c new file mode 100644 index 00000000..d7de9f15 --- /dev/null +++ b/src/orca-libc/src/stdio/ofl_add.c @@ -0,0 +1,11 @@ +#include "stdio_impl.h" + +FILE *__ofl_add(FILE *f) +{ + FILE **head = __ofl_lock(); + f->next = *head; + if (*head) (*head)->prev = f; + *head = f; + __ofl_unlock(); + return f; +} diff --git a/src/orca-libc/src/stdio/perror.c b/src/orca-libc/src/stdio/perror.c new file mode 100644 index 00000000..d0943f26 --- /dev/null +++ b/src/orca-libc/src/stdio/perror.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include "stdio_impl.h" + +void perror(const char *msg) +{ + FILE *f = stderr; + char *errstr = strerror(errno); + + FLOCK(f); + + /* Save stderr's orientation and encoding rule, since perror is not + * permitted to change them. */ + void *old_locale = f->locale; + int old_mode = f->mode; + + if (msg && *msg) { + fwrite(msg, strlen(msg), 1, f); + fputc(':', f); + fputc(' ', f); + } + fwrite(errstr, strlen(errstr), 1, f); + fputc('\n', f); + + f->mode = old_mode; + f->locale = old_locale; + + FUNLOCK(f); +} diff --git a/src/orca-libc/src/stdio/printf.c b/src/orca-libc/src/stdio/printf.c new file mode 100644 index 00000000..46cc6d8e --- /dev/null +++ b/src/orca-libc/src/stdio/printf.c @@ -0,0 +1,17 @@ +#include +#include + +int printf(const char *restrict fmt, ...) +{ + int ret; + va_list ap; + va_start(ap, fmt); + ret = vfprintf(stdout, fmt, ap); + va_end(ap); + return ret; +} +#ifdef __wasilibc_unmodified_upstream // Changes to optimize printf/scanf when long double isn't needed +#else +weak_alias(printf, iprintf); +weak_alias(printf, __small_printf); +#endif diff --git a/src/orca-libc/src/stdio/putc.h b/src/orca-libc/src/stdio/putc.h new file mode 100644 index 00000000..2cc63d2d --- /dev/null +++ b/src/orca-libc/src/stdio/putc.h @@ -0,0 +1,29 @@ +#include "stdio_impl.h" +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) +#include "pthread_impl.h" + +#ifdef __GNUC__ +__attribute__((__noinline__)) +#endif +static int locking_putc(int c, FILE *f) +{ + if (a_cas(&f->lock, 0, MAYBE_WAITERS-1)) __lockfile(f); + c = putc_unlocked(c, f); + if (a_swap(&f->lock, 0) & MAYBE_WAITERS) + __wake(&f->lock, 1, 1); + return c; +} +#endif + +static inline int do_putc(int c, FILE *f) +{ +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) + int l = f->lock; + if (l < 0 || l && (l & ~MAYBE_WAITERS) == __pthread_self()->tid) + return putc_unlocked(c, f); + return locking_putc(c, f); +#else + // With no threads, locking is unnecessary. + return putc_unlocked(c, f); +#endif +} diff --git a/src/orca-libc/src/stdio/putchar.c b/src/orca-libc/src/stdio/putchar.c new file mode 100644 index 00000000..f044f169 --- /dev/null +++ b/src/orca-libc/src/stdio/putchar.c @@ -0,0 +1,7 @@ +#include +#include "putc.h" + +int putchar(int c) +{ + return do_putc(c, stdout); +} diff --git a/src/orca-libc/src/stdio/rewind.c b/src/orca-libc/src/stdio/rewind.c new file mode 100644 index 00000000..6f4b58b5 --- /dev/null +++ b/src/orca-libc/src/stdio/rewind.c @@ -0,0 +1,9 @@ +#include "stdio_impl.h" + +void rewind(FILE *f) +{ + FLOCK(f); + __fseeko_unlocked(f, 0, SEEK_SET); + f->flags &= ~F_ERR; + FUNLOCK(f); +} diff --git a/src/orca-libc/src/stdio/scanf.c b/src/orca-libc/src/stdio/scanf.c new file mode 100644 index 00000000..bd77699c --- /dev/null +++ b/src/orca-libc/src/stdio/scanf.c @@ -0,0 +1,14 @@ +#include +#include + +int scanf(const char *restrict fmt, ...) +{ + int ret; + va_list ap; + va_start(ap, fmt); + ret = vscanf(fmt, ap); + va_end(ap); + return ret; +} + +weak_alias(scanf,__isoc99_scanf); diff --git a/src/orca-libc/src/stdio/setbuf.c b/src/orca-libc/src/stdio/setbuf.c new file mode 100644 index 00000000..74ad7834 --- /dev/null +++ b/src/orca-libc/src/stdio/setbuf.c @@ -0,0 +1,6 @@ +#include + +void setbuf(FILE *restrict f, char *restrict buf) +{ + setvbuf(f, buf, buf ? _IOFBF : _IONBF, BUFSIZ); +} diff --git a/src/orca-libc/src/stdio/setvbuf.c b/src/orca-libc/src/stdio/setvbuf.c new file mode 100644 index 00000000..523dddc8 --- /dev/null +++ b/src/orca-libc/src/stdio/setvbuf.c @@ -0,0 +1,29 @@ +#include "stdio_impl.h" + +/* The behavior of this function is undefined except when it is the first + * operation on the stream, so the presence or absence of locking is not + * observable in a program whose behavior is defined. Thus no locking is + * performed here. No allocation of buffers is performed, but a buffer + * provided by the caller is used as long as it is suitably sized. */ + +int setvbuf(FILE *restrict f, char *restrict buf, int type, size_t size) +{ + f->lbf = EOF; + + if (type == _IONBF) { + f->buf_size = 0; + } else if (type == _IOLBF || type == _IOFBF) { + if (buf && size >= UNGET) { + f->buf = (void *)(buf + UNGET); + f->buf_size = size - UNGET; + } + if (type == _IOLBF && f->buf_size) + f->lbf = '\n'; + } else { + return -1; + } + + f->flags |= F_SVB; + + return 0; +} diff --git a/src/orca-libc/src/stdio/snprintf.c b/src/orca-libc/src/stdio/snprintf.c new file mode 100644 index 00000000..771503b2 --- /dev/null +++ b/src/orca-libc/src/stdio/snprintf.c @@ -0,0 +1,13 @@ +#include +#include + +int snprintf(char *restrict s, size_t n, const char *restrict fmt, ...) +{ + int ret; + va_list ap; + va_start(ap, fmt); + ret = vsnprintf(s, n, fmt, ap); + va_end(ap); + return ret; +} + diff --git a/src/orca-libc/src/stdio/sprintf.c b/src/orca-libc/src/stdio/sprintf.c new file mode 100644 index 00000000..9dff524c --- /dev/null +++ b/src/orca-libc/src/stdio/sprintf.c @@ -0,0 +1,12 @@ +#include +#include + +int sprintf(char *restrict s, const char *restrict fmt, ...) +{ + int ret; + va_list ap; + va_start(ap, fmt); + ret = vsprintf(s, fmt, ap); + va_end(ap); + return ret; +} diff --git a/src/orca-libc/src/stdio/sscanf.c b/src/orca-libc/src/stdio/sscanf.c new file mode 100644 index 00000000..f2ac2f5d --- /dev/null +++ b/src/orca-libc/src/stdio/sscanf.c @@ -0,0 +1,14 @@ +#include +#include + +int sscanf(const char *restrict s, const char *restrict fmt, ...) +{ + int ret; + va_list ap; + va_start(ap, fmt); + ret = vsscanf(s, fmt, ap); + va_end(ap); + return ret; +} + +weak_alias(sscanf,__isoc99_sscanf); diff --git a/src/orca-libc/src/stdio/stderr.c b/src/orca-libc/src/stdio/stderr.c new file mode 100644 index 00000000..a2b2811a --- /dev/null +++ b/src/orca-libc/src/stdio/stderr.c @@ -0,0 +1,20 @@ +#include "stdio_impl.h" + +#undef stderr + +static unsigned char buf[BUFSIZ+UNGET]; +hidden FILE __stderr_FILE = { + .buf = buf+UNGET, + .buf_size = sizeof buf-UNGET, + .orca_file = 0, // oc_file handle 0 is the nil handle, + .flags = F_PERM | F_NOWR | F_NORD, + .read = __file_read_err_shim, + .write = __file_write_err_shim, + .seek = __file_seek_err_shim, + .close = __file_close_err_shim, +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) + .lock = -1, +#endif +}; +FILE *const stderr = &__stderr_FILE; +FILE *volatile __stderr_used = &__stderr_FILE; diff --git a/src/orca-libc/src/stdio/stdin.c b/src/orca-libc/src/stdio/stdin.c new file mode 100644 index 00000000..9f128538 --- /dev/null +++ b/src/orca-libc/src/stdio/stdin.c @@ -0,0 +1,20 @@ +#include "stdio_impl.h" + +#undef stdin + +static unsigned char buf[BUFSIZ+UNGET]; +hidden FILE __stdin_FILE = { + .buf = buf+UNGET, + .buf_size = sizeof buf-UNGET, + .orca_file = 0, // oc_file handle 0 is the nil handle, + .flags = F_PERM | F_NOWR | F_NORD, + .read = __file_read_err_shim, + .write = __file_write_err_shim, + .seek = __file_seek_err_shim, + .close = __file_close_err_shim, +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) + .lock = -1, +#endif +}; +FILE *const stdin = &__stdin_FILE; +FILE *volatile __stdin_used = &__stdin_FILE; diff --git a/src/orca-libc/src/stdio/stdout.c b/src/orca-libc/src/stdio/stdout.c new file mode 100644 index 00000000..314c8853 --- /dev/null +++ b/src/orca-libc/src/stdio/stdout.c @@ -0,0 +1,20 @@ +#include "stdio_impl.h" + +#undef stdout + +static unsigned char buf[BUFSIZ+UNGET]; +hidden FILE __stdout_FILE = { + .buf = buf+UNGET, + .buf_size = sizeof buf-UNGET, + .orca_file = 0, // oc_file handle 0 is the nil handle, + .flags = F_PERM | F_NOWR | F_NORD, + .read = __file_read_err_shim, + .write = __file_write_err_shim, + .seek = __file_seek_err_shim, + .close = __file_close_err_shim, +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) + .lock = -1, +#endif +}; +FILE *const stdout = &__stdout_FILE; +FILE *volatile __stdout_used = &__stdout_FILE; diff --git a/src/orca-libc/src/stdio/ungetc.c b/src/orca-libc/src/stdio/ungetc.c new file mode 100644 index 00000000..bc629d4c --- /dev/null +++ b/src/orca-libc/src/stdio/ungetc.c @@ -0,0 +1,20 @@ +#include "stdio_impl.h" + +int ungetc(int c, FILE *f) +{ + if (c == EOF) return c; + + FLOCK(f); + + if (!f->rpos) __toread(f); + if (!f->rpos || f->rpos <= f->buf - UNGET) { + FUNLOCK(f); + return EOF; + } + + *--f->rpos = c; + f->flags &= ~F_EOF; + + FUNLOCK(f); + return (unsigned char)c; +} diff --git a/src/orca-libc/src/stdio/vfprintf.c b/src/orca-libc/src/stdio/vfprintf.c new file mode 100644 index 00000000..7da2e504 --- /dev/null +++ b/src/orca-libc/src/stdio/vfprintf.c @@ -0,0 +1,737 @@ +#include "stdio_impl.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __wasilibc_unmodified_upstream // Changes to optimize printf/scanf when long double isn't needed +#else +#include "printscan.h" +#endif + +/* Some useful macros */ + +#define MAX(a,b) ((a)>(b) ? (a) : (b)) +#define MIN(a,b) ((a)<(b) ? (a) : (b)) + +/* Convenient bit representation for modifier flags, which all fall + * within 31 codepoints of the space character. */ + +#define ALT_FORM (1U<<'#'-' ') +#define ZERO_PAD (1U<<'0'-' ') +#define LEFT_ADJ (1U<<'-'-' ') +#define PAD_POS (1U<<' '-' ') +#define MARK_POS (1U<<'+'-' ') +#define GROUPED (1U<<'\''-' ') + +#define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS|GROUPED) + +/* State machine to accept length modifiers + conversion specifiers. + * Result is 0 on failure, or an argument type to pop on success. */ + +enum { + BARE, LPRE, LLPRE, HPRE, HHPRE, BIGLPRE, + ZTPRE, JPRE, + STOP, + PTR, INT, UINT, ULLONG, + LONG, ULONG, + SHORT, USHORT, CHAR, UCHAR, + LLONG, SIZET, IMAX, UMAX, PDIFF, UIPTR, + DBL, LDBL, + NOARG, + MAXSTATE +}; + +#define S(x) [(x)-'A'] + +static const unsigned char states[]['z'-'A'+1] = { + { /* 0: bare types */ + S('d') = INT, S('i') = INT, + S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT, + S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL, + S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL, + S('c') = CHAR, S('C') = INT, + S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR, + S('m') = NOARG, + S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE, + S('z') = ZTPRE, S('j') = JPRE, S('t') = ZTPRE, + }, { /* 1: l-prefixed */ + S('d') = LONG, S('i') = LONG, + S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG, + S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL, + S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL, + S('c') = INT, S('s') = PTR, S('n') = PTR, + S('l') = LLPRE, + }, { /* 2: ll-prefixed */ + S('d') = LLONG, S('i') = LLONG, + S('o') = ULLONG, S('u') = ULLONG, + S('x') = ULLONG, S('X') = ULLONG, + S('n') = PTR, + }, { /* 3: h-prefixed */ + S('d') = SHORT, S('i') = SHORT, + S('o') = USHORT, S('u') = USHORT, + S('x') = USHORT, S('X') = USHORT, + S('n') = PTR, + S('h') = HHPRE, + }, { /* 4: hh-prefixed */ + S('d') = CHAR, S('i') = CHAR, + S('o') = UCHAR, S('u') = UCHAR, + S('x') = UCHAR, S('X') = UCHAR, + S('n') = PTR, + }, { /* 5: L-prefixed */ + S('e') = LDBL, S('f') = LDBL, S('g') = LDBL, S('a') = LDBL, + S('E') = LDBL, S('F') = LDBL, S('G') = LDBL, S('A') = LDBL, + S('n') = PTR, + }, { /* 6: z- or t-prefixed (assumed to be same size) */ + S('d') = PDIFF, S('i') = PDIFF, + S('o') = SIZET, S('u') = SIZET, + S('x') = SIZET, S('X') = SIZET, + S('n') = PTR, + }, { /* 7: j-prefixed */ + S('d') = IMAX, S('i') = IMAX, + S('o') = UMAX, S('u') = UMAX, + S('x') = UMAX, S('X') = UMAX, + S('n') = PTR, + } +}; + +#define OOB(x) ((unsigned)(x)-'A' > 'z'-'A') + +union arg +{ + uintmax_t i; +#if !defined(__wasilibc_printscan_no_floating_point) +#if defined(__wasilibc_printscan_no_long_double) + long_double f; +#else + long double f; +#endif +#endif + void *p; +}; + +static void pop_arg(union arg *arg, int type, va_list *ap) +{ + switch (type) { + case PTR: arg->p = va_arg(*ap, void *); + break; case INT: arg->i = va_arg(*ap, int); + break; case UINT: arg->i = va_arg(*ap, unsigned int); + break; case LONG: arg->i = va_arg(*ap, long); + break; case ULONG: arg->i = va_arg(*ap, unsigned long); + break; case ULLONG: arg->i = va_arg(*ap, unsigned long long); + break; case SHORT: arg->i = (short)va_arg(*ap, int); + break; case USHORT: arg->i = (unsigned short)va_arg(*ap, int); + break; case CHAR: arg->i = (signed char)va_arg(*ap, int); + break; case UCHAR: arg->i = (unsigned char)va_arg(*ap, int); + break; case LLONG: arg->i = va_arg(*ap, long long); + break; case SIZET: arg->i = va_arg(*ap, size_t); + break; case IMAX: arg->i = va_arg(*ap, intmax_t); + break; case UMAX: arg->i = va_arg(*ap, uintmax_t); + break; case PDIFF: arg->i = va_arg(*ap, ptrdiff_t); + break; case UIPTR: arg->i = (uintptr_t)va_arg(*ap, void *); +#if defined(__wasilibc_printscan_no_floating_point) + break; case DBL: + case LDBL: + floating_point_not_supported(); +#else + break; case DBL: arg->f = va_arg(*ap, double); +#if defined(__wasilibc_printscan_no_long_double) + break; case LDBL: long_double_not_supported(); +#else + break; case LDBL: arg->f = va_arg(*ap, long double); +#endif +#endif + } +} + +static void out(FILE *f, const char *s, size_t l) +{ + if (!(f->flags & F_ERR)) __fwritex((void *)s, l, f); +} + +static void pad(FILE *f, char c, int w, int l, int fl) +{ + char pad[256]; + if (fl & (LEFT_ADJ | ZERO_PAD) || l >= w) return; + l = w - l; + memset(pad, c, l>sizeof pad ? sizeof pad : l); + for (; l >= sizeof pad; l -= sizeof pad) + out(f, pad, sizeof pad); + out(f, pad, l); +} + +static const char xdigits[16] = { + "0123456789ABCDEF" +}; + +static char *fmt_x(uintmax_t x, char *s, int lower) +{ + for (; x; x>>=4) *--s = xdigits[(x&15)]|lower; + return s; +} + +static char *fmt_o(uintmax_t x, char *s) +{ + for (; x; x>>=3) *--s = '0' + (x&7); + return s; +} + +static char *fmt_u(uintmax_t x, char *s) +{ + unsigned long y; + for ( ; x>ULONG_MAX; x/=10) *--s = '0' + x%10; + for (y=x; y; y/=10) *--s = '0' + y%10; + return s; +} + +#if !defined(__wasilibc_printscan_no_floating_point) +/* Do not override this check. The floating point printing code below + * depends on the float.h constants being right. If they are wrong, it + * may overflow the stack. */ +#if LDBL_MANT_DIG == 53 +#if defined(__wasilibc_printscan_no_long_double) +typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long_double)]; +#else +typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)]; +#endif +#endif + +#if defined(__wasilibc_printscan_no_long_double) +static int fmt_fp(FILE *f, long_double y, int w, int p, int fl, int t) +#else +static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t) +#endif +{ + uint32_t big[(LDBL_MANT_DIG+28)/29 + 1 // mantissa expansion + + (LDBL_MAX_EXP+LDBL_MANT_DIG+28+8)/9]; // exponent expansion + uint32_t *a, *d, *r, *z; + int e2=0, e, i, j, l; + char buf[9+LDBL_MANT_DIG/4], *s; + const char *prefix="-0X+0X 0X-0x+0x 0x"; + int pl; + char ebuf0[3*sizeof(int)], *ebuf=&ebuf0[3*sizeof(int)], *estr; + + pl=1; + if (signbit(y)) { + y=-y; + } else if (fl & MARK_POS) { + prefix+=3; + } else if (fl & PAD_POS) { + prefix+=6; + } else prefix++, pl=0; + + if (!isfinite(y)) { + char *s = (t&32)?"inf":"INF"; + if (y!=y) s=(t&32)?"nan":"NAN"; + pad(f, ' ', w, 3+pl, fl&~ZERO_PAD); + out(f, prefix, pl); + out(f, s, 3); + pad(f, ' ', w, 3+pl, fl^LEFT_ADJ); + return MAX(w, 3+pl); + } + + y = frexpl(y, &e2) * 2; + if (y) e2--; + + if ((t|32)=='a') { +#if defined(__wasilibc_printscan_no_long_double) + long_double round = 8.0; +#else + long double round = 8.0; +#endif + int re; + + if (t&32) prefix += 9; + pl += 2; + + if (p<0 || p>=LDBL_MANT_DIG/4-1) re=0; + else re=LDBL_MANT_DIG/4-1-p; + + if (re) { + round *= 1<<(LDBL_MANT_DIG%4); + while (re--) round*=16; + if (*prefix=='-') { + y=-y; + y-=round; + y+=round; + y=-y; + } else { + y+=round; + y-=round; + } + } + + estr=fmt_u(e2<0 ? -e2 : e2, ebuf); + if (estr==ebuf) *--estr='0'; + *--estr = (e2<0 ? '-' : '+'); + *--estr = t+('p'-'a'); + + s=buf; + do { + int x=y; + *s++=xdigits[x]|(t&32); + y=16*(y-x); + if (s-buf==1 && (y||p>0||(fl&ALT_FORM))) *s++='.'; + } while (y); + + if (p > INT_MAX-2-(ebuf-estr)-pl) + return -1; + if (p && s-buf-2 < p) + l = (p+2) + (ebuf-estr); + else + l = (s-buf) + (ebuf-estr); + + pad(f, ' ', w, pl+l, fl); + out(f, prefix, pl); + pad(f, '0', w, pl+l, fl^ZERO_PAD); + out(f, buf, s-buf); + pad(f, '0', l-(ebuf-estr)-(s-buf), 0, 0); + out(f, estr, ebuf-estr); + pad(f, ' ', w, pl+l, fl^LEFT_ADJ); + return MAX(w, pl+l); + } + if (p<0) p=6; + + if (y) y *= 0x1p28, e2-=28; + + if (e2<0) a=r=z=big; + else a=r=z=big+sizeof(big)/sizeof(*big) - LDBL_MANT_DIG - 1; + + do { + *z = y; + y = 1000000000*(y-*z++); + } while (y); + + while (e2>0) { + uint32_t carry=0; + int sh=MIN(29,e2); + for (d=z-1; d>=a; d--) { + uint64_t x = ((uint64_t)*d<a && !z[-1]) z--; + e2-=sh; + } + while (e2<0) { + uint32_t carry=0, *b; + int sh=MIN(9,-e2), need=1+(p+LDBL_MANT_DIG/3U+8)/9; + for (d=a; d>sh) + carry; + carry = (1000000000>>sh) * rm; + } + if (!*a) a++; + if (carry) *z++ = carry; + /* Avoid (slow!) computation past requested precision */ + b = (t|32)=='f' ? r : a; + if (z-b > need) z = b+need; + e2+=sh; + } + + if (a=i; i*=10, e++); + else e=0; + + /* Perform rounding: j is precision after the radix (possibly neg) */ + j = p - ((t|32)!='f')*e - ((t|32)=='g' && p); + if (j < 9*(z-r-1)) { + uint32_t x; + /* We avoid C's broken division of negative numbers */ + d = r + 1 + ((j+9*LDBL_MAX_EXP)/9 - LDBL_MAX_EXP); + j += 9*LDBL_MAX_EXP; + j %= 9; + for (i=10, j++; j<9; i*=10, j++); + x = *d % i; + /* Are there any significant digits past j? */ + if (x || d+1!=z) { +#if defined(__wasilibc_printscan_no_long_double) + long_double round = 2/LDBL_EPSILON; + long_double small; +#else + long double round = 2/LDBL_EPSILON; + long double small; +#endif + if ((*d/i & 1) || (i==1000000000 && d>a && (d[-1]&1))) + round += 2; + if (x 999999999) { + *d--=0; + if (d=i; i*=10, e++); + } + } + if (z>d+1) z=d+1; + } + for (; z>a && !z[-1]; z--); + + if ((t|32)=='g') { + if (!p) p++; + if (p>e && e>=-4) { + t--; + p-=e+1; + } else { + t-=2; + p--; + } + if (!(fl&ALT_FORM)) { + /* Count trailing zeros in last place */ + if (z>a && z[-1]) for (i=10, j=0; z[-1]%i==0; i*=10, j++); + else j=9; + if ((t|32)=='f') + p = MIN(p,MAX(0,9*(z-r-1)-j)); + else + p = MIN(p,MAX(0,9*(z-r-1)+e-j)); + } + } + if (p > INT_MAX-1-(p || (fl&ALT_FORM))) + return -1; + l = 1 + p + (p || (fl&ALT_FORM)); + if ((t|32)=='f') { + if (e > INT_MAX-l) return -1; + if (e>0) l+=e; + } else { + estr=fmt_u(e<0 ? -e : e, ebuf); + while(ebuf-estr<2) *--estr='0'; + *--estr = (e<0 ? '-' : '+'); + *--estr = t; + if (ebuf-estr > INT_MAX-l) return -1; + l += ebuf-estr; + } + + if (l > INT_MAX-pl) return -1; + pad(f, ' ', w, pl+l, fl); + out(f, prefix, pl); + pad(f, '0', w, pl+l, fl^ZERO_PAD); + + if ((t|32)=='f') { + if (a>r) a=r; + for (d=a; d<=r; d++) { + char *s = fmt_u(*d, buf+9); + if (d!=a) while (s>buf) *--s='0'; + else if (s==buf+9) *--s='0'; + out(f, s, buf+9-s); + } + if (p || (fl&ALT_FORM)) out(f, ".", 1); + for (; d0; d++, p-=9) { + char *s = fmt_u(*d, buf+9); + while (s>buf) *--s='0'; + out(f, s, MIN(9,p)); + } + pad(f, '0', p+9, 9, 0); + } else { + if (z<=a) z=a+1; + for (d=a; d=0; d++) { + char *s = fmt_u(*d, buf+9); + if (s==buf+9) *--s='0'; + if (d!=a) while (s>buf) *--s='0'; + else { + out(f, s++, 1); + if (p>0||(fl&ALT_FORM)) out(f, ".", 1); + } + out(f, s, MIN(buf+9-s, p)); + p -= buf+9-s; + } + pad(f, '0', p+18, 18, 0); + out(f, estr, ebuf-estr); + } + + pad(f, ' ', w, pl+l, fl^LEFT_ADJ); + + return MAX(w, pl+l); +} +#endif + +static int getint(char **s) { + int i; + for (i=0; isdigit(**s); (*s)++) { + if (i > INT_MAX/10U || **s-'0' > INT_MAX-10*i) i = -1; + else i = 10*i + (**s-'0'); + } + return i; +} + +static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, int *nl_type) +{ + char *a, *z, *s=(char *)fmt; + unsigned l10n=0, fl; + int w, p, xp; + union arg arg; + int argpos; + unsigned st, ps; + int cnt=0, l=0; + size_t i; + char buf[sizeof(uintmax_t)*3+3+LDBL_MANT_DIG/4]; + const char *prefix; + int t, pl; + wchar_t wc[2], *ws; + char mb[4]; + + for (;;) { + /* This error is only specified for snprintf, but since it's + * unspecified for other forms, do the same. Stop immediately + * on overflow; otherwise %n could produce wrong results. */ + if (l > INT_MAX - cnt) goto overflow; + + /* Update output count, end loop when fmt is exhausted */ + cnt += l; + if (!*s) break; + + /* Handle literal text and %% format specifiers */ + for (a=s; *s && *s!='%'; s++); + for (z=s; s[0]=='%' && s[1]=='%'; z++, s+=2); + if (z-a > INT_MAX-cnt) goto overflow; + l = z-a; + if (f) out(f, a, l); + if (l) continue; + + if (isdigit(s[1]) && s[2]=='$') { + l10n=1; + argpos = s[1]-'0'; + s+=3; + } else { + argpos = -1; + s++; + } + + /* Read modifier flags */ + for (fl=0; (unsigned)*s-' '<32 && (FLAGMASK&(1U<<*s-' ')); s++) + fl |= 1U<<*s-' '; + + /* Read field width */ + if (*s=='*') { + if (isdigit(s[1]) && s[2]=='$') { + l10n=1; + nl_type[s[1]-'0'] = INT; + w = nl_arg[s[1]-'0'].i; + s+=3; + } else if (!l10n) { + w = f ? va_arg(*ap, int) : 0; + s++; + } else goto inval; + if (w<0) fl|=LEFT_ADJ, w=-w; + } else if ((w=getint(&s))<0) goto overflow; + + /* Read precision */ + if (*s=='.' && s[1]=='*') { + if (isdigit(s[2]) && s[3]=='$') { + nl_type[s[2]-'0'] = INT; + p = nl_arg[s[2]-'0'].i; + s+=4; + } else if (!l10n) { + p = f ? va_arg(*ap, int) : 0; + s+=2; + } else goto inval; + xp = (p>=0); + } else if (*s=='.') { + s++; + p = getint(&s); + xp = 1; + } else { + p = -1; + xp = 0; + } + + /* Format specifier state machine */ + st=0; + do { + if (OOB(*s)) goto inval; + ps=st; + st=states[st]S(*s++); + } while (st-1=0) goto inval; + } else { + if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos]; + else if (f) pop_arg(&arg, st, ap); + else return 0; + } + + if (!f) continue; + + z = buf + sizeof(buf); + prefix = "-+ 0X0x"; + pl = 0; + t = s[-1]; + + /* Transform ls,lc -> S,C */ + if (ps && (t&15)==3) t&=~32; + + /* - and 0 flags are mutually exclusive */ + if (fl & LEFT_ADJ) fl &= ~ZERO_PAD; + + switch(t) { + case 'n': + switch(ps) { + case BARE: *(int *)arg.p = cnt; break; + case LPRE: *(long *)arg.p = cnt; break; + case LLPRE: *(long long *)arg.p = cnt; break; + case HPRE: *(unsigned short *)arg.p = cnt; break; + case HHPRE: *(unsigned char *)arg.p = cnt; break; + case ZTPRE: *(size_t *)arg.p = cnt; break; + case JPRE: *(uintmax_t *)arg.p = cnt; break; + } + continue; + case 'p': + p = MAX(p, 2*sizeof(void*)); + t = 'x'; + fl |= ALT_FORM; + case 'x': case 'X': + a = fmt_x(arg.i, z, t&32); + if (arg.i && (fl & ALT_FORM)) prefix+=(t>>4), pl=2; + if (0) { + case 'o': + a = fmt_o(arg.i, z); + if ((fl&ALT_FORM) && pINTMAX_MAX) { + arg.i=-arg.i; + } else if (fl & MARK_POS) { + prefix++; + } else if (fl & PAD_POS) { + prefix+=2; + } else pl=0; + case 'u': + a = fmt_u(arg.i, z); + } + if (xp && p<0) goto overflow; + if (xp) fl &= ~ZERO_PAD; + if (!arg.i && !p) { + a=z; + break; + } + p = MAX(p, z-a + !arg.i); + break; + case 'c': + *(a=z-(p=1))=arg.i; + fl &= ~ZERO_PAD; + break; + case 'm': + if (1) a = strerror(errno); else + case 's': + a = arg.p ? arg.p : "(null)"; + z = a + strnlen(a, p<0 ? INT_MAX : p); + if (p<0 && *z) goto overflow; + p = z-a; + fl &= ~ZERO_PAD; + break; + case 'C': + wc[0] = arg.i; + wc[1] = 0; + arg.p = wc; + p = -1; + case 'S': + ws = arg.p; + for (i=l=0; i

=0 && l<=p-i; i+=l); + if (l<0) return -1; + if (i > INT_MAX) goto overflow; + p = i; + pad(f, ' ', w, p, fl); + ws = arg.p; + for (i=0; i<0U+p && *ws && i+(l=wctomb(mb, *ws++))<=p; i+=l) + out(f, mb, l); + pad(f, ' ', w, p, fl^LEFT_ADJ); + l = w>p ? w : p; + continue; +#if !defined(__wasilibc_printscan_no_floating_point) + case 'e': case 'f': case 'g': case 'a': + case 'E': case 'F': case 'G': case 'A': + if (xp && p<0) goto overflow; + l = fmt_fp(f, arg.f, w, p, fl, t); + if (l<0) goto overflow; + continue; +#endif + } + + if (p < z-a) p = z-a; + if (p > INT_MAX-pl) goto overflow; + if (w < pl+p) w = pl+p; + if (w > INT_MAX-cnt) goto overflow; + + pad(f, ' ', w, pl+p, fl); + out(f, prefix, pl); + pad(f, '0', w, pl+p, fl^ZERO_PAD); + pad(f, '0', p, z-a, 0); + out(f, a, z-a); + pad(f, ' ', w, pl+p, fl^LEFT_ADJ); + + l = w; + } + + if (f) return cnt; + if (!l10n) return 0; + + for (i=1; i<=NL_ARGMAX && nl_type[i]; i++) + pop_arg(nl_arg+i, nl_type[i], ap); + for (; i<=NL_ARGMAX && !nl_type[i]; i++); + if (i<=NL_ARGMAX) goto inval; + return 1; + +inval: + errno = EINVAL; + return -1; +overflow: + errno = EOVERFLOW; + return -1; +} + +int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap) +{ + va_list ap2; + int nl_type[NL_ARGMAX+1] = {0}; + union arg nl_arg[NL_ARGMAX+1]; + unsigned char internal_buf[80], *saved_buf = 0; + int olderr; + int ret; + + /* the copy allows passing va_list* even if va_list is an array */ + va_copy(ap2, ap); + if (printf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) { + va_end(ap2); + return -1; + } + + FLOCK(f); + olderr = f->flags & F_ERR; + if (f->mode < 1) f->flags &= ~F_ERR; + if (!f->buf_size) { + saved_buf = f->buf; + f->buf = internal_buf; + f->buf_size = sizeof internal_buf; + f->wpos = f->wbase = f->wend = 0; + } + if (!f->wend && __towrite(f)) ret = -1; + else ret = printf_core(f, fmt, &ap2, nl_arg, nl_type); + if (saved_buf) { + f->write(f, 0, 0); + if (!f->wpos) ret = -1; + f->buf = saved_buf; + f->buf_size = 0; + f->wpos = f->wbase = f->wend = 0; + } + if (f->flags & F_ERR) ret = -1; + f->flags |= olderr; + FUNLOCK(f); + va_end(ap2); + return ret; +} diff --git a/src/orca-libc/src/stdio/vfscanf.c b/src/orca-libc/src/stdio/vfscanf.c new file mode 100644 index 00000000..4ad1f529 --- /dev/null +++ b/src/orca-libc/src/stdio/vfscanf.c @@ -0,0 +1,448 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stdio_impl.h" +#include "shgetc.h" +#include "intscan.h" +#include "floatscan.h" + +#define SIZE_hh -2 +#define SIZE_h -1 +#define SIZE_def 0 +#define SIZE_l 1 +#define SIZE_L 2 +#define SIZE_ll 3 + +static void store_int(void* dest, int size, unsigned long long i) +{ + if(!dest) + return; + switch(size) + { + case SIZE_hh: + *(char*)dest = i; + break; + case SIZE_h: + *(short*)dest = i; + break; + case SIZE_def: + *(int*)dest = i; + break; + case SIZE_l: + *(long*)dest = i; + break; + case SIZE_ll: + *(long long*)dest = i; + break; + } +} + +static void* arg_n(va_list ap, unsigned int n) +{ + void* p; + unsigned int i; + va_list ap2; + va_copy(ap2, ap); + for(i = n; i > 1; i--) + va_arg(ap2, void*); + p = va_arg(ap2, void*); + va_end(ap2); + return p; +} + +int vfscanf(FILE* restrict f, const char* restrict fmt, va_list ap) +{ + int width; + int size; + int alloc = 0; + int base; + const unsigned char* p; + int c, t; + char* s; + wchar_t* wcs; + mbstate_t st; + void* dest = NULL; + int invert; + int matches = 0; + unsigned long long x; + + long double y; + + off_t pos = 0; + unsigned char scanset[257]; + size_t i, k; + wchar_t wc; + + FLOCK(f); + + if(!f->rpos) + __toread(f); + if(!f->rpos) + goto input_fail; + + for(p = (const unsigned char*)fmt; *p; p++) + { + + alloc = 0; + + if(isspace(*p)) + { + while(isspace(p[1])) + p++; + shlim(f, 0); + while(isspace(shgetc(f))) + ; + shunget(f); + pos += shcnt(f); + continue; + } + if(*p != '%' || p[1] == '%') + { + shlim(f, 0); + if(*p == '%') + { + p++; + while(isspace((c = shgetc(f)))) + ; + } + else + { + c = shgetc(f); + } + if(c != *p) + { + shunget(f); + if(c < 0) + goto input_fail; + goto match_fail; + } + pos += shcnt(f); + continue; + } + + p++; + if(*p == '*') + { + dest = 0; + p++; + } + else if(isdigit(*p) && p[1] == '$') + { + dest = arg_n(ap, *p - '0'); + p += 2; + } + else + { + dest = va_arg(ap, void*); + } + + for(width = 0; isdigit(*p); p++) + { + width = 10 * width + *p - '0'; + } + + if(*p == 'm') + { + wcs = 0; + s = 0; + alloc = !!dest; + p++; + } + else + { + alloc = 0; + } + + size = SIZE_def; + switch(*p++) + { + case 'h': + if(*p == 'h') + p++, size = SIZE_hh; + else + size = SIZE_h; + break; + case 'l': + if(*p == 'l') + p++, size = SIZE_ll; + else + size = SIZE_l; + break; + case 'j': + size = SIZE_ll; + break; + case 'z': + case 't': + size = SIZE_l; + break; + case 'L': + size = SIZE_L; + break; + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'a': + case 'e': + case 'f': + case 'g': + case 'A': + case 'E': + case 'F': + case 'G': + case 'X': + case 's': + case 'c': + case '[': + case 'S': + case 'C': + case 'p': + case 'n': + p--; + break; + default: + goto fmt_fail; + } + + t = *p; + + /* C or S */ + if((t & 0x2f) == 3) + { + t |= 32; + size = SIZE_l; + } + + switch(t) + { + case 'c': + if(width < 1) + width = 1; + case '[': + break; + case 'n': + store_int(dest, size, pos); + /* do not increment match count, etc! */ + continue; + default: + shlim(f, 0); + while(isspace(shgetc(f))) + ; + shunget(f); + pos += shcnt(f); + } + + shlim(f, width); + if(shgetc(f) < 0) + goto input_fail; + shunget(f); + + switch(t) + { + case 's': + case 'c': + case '[': + if(t == 'c' || t == 's') + { + memset(scanset, -1, sizeof scanset); + scanset[0] = 0; + if(t == 's') + { + scanset[1 + '\t'] = 0; + scanset[1 + '\n'] = 0; + scanset[1 + '\v'] = 0; + scanset[1 + '\f'] = 0; + scanset[1 + '\r'] = 0; + scanset[1 + ' '] = 0; + } + } + else + { + if(*++p == '^') + p++, invert = 1; + else + invert = 0; + memset(scanset, invert, sizeof scanset); + scanset[0] = 0; + if(*p == '-') + p++, scanset[1 + '-'] = 1 - invert; + else if(*p == ']') + p++, scanset[1 + ']'] = 1 - invert; + for(; *p != ']'; p++) + { + if(!*p) + goto fmt_fail; + if(*p == '-' && p[1] && p[1] != ']') + for(c = p++ [-1]; c < *p; c++) + scanset[1 + c] = 1 - invert; + scanset[1 + *p] = 1 - invert; + } + } + wcs = 0; + s = 0; + i = 0; + k = t == 'c' ? width + 1U : 31; + if(size == SIZE_l) + { + if(alloc) + { + wcs = malloc(k * sizeof(wchar_t)); + if(!wcs) + goto alloc_fail; + } + else + { + wcs = dest; + } + st = (mbstate_t){ 0 }; + while(scanset[(c = shgetc(f)) + 1]) + { + switch(mbrtowc(&wc, &(char){ c }, 1, &st)) + { + case -1: + goto input_fail; + case -2: + continue; + } + if(wcs) + wcs[i++] = wc; + if(alloc && i == k) + { + k += k + 1; + wchar_t* tmp = realloc(wcs, k * sizeof(wchar_t)); + if(!tmp) + goto alloc_fail; + wcs = tmp; + } + } + if(!mbsinit(&st)) + goto input_fail; + } + else if(alloc) + { + s = malloc(k); + if(!s) + goto alloc_fail; + while(scanset[(c = shgetc(f)) + 1]) + { + s[i++] = c; + if(i == k) + { + k += k + 1; + char* tmp = realloc(s, k); + if(!tmp) + goto alloc_fail; + s = tmp; + } + } + } + else if((s = dest)) + { + while(scanset[(c = shgetc(f)) + 1]) + s[i++] = c; + } + else + { + while(scanset[(c = shgetc(f)) + 1]) + ; + } + shunget(f); + if(!shcnt(f)) + goto match_fail; + if(t == 'c' && shcnt(f) != width) + goto match_fail; + if(alloc) + { + if(size == SIZE_l) + *(wchar_t**)dest = wcs; + else + *(char**)dest = s; + } + if(t != 'c') + { + if(wcs) + wcs[i] = 0; + if(s) + s[i] = 0; + } + break; + case 'p': + case 'X': + case 'x': + base = 16; + goto int_common; + case 'o': + base = 8; + goto int_common; + case 'd': + case 'u': + base = 10; + goto int_common; + case 'i': + base = 0; + int_common: + x = __intscan(f, base, 0, ULLONG_MAX); + if(!shcnt(f)) + goto match_fail; + if(t == 'p' && dest) + *(void**)dest = (void*)(uintptr_t)x; + else + store_int(dest, size, x); + break; + case 'a': + case 'A': + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + y = __floatscan(f, size, 0); + if(!shcnt(f)) + goto match_fail; + if(dest) + switch(size) + { + case SIZE_def: + *(float*)dest = y; + break; + case SIZE_l: + *(double*)dest = y; + break; + case SIZE_L: + *(long double*)dest = y; + break; + } + break; + } + + pos += shcnt(f); + if(dest) + matches++; + } + if(0) + { + fmt_fail: + alloc_fail: + input_fail: + if(!matches) + matches--; + match_fail: + if(alloc) + { + free(s); + free(wcs); + } + } + FUNLOCK(f); + return matches; +} + +weak_alias(vfscanf, __isoc99_vfscanf); diff --git a/src/orca-libc/src/stdio/vscanf.c b/src/orca-libc/src/stdio/vscanf.c new file mode 100644 index 00000000..9d46ab09 --- /dev/null +++ b/src/orca-libc/src/stdio/vscanf.c @@ -0,0 +1,9 @@ +#include +#include + +int vscanf(const char *restrict fmt, va_list ap) +{ + return vfscanf(stdin, fmt, ap); +} + +weak_alias(vscanf,__isoc99_vscanf); diff --git a/src/orca-libc/src/stdio/vsnprintf.c b/src/orca-libc/src/stdio/vsnprintf.c new file mode 100644 index 00000000..08989d68 --- /dev/null +++ b/src/orca-libc/src/stdio/vsnprintf.c @@ -0,0 +1,57 @@ +#include "stdio_impl.h" +#include +#include +#include +#include + +struct cookie { + char *s; + size_t n; +}; + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +static size_t sn_write(FILE *f, const unsigned char *s, size_t l) +{ + struct cookie *c = f->cookie; + size_t k = MIN(c->n, f->wpos - f->wbase); + if (k) { + memcpy(c->s, f->wbase, k); + c->s += k; + c->n -= k; + } + k = MIN(c->n, l); + if (k) { + memcpy(c->s, s, k); + c->s += k; + c->n -= k; + } + *c->s = 0; + f->wpos = f->wbase = f->buf; + /* pretend to succeed, even if we discarded extra data */ + return l; +} + +int vsnprintf(char *restrict s, size_t n, const char *restrict fmt, va_list ap) +{ + unsigned char buf[1]; + char dummy[1]; + struct cookie c = { .s = n ? s : dummy, .n = n ? n-1 : 0 }; + FILE f = { + .lbf = EOF, + .write = sn_write, +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) + .lock = -1, +#endif + .buf = buf, + .cookie = &c, + }; + + if (n > INT_MAX) { + errno = EOVERFLOW; + return -1; + } + + *c.s = 0; + return vfprintf(&f, fmt, ap); +} diff --git a/src/orca-libc/src/stdio/vsprintf.c b/src/orca-libc/src/stdio/vsprintf.c new file mode 100644 index 00000000..c57349d4 --- /dev/null +++ b/src/orca-libc/src/stdio/vsprintf.c @@ -0,0 +1,7 @@ +#include +#include + +int vsprintf(char *restrict s, const char *restrict fmt, va_list ap) +{ + return vsnprintf(s, INT_MAX, fmt, ap); +} diff --git a/src/orca-libc/src/stdio/vsscanf.c b/src/orca-libc/src/stdio/vsscanf.c new file mode 100644 index 00000000..0e5b4826 --- /dev/null +++ b/src/orca-libc/src/stdio/vsscanf.c @@ -0,0 +1,31 @@ +#include "stdio_impl.h" +#include + +static size_t string_read(FILE *f, unsigned char *buf, size_t len) +{ + char *src = f->cookie; + size_t k = len+256; + char *end = memchr(src, 0, k); + if (end) k = end-src; + if (k < len) len = k; + memcpy(buf, src, len); + f->rpos = (void *)(src+len); + f->rend = (void *)(src+k); + f->cookie = src+k; + return len; +} + +int vsscanf(const char *restrict s, const char *restrict fmt, va_list ap) +{ + FILE f = { + .buf = (void *)s, .cookie = (void *)s, +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) + .read = string_read, .lock = -1 +#else + .read = string_read +#endif + }; + return vfscanf(&f, fmt, ap); +} + +weak_alias(vsscanf,__isoc99_vsscanf); diff --git a/src/libc-shim/src/abs.c b/src/orca-libc/src/stdlib/abs.c similarity index 59% rename from src/libc-shim/src/abs.c rename to src/orca-libc/src/stdlib/abs.c index b6a294f0..e721fdc2 100644 --- a/src/libc-shim/src/abs.c +++ b/src/orca-libc/src/stdlib/abs.c @@ -2,5 +2,5 @@ int abs(int a) { - return a > 0 ? a : -a; + return a>0 ? a : -a; } diff --git a/src/orca-libc/src/stdlib/atof.c b/src/orca-libc/src/stdlib/atof.c new file mode 100644 index 00000000..f7fcd826 --- /dev/null +++ b/src/orca-libc/src/stdlib/atof.c @@ -0,0 +1,6 @@ +#include + +double atof(const char *s) +{ + return strtod(s, 0); +} diff --git a/src/orca-libc/src/stdlib/atoi.c b/src/orca-libc/src/stdlib/atoi.c new file mode 100644 index 00000000..9baca7b8 --- /dev/null +++ b/src/orca-libc/src/stdlib/atoi.c @@ -0,0 +1,16 @@ +#include +#include + +int atoi(const char *s) +{ + int n=0, neg=0; + while (isspace(*s)) s++; + switch (*s) { + case '-': neg=1; + case '+': s++; + } + /* Compute n as a negative number to avoid overflow on INT_MIN */ + while (isdigit(*s)) + n = 10*n - (*s++ - '0'); + return neg ? n : -n; +} diff --git a/src/orca-libc/src/stdlib/atol.c b/src/orca-libc/src/stdlib/atol.c new file mode 100644 index 00000000..140ea3ea --- /dev/null +++ b/src/orca-libc/src/stdlib/atol.c @@ -0,0 +1,17 @@ +#include +#include + +long atol(const char *s) +{ + long n=0; + int neg=0; + while (isspace(*s)) s++; + switch (*s) { + case '-': neg=1; + case '+': s++; + } + /* Compute n as a negative number to avoid overflow on LONG_MIN */ + while (isdigit(*s)) + n = 10*n - (*s++ - '0'); + return neg ? n : -n; +} diff --git a/src/orca-libc/src/stdlib/atoll.c b/src/orca-libc/src/stdlib/atoll.c new file mode 100644 index 00000000..b6930489 --- /dev/null +++ b/src/orca-libc/src/stdlib/atoll.c @@ -0,0 +1,17 @@ +#include +#include + +long long atoll(const char *s) +{ + long long n=0; + int neg=0; + while (isspace(*s)) s++; + switch (*s) { + case '-': neg=1; + case '+': s++; + } + /* Compute n as a negative number to avoid overflow on LLONG_MIN */ + while (isdigit(*s)) + n = 10*n - (*s++ - '0'); + return neg ? n : -n; +} diff --git a/src/orca-libc/src/stdlib/bsearch.c b/src/orca-libc/src/stdlib/bsearch.c new file mode 100644 index 00000000..fe050ea3 --- /dev/null +++ b/src/orca-libc/src/stdlib/bsearch.c @@ -0,0 +1,20 @@ +#include + +void *bsearch(const void *key, const void *base, size_t nel, size_t width, int (*cmp)(const void *, const void *)) +{ + void *try; + int sign; + while (nel > 0) { + try = (char *)base + width*(nel/2); + sign = cmp(key, try); + if (sign < 0) { + nel /= 2; + } else if (sign > 0) { + base = (char *)try + width; + nel -= nel/2+1; + } else { + return try; + } + } + return NULL; +} diff --git a/src/orca-libc/src/stdlib/div.c b/src/orca-libc/src/stdlib/div.c new file mode 100644 index 00000000..e42c1f14 --- /dev/null +++ b/src/orca-libc/src/stdlib/div.c @@ -0,0 +1,6 @@ +#include + +div_t div(int num, int den) +{ + return (div_t){ num/den, num%den }; +} diff --git a/src/orca-libc/src/stdlib/imaxabs.c b/src/orca-libc/src/stdlib/imaxabs.c new file mode 100644 index 00000000..81001819 --- /dev/null +++ b/src/orca-libc/src/stdlib/imaxabs.c @@ -0,0 +1,6 @@ +#include + +intmax_t imaxabs(intmax_t a) +{ + return a>0 ? a : -a; +} diff --git a/src/orca-libc/src/stdlib/imaxdiv.c b/src/orca-libc/src/stdlib/imaxdiv.c new file mode 100644 index 00000000..b2ce821f --- /dev/null +++ b/src/orca-libc/src/stdlib/imaxdiv.c @@ -0,0 +1,6 @@ +#include + +imaxdiv_t imaxdiv(intmax_t num, intmax_t den) +{ + return (imaxdiv_t){ num/den, num%den }; +} diff --git a/src/orca-libc/src/stdlib/labs.c b/src/orca-libc/src/stdlib/labs.c new file mode 100644 index 00000000..83ddb147 --- /dev/null +++ b/src/orca-libc/src/stdlib/labs.c @@ -0,0 +1,6 @@ +#include + +long labs(long a) +{ + return a>0 ? a : -a; +} diff --git a/src/orca-libc/src/stdlib/ldiv.c b/src/orca-libc/src/stdlib/ldiv.c new file mode 100644 index 00000000..36eb960b --- /dev/null +++ b/src/orca-libc/src/stdlib/ldiv.c @@ -0,0 +1,6 @@ +#include + +ldiv_t ldiv(long num, long den) +{ + return (ldiv_t){ num/den, num%den }; +} diff --git a/src/orca-libc/src/stdlib/llabs.c b/src/orca-libc/src/stdlib/llabs.c new file mode 100644 index 00000000..9dfaf5cf --- /dev/null +++ b/src/orca-libc/src/stdlib/llabs.c @@ -0,0 +1,6 @@ +#include + +long long llabs(long long a) +{ + return a>0 ? a : -a; +} diff --git a/src/orca-libc/src/stdlib/lldiv.c b/src/orca-libc/src/stdlib/lldiv.c new file mode 100644 index 00000000..7aaf7a0e --- /dev/null +++ b/src/orca-libc/src/stdlib/lldiv.c @@ -0,0 +1,6 @@ +#include + +lldiv_t lldiv(long long num, long long den) +{ + return (lldiv_t){ num/den, num%den }; +} diff --git a/src/orca-libc/src/stdlib/qsort.c b/src/orca-libc/src/stdlib/qsort.c new file mode 100644 index 00000000..314ddc29 --- /dev/null +++ b/src/orca-libc/src/stdlib/qsort.c @@ -0,0 +1,221 @@ +/* Copyright (C) 2011 by Valentin Ochs + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/* Minor changes by Rich Felker for integration in musl, 2011-04-27. */ + +/* Smoothsort, an adaptive variant of Heapsort. Memory usage: O(1). + Run time: Worst case O(n log n), close to O(n) in the mostly-sorted case. */ + +#define _BSD_SOURCE +#include +#include +#include + +#include "atomic.h" +#define ntz(x) a_ctz_l((x)) + +typedef int (*cmpfun)(const void *, const void *, void *); + +static inline int pntz(size_t p[2]) { + int r = ntz(p[0] - 1); + if(r != 0 || (r = 8*sizeof(size_t) + ntz(p[1])) != 8*sizeof(size_t)) { + return r; + } + return 0; +} + +static void cycle(size_t width, unsigned char* ar[], int n) +{ + unsigned char tmp[256]; + size_t l; + int i; + + if(n < 2) { + return; + } + + ar[n] = tmp; + while(width) { + l = sizeof(tmp) < width ? sizeof(tmp) : width; + memcpy(ar[n], ar[0], l); + for(i = 0; i < n; i++) { + memcpy(ar[i], ar[i + 1], l); + ar[i] += l; + } + width -= l; + } +} + +/* shl() and shr() need n > 0 */ +static inline void shl(size_t p[2], int n) +{ + if(n >= 8 * sizeof(size_t)) { + n -= 8 * sizeof(size_t); + p[1] = p[0]; + p[0] = 0; + } + p[1] <<= n; + p[1] |= p[0] >> (sizeof(size_t) * 8 - n); + p[0] <<= n; +} + +static inline void shr(size_t p[2], int n) +{ + if(n >= 8 * sizeof(size_t)) { + n -= 8 * sizeof(size_t); + p[0] = p[1]; + p[1] = 0; + } + p[0] >>= n; + p[0] |= p[1] << (sizeof(size_t) * 8 - n); + p[1] >>= n; +} + +static void sift(unsigned char *head, size_t width, cmpfun cmp, void *arg, int pshift, size_t lp[]) +{ + unsigned char *rt, *lf; + unsigned char *ar[14 * sizeof(size_t) + 1]; + int i = 1; + + ar[0] = head; + while(pshift > 1) { + rt = head - width; + lf = head - width - lp[pshift - 2]; + + if(cmp(ar[0], lf, arg) >= 0 && cmp(ar[0], rt, arg) >= 0) { + break; + } + if(cmp(lf, rt, arg) >= 0) { + ar[i++] = lf; + head = lf; + pshift -= 1; + } else { + ar[i++] = rt; + head = rt; + pshift -= 2; + } + } + cycle(width, ar, i); +} + +static void trinkle(unsigned char *head, size_t width, cmpfun cmp, void *arg, size_t pp[2], int pshift, int trusty, size_t lp[]) +{ + unsigned char *stepson, + *rt, *lf; + size_t p[2]; + unsigned char *ar[14 * sizeof(size_t) + 1]; + int i = 1; + int trail; + + p[0] = pp[0]; + p[1] = pp[1]; + + ar[0] = head; + while(p[0] != 1 || p[1] != 0) { + stepson = head - lp[pshift]; + if(cmp(stepson, ar[0], arg) <= 0) { + break; + } + if(!trusty && pshift > 1) { + rt = head - width; + lf = head - width - lp[pshift - 2]; + if(cmp(rt, stepson, arg) >= 0 || cmp(lf, stepson, arg) >= 0) { + break; + } + } + + ar[i++] = stepson; + head = stepson; + trail = pntz(p); + shr(p, trail); + pshift += trail; + trusty = 0; + } + if(!trusty) { + cycle(width, ar, i); + sift(head, width, cmp, arg, pshift, lp); + } +} + +void __qsort_r(void *base, size_t nel, size_t width, cmpfun cmp, void *arg) +{ + size_t lp[12*sizeof(size_t)]; + size_t i, size = width * nel; + unsigned char *head, *high; + size_t p[2] = {1, 0}; + int pshift = 1; + int trail; + + if (!size) return; + + head = base; + high = head + size - width; + + /* Precompute Leonardo numbers, scaled by element width */ + for(lp[0]=lp[1]=width, i=2; (lp[i]=lp[i-2]+lp[i-1]+width) < size; i++); + + while(head < high) { + if((p[0] & 3) == 3) { + sift(head, width, cmp, arg, pshift, lp); + shr(p, 2); + pshift += 2; + } else { + if(lp[pshift - 1] >= high - head) { + trinkle(head, width, cmp, arg, p, pshift, 0, lp); + } else { + sift(head, width, cmp, arg, pshift, lp); + } + + if(pshift == 1) { + shl(p, 1); + pshift = 0; + } else { + shl(p, pshift - 1); + pshift = 1; + } + } + + p[0] |= 1; + head += width; + } + + trinkle(head, width, cmp, arg, p, pshift, 0, lp); + + while(pshift != 1 || p[0] != 1 || p[1] != 0) { + if(pshift <= 1) { + trail = pntz(p); + shr(p, trail); + pshift += trail; + } else { + shl(p, 2); + pshift -= 2; + p[0] ^= 7; + shr(p, 1); + trinkle(head - lp[pshift] - width, width, cmp, arg, p, pshift + 1, 1, lp); + shl(p, 1); + p[0] |= 1; + trinkle(head - width, width, cmp, arg, p, pshift, 1, lp); + } + head -= width; + } +} + +weak_alias(__qsort_r, qsort_r); diff --git a/src/orca-libc/src/stdlib/qsort_nr.c b/src/orca-libc/src/stdlib/qsort_nr.c new file mode 100644 index 00000000..d40b5825 --- /dev/null +++ b/src/orca-libc/src/stdlib/qsort_nr.c @@ -0,0 +1,17 @@ +#define _BSD_SOURCE +#include + +typedef int (*cmpfun)(const void *, const void *); +typedef int (*cmpfun_r)(const void *v1, const void *v2, void *cmp); + +static int wrapper_cmp(const void *v1, const void *v2, void *cmp) +{ + return ((cmpfun)cmp)(v1, v2); +} + +void __qsort_r(void *base, size_t nel, size_t width, cmpfun_r cmp, void *arg); + +void qsort(void *base, size_t nel, size_t width, cmpfun cmp) +{ + __qsort_r(base, nel, width, wrapper_cmp, cmp); +} diff --git a/src/orca-libc/src/stdlib/strtod.c b/src/orca-libc/src/stdlib/strtod.c new file mode 100644 index 00000000..39b9daad --- /dev/null +++ b/src/orca-libc/src/stdlib/strtod.c @@ -0,0 +1,30 @@ +#include +#include "shgetc.h" +#include "floatscan.h" +#include "stdio_impl.h" + +static long double strtox(const char *s, char **p, int prec) +{ + FILE f; + sh_fromstring(&f, s); + shlim(&f, 0); + long double y = __floatscan(&f, prec, 1); + off_t cnt = shcnt(&f); + if (p) *p = cnt ? (char *)s + cnt : (char *)s; + return y; +} + +float strtof(const char *restrict s, char **restrict p) +{ + return strtox(s, p, 0); +} + +double strtod(const char *restrict s, char **restrict p) +{ + return strtox(s, p, 1); +} + +long double strtold(const char *restrict s, char **restrict p) +{ + return strtox(s, p, 2); +} diff --git a/src/orca-libc/src/stdlib/strtol.c b/src/orca-libc/src/stdlib/strtol.c new file mode 100644 index 00000000..bfefea69 --- /dev/null +++ b/src/orca-libc/src/stdlib/strtol.c @@ -0,0 +1,56 @@ +#include "stdio_impl.h" +#include "intscan.h" +#include "shgetc.h" +#include +#include +#include + +static unsigned long long strtox(const char *s, char **p, int base, unsigned long long lim) +{ + FILE f; + sh_fromstring(&f, s); + shlim(&f, 0); + unsigned long long y = __intscan(&f, base, 1, lim); + if (p) { + size_t cnt = shcnt(&f); + *p = (char *)s + cnt; + } + return y; +} + +unsigned long long strtoull(const char *restrict s, char **restrict p, int base) +{ + return strtox(s, p, base, ULLONG_MAX); +} + +long long strtoll(const char *restrict s, char **restrict p, int base) +{ + return strtox(s, p, base, LLONG_MIN); +} + +unsigned long strtoul(const char *restrict s, char **restrict p, int base) +{ + return strtox(s, p, base, ULONG_MAX); +} + +long strtol(const char *restrict s, char **restrict p, int base) +{ + return strtox(s, p, base, 0UL+LONG_MIN); +} + +intmax_t strtoimax(const char *restrict s, char **restrict p, int base) +{ + return strtoll(s, p, base); +} + +uintmax_t strtoumax(const char *restrict s, char **restrict p, int base) +{ + return strtoull(s, p, base); +} + +weak_alias(strtol, __strtol_internal); +weak_alias(strtoul, __strtoul_internal); +weak_alias(strtoll, __strtoll_internal); +weak_alias(strtoull, __strtoull_internal); +weak_alias(strtoimax, __strtoimax_internal); +weak_alias(strtoumax, __strtoumax_internal); diff --git a/src/orca-libc/src/stdlib/wcstod.c b/src/orca-libc/src/stdlib/wcstod.c new file mode 100644 index 00000000..e5c24b27 --- /dev/null +++ b/src/orca-libc/src/stdlib/wcstod.c @@ -0,0 +1,66 @@ +#include "shgetc.h" +#include "floatscan.h" +#include "stdio_impl.h" +#include +#include + +/* This read function heavily cheats. It knows: + * (1) len will always be 1 + * (2) non-ascii characters don't matter */ + +static size_t do_read(FILE *f, unsigned char *buf, size_t len) +{ + size_t i; + const wchar_t *wcs = f->cookie; + + if (!wcs[0]) wcs=L"@"; + for (i=0; ibuf_size && wcs[i]; i++) + f->buf[i] = wcs[i] < 128 ? wcs[i] : '@'; + f->rpos = f->buf; + f->rend = f->buf + i; + f->cookie = (void *)(wcs+i); + + if (i && len) { + *buf = *f->rpos++; + return 1; + } + return 0; +} + +static long double wcstox(const wchar_t *s, wchar_t **p, int prec) +{ + wchar_t *t = (wchar_t *)s; + unsigned char buf[64]; + FILE f = {0}; + f.flags = 0; + f.rpos = f.rend = f.buf = buf + 4; + f.buf_size = sizeof buf - 4; +#if defined(_REENTRANT) + f.lock = -1; +#endif + f.read = do_read; + while (iswspace(*t)) t++; + f.cookie = (void *)t; + shlim(&f, 0); + long double y = __floatscan(&f, prec, 1); + if (p) { + size_t cnt = shcnt(&f); + *p = cnt ? t + cnt : (wchar_t *)s; + } + return y; +} + +float wcstof(const wchar_t *restrict s, wchar_t **restrict p) +{ + return wcstox(s, p, 0); +} + +double wcstod(const wchar_t *restrict s, wchar_t **restrict p) +{ + return wcstox(s, p, 1); +} + +long double wcstold(const wchar_t *restrict s, wchar_t **restrict p) +{ + return wcstox(s, p, 2); +} diff --git a/src/orca-libc/src/stdlib/wcstol.c b/src/orca-libc/src/stdlib/wcstol.c new file mode 100644 index 00000000..3aefd06f --- /dev/null +++ b/src/orca-libc/src/stdlib/wcstol.c @@ -0,0 +1,83 @@ +#include "stdio_impl.h" +#include "intscan.h" +#include "shgetc.h" +#include +#include +#include +#include + +/* This read function heavily cheats. It knows: + * (1) len will always be 1 + * (2) non-ascii characters don't matter */ + +static size_t do_read(FILE *f, unsigned char *buf, size_t len) +{ + size_t i; + const wchar_t *wcs = f->cookie; + + if (!wcs[0]) wcs=L"@"; + for (i=0; ibuf_size && wcs[i]; i++) + f->buf[i] = wcs[i] < 128 ? wcs[i] : '@'; + f->rpos = f->buf; + f->rend = f->buf + i; + f->cookie = (void *)(wcs+i); + + if (i && len) { + *buf = *f->rpos++; + return 1; + } + return 0; +} + +static unsigned long long wcstox(const wchar_t *s, wchar_t **p, int base, unsigned long long lim) +{ + wchar_t *t = (wchar_t *)s; + unsigned char buf[64]; + FILE f = {0}; + f.flags = 0; + f.rpos = f.rend = f.buf = buf + 4; + f.buf_size = sizeof buf - 4; +#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) + f.lock = -1; +#endif + f.read = do_read; + while (iswspace(*t)) t++; + f.cookie = (void *)t; + shlim(&f, 0); + unsigned long long y = __intscan(&f, base, 1, lim); + if (p) { + size_t cnt = shcnt(&f); + *p = cnt ? t + cnt : (wchar_t *)s; + } + return y; +} + +unsigned long long wcstoull(const wchar_t *restrict s, wchar_t **restrict p, int base) +{ + return wcstox(s, p, base, ULLONG_MAX); +} + +long long wcstoll(const wchar_t *restrict s, wchar_t **restrict p, int base) +{ + return wcstox(s, p, base, LLONG_MIN); +} + +unsigned long wcstoul(const wchar_t *restrict s, wchar_t **restrict p, int base) +{ + return wcstox(s, p, base, ULONG_MAX); +} + +long wcstol(const wchar_t *restrict s, wchar_t **restrict p, int base) +{ + return wcstox(s, p, base, 0UL+LONG_MIN); +} + +intmax_t wcstoimax(const wchar_t *restrict s, wchar_t **restrict p, int base) +{ + return wcstoll(s, p, base); +} + +uintmax_t wcstoumax(const wchar_t *restrict s, wchar_t **restrict p, int base) +{ + return wcstoull(s, p, base); +} diff --git a/src/orca-libc/src/string/bcmp.c b/src/orca-libc/src/string/bcmp.c new file mode 100644 index 00000000..87c6007e --- /dev/null +++ b/src/orca-libc/src/string/bcmp.c @@ -0,0 +1,8 @@ +#define _BSD_SOURCE +#include +#include + +int bcmp(const void *s1, const void *s2, size_t n) +{ + return memcmp(s1, s2, n); +} diff --git a/src/orca-libc/src/string/bcopy.c b/src/orca-libc/src/string/bcopy.c new file mode 100644 index 00000000..a07129f5 --- /dev/null +++ b/src/orca-libc/src/string/bcopy.c @@ -0,0 +1,8 @@ +#define _BSD_SOURCE +#include +#include + +void bcopy(const void *s1, void *s2, size_t n) +{ + memmove(s2, s1, n); +} diff --git a/src/orca-libc/src/string/bzero.c b/src/orca-libc/src/string/bzero.c new file mode 100644 index 00000000..ba536b07 --- /dev/null +++ b/src/orca-libc/src/string/bzero.c @@ -0,0 +1,8 @@ +#define _BSD_SOURCE +#include +#include + +void bzero(void *s, size_t n) +{ + memset(s, 0, n); +} diff --git a/src/orca-libc/src/string/explicit_bzero.c b/src/orca-libc/src/string/explicit_bzero.c new file mode 100644 index 00000000..f2e12f23 --- /dev/null +++ b/src/orca-libc/src/string/explicit_bzero.c @@ -0,0 +1,8 @@ +#define _BSD_SOURCE +#include + +void explicit_bzero(void *d, size_t n) +{ + d = memset(d, 0, n); + __asm__ __volatile__ ("" : : "r"(d) : "memory"); +} diff --git a/src/orca-libc/src/string/index.c b/src/orca-libc/src/string/index.c new file mode 100644 index 00000000..252948f9 --- /dev/null +++ b/src/orca-libc/src/string/index.c @@ -0,0 +1,8 @@ +#define _BSD_SOURCE +#include +#include + +char *index(const char *s, int c) +{ + return strchr(s, c); +} diff --git a/src/orca-libc/src/string/memccpy.c b/src/orca-libc/src/string/memccpy.c new file mode 100644 index 00000000..3b0a3700 --- /dev/null +++ b/src/orca-libc/src/string/memccpy.c @@ -0,0 +1,34 @@ +#include +#include +#include + +#define ALIGN (sizeof(size_t)-1) +#define ONES ((size_t)-1/UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX/2+1)) +#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS) + +void *memccpy(void *restrict dest, const void *restrict src, int c, size_t n) +{ + unsigned char *d = dest; + const unsigned char *s = src; + + c = (unsigned char)c; +#ifdef __GNUC__ + typedef size_t __attribute__((__may_alias__)) word; + word *wd; + const word *ws; + if (((uintptr_t)s & ALIGN) == ((uintptr_t)d & ALIGN)) { + for (; ((uintptr_t)s & ALIGN) && n && (*d=*s)!=c; n--, s++, d++); + if ((uintptr_t)s & ALIGN) goto tail; + size_t k = ONES * c; + wd=(void *)d; ws=(const void *)s; + for (; n>=sizeof(size_t) && !HASZERO(*ws^k); + n-=sizeof(size_t), ws++, wd++) *wd = *ws; + d=(void *)wd; s=(const void *)ws; + } +#endif + for (; n && (*d=*s)!=c; n--, s++, d++); +tail: + if (n) return d+1; + return 0; +} diff --git a/src/orca-libc/src/string/memchr.c b/src/orca-libc/src/string/memchr.c new file mode 100644 index 00000000..65f0d789 --- /dev/null +++ b/src/orca-libc/src/string/memchr.c @@ -0,0 +1,27 @@ +#include +#include +#include + +#define SS (sizeof(size_t)) +#define ALIGN (sizeof(size_t)-1) +#define ONES ((size_t)-1/UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX/2+1)) +#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS) + +void *memchr(const void *src, int c, size_t n) +{ + const unsigned char *s = src; + c = (unsigned char)c; +#ifdef __GNUC__ + for (; ((uintptr_t)s & ALIGN) && n && *s != c; s++, n--); + if (n && *s != c) { + typedef size_t __attribute__((__may_alias__)) word; + const word *w; + size_t k = ONES * c; + for (w = (const void *)s; n>=SS && !HASZERO(*w^k); w++, n-=SS); + s = (const void *)w; + } +#endif + for (; n && *s != c; s++, n--); + return n ? (void *)s : 0; +} diff --git a/src/orca-libc/src/string/memcmp.c b/src/orca-libc/src/string/memcmp.c new file mode 100644 index 00000000..bdbce9f0 --- /dev/null +++ b/src/orca-libc/src/string/memcmp.c @@ -0,0 +1,8 @@ +#include + +int memcmp(const void *vl, const void *vr, size_t n) +{ + const unsigned char *l=vl, *r=vr; + for (; n && *l == *r; n--, l++, r++); + return n ? *l-*r : 0; +} diff --git a/src/orca-libc/src/string/memcpy.c b/src/orca-libc/src/string/memcpy.c new file mode 100644 index 00000000..3cc7e28f --- /dev/null +++ b/src/orca-libc/src/string/memcpy.c @@ -0,0 +1,128 @@ +#include +#include +#include + +void *memcpy(void *restrict dest, const void *restrict src, size_t n) +{ +#if defined(__wasm_bulk_memory__) + if (n > BULK_MEMORY_THRESHOLD) + return __builtin_memcpy(dest, src, n); +#endif + unsigned char *d = dest; + const unsigned char *s = src; + +#ifdef __GNUC__ + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define LS >> +#define RS << +#else +#define LS << +#define RS >> +#endif + + typedef uint32_t __attribute__((__may_alias__)) u32; + uint32_t w, x; + + for (; (uintptr_t)s % 4 && n; n--) *d++ = *s++; + + if ((uintptr_t)d % 4 == 0) { + for (; n>=16; s+=16, d+=16, n-=16) { + *(u32 *)(d+0) = *(u32 *)(s+0); + *(u32 *)(d+4) = *(u32 *)(s+4); + *(u32 *)(d+8) = *(u32 *)(s+8); + *(u32 *)(d+12) = *(u32 *)(s+12); + } + if (n&8) { + *(u32 *)(d+0) = *(u32 *)(s+0); + *(u32 *)(d+4) = *(u32 *)(s+4); + d += 8; s += 8; + } + if (n&4) { + *(u32 *)(d+0) = *(u32 *)(s+0); + d += 4; s += 4; + } + if (n&2) { + *d++ = *s++; *d++ = *s++; + } + if (n&1) { + *d = *s; + } + return dest; + } + + if (n >= 32) switch ((uintptr_t)d % 4) { + case 1: + w = *(u32 *)s; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + n -= 3; + for (; n>=17; s+=16, d+=16, n-=16) { + x = *(u32 *)(s+1); + *(u32 *)(d+0) = (w LS 24) | (x RS 8); + w = *(u32 *)(s+5); + *(u32 *)(d+4) = (x LS 24) | (w RS 8); + x = *(u32 *)(s+9); + *(u32 *)(d+8) = (w LS 24) | (x RS 8); + w = *(u32 *)(s+13); + *(u32 *)(d+12) = (x LS 24) | (w RS 8); + } + break; + case 2: + w = *(u32 *)s; + *d++ = *s++; + *d++ = *s++; + n -= 2; + for (; n>=18; s+=16, d+=16, n-=16) { + x = *(u32 *)(s+2); + *(u32 *)(d+0) = (w LS 16) | (x RS 16); + w = *(u32 *)(s+6); + *(u32 *)(d+4) = (x LS 16) | (w RS 16); + x = *(u32 *)(s+10); + *(u32 *)(d+8) = (w LS 16) | (x RS 16); + w = *(u32 *)(s+14); + *(u32 *)(d+12) = (x LS 16) | (w RS 16); + } + break; + case 3: + w = *(u32 *)s; + *d++ = *s++; + n -= 1; + for (; n>=19; s+=16, d+=16, n-=16) { + x = *(u32 *)(s+3); + *(u32 *)(d+0) = (w LS 8) | (x RS 24); + w = *(u32 *)(s+7); + *(u32 *)(d+4) = (x LS 8) | (w RS 24); + x = *(u32 *)(s+11); + *(u32 *)(d+8) = (w LS 8) | (x RS 24); + w = *(u32 *)(s+15); + *(u32 *)(d+12) = (x LS 8) | (w RS 24); + } + break; + } + if (n&16) { + *d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++; + *d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++; + *d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++; + *d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++; + } + if (n&8) { + *d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++; + *d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++; + } + if (n&4) { + *d++ = *s++; *d++ = *s++; *d++ = *s++; *d++ = *s++; + } + if (n&2) { + *d++ = *s++; *d++ = *s++; + } + if (n&1) { + *d = *s; + } + return dest; +#endif + + for (; n; n--) *d++ = *s++; + return dest; +} diff --git a/src/orca-libc/src/string/memmem.c b/src/orca-libc/src/string/memmem.c new file mode 100644 index 00000000..11eff86e --- /dev/null +++ b/src/orca-libc/src/string/memmem.c @@ -0,0 +1,149 @@ +#define _GNU_SOURCE +#include +#include + +static char *twobyte_memmem(const unsigned char *h, size_t k, const unsigned char *n) +{ + uint16_t nw = n[0]<<8 | n[1], hw = h[0]<<8 | h[1]; + for (h+=2, k-=2; k; k--, hw = hw<<8 | *h++) + if (hw == nw) return (char *)h-2; + return hw == nw ? (char *)h-2 : 0; +} + +static char *threebyte_memmem(const unsigned char *h, size_t k, const unsigned char *n) +{ + uint32_t nw = (uint32_t)n[0]<<24 | n[1]<<16 | n[2]<<8; + uint32_t hw = (uint32_t)h[0]<<24 | h[1]<<16 | h[2]<<8; + for (h+=3, k-=3; k; k--, hw = (hw|*h++)<<8) + if (hw == nw) return (char *)h-3; + return hw == nw ? (char *)h-3 : 0; +} + +static char *fourbyte_memmem(const unsigned char *h, size_t k, const unsigned char *n) +{ + uint32_t nw = (uint32_t)n[0]<<24 | n[1]<<16 | n[2]<<8 | n[3]; + uint32_t hw = (uint32_t)h[0]<<24 | h[1]<<16 | h[2]<<8 | h[3]; + for (h+=4, k-=4; k; k--, hw = hw<<8 | *h++) + if (hw == nw) return (char *)h-4; + return hw == nw ? (char *)h-4 : 0; +} + +#define MAX(a,b) ((a)>(b)?(a):(b)) +#define MIN(a,b) ((a)<(b)?(a):(b)) + +#define BITOP(a,b,op) \ + ((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a)))) + +static char *twoway_memmem(const unsigned char *h, const unsigned char *z, const unsigned char *n, size_t l) +{ + size_t i, ip, jp, k, p, ms, p0, mem, mem0; + size_t byteset[32 / sizeof(size_t)] = { 0 }; + size_t shift[256]; + + /* Computing length of needle and fill shift table */ + for (i=0; i n[jp+k]) { + jp += k; + k = 1; + p = jp - ip; + } else { + ip = jp++; + k = p = 1; + } + } + ms = ip; + p0 = p; + + /* And with the opposite comparison */ + ip = -1; jp = 0; k = p = 1; + while (jp+k ms+1) ms = ip; + else p = p0; + + /* Periodic needle? */ + if (memcmp(n, n+p, ms+1)) { + mem0 = 0; + p = MAX(ms, l-ms-1) + 1; + } else mem0 = l-p; + mem = 0; + + /* Search loop */ + for (;;) { + /* If remainder of haystack is shorter than needle, done */ + if (z-h < l) return 0; + + /* Check last byte first; advance by shift on mismatch */ + if (BITOP(byteset, h[l-1], &)) { + k = l-shift[h[l-1]]; + if (k) { + if (k < mem) k = mem; + h += k; + mem = 0; + continue; + } + } else { + h += l; + mem = 0; + continue; + } + + /* Compare right half */ + for (k=MAX(ms+1,mem); kmem && n[k-1] == h[k-1]; k--); + if (k <= mem) return (char *)h; + h += p; + mem = mem0; + } +} + +void *memmem(const void *h0, size_t k, const void *n0, size_t l) +{ + const unsigned char *h = h0, *n = n0; + + /* Return immediately on empty needle */ + if (!l) return (void *)h; + + /* Return immediately when needle is longer than haystack */ + if (k +#include + +#ifdef __GNUC__ +typedef __attribute__((__may_alias__)) size_t WT; +#define WS (sizeof(WT)) +#endif + +void *memmove(void *dest, const void *src, size_t n) +{ +#if defined(__wasm_bulk_memory__) + if (n > BULK_MEMORY_THRESHOLD) + return __builtin_memmove(dest, src, n); +#endif + char *d = dest; + const char *s = src; + + if (d==s) return d; + if ((uintptr_t)s-(uintptr_t)d-n <= -2*n) return memcpy(d, s, n); + + if (d=WS; n-=WS, d+=WS, s+=WS) *(WT *)d = *(WT *)s; + } +#endif + for (; n; n--) *d++ = *s++; + } else { +#ifdef __GNUC__ + if ((uintptr_t)s % WS == (uintptr_t)d % WS) { + while ((uintptr_t)(d+n) % WS) { + if (!n--) return dest; + d[n] = s[n]; + } + while (n>=WS) n-=WS, *(WT *)(d+n) = *(WT *)(s+n); + } +#endif + while (n) n--, d[n] = s[n]; + } + + return dest; +} diff --git a/src/orca-libc/src/string/mempcpy.c b/src/orca-libc/src/string/mempcpy.c new file mode 100644 index 00000000..a297985e --- /dev/null +++ b/src/orca-libc/src/string/mempcpy.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include + +void *mempcpy(void *dest, const void *src, size_t n) +{ + return (char *)memcpy(dest, src, n) + n; +} diff --git a/src/orca-libc/src/string/memrchr.c b/src/orca-libc/src/string/memrchr.c new file mode 100644 index 00000000..e51748b8 --- /dev/null +++ b/src/orca-libc/src/string/memrchr.c @@ -0,0 +1,11 @@ +#include + +void *__memrchr(const void *m, int c, size_t n) +{ + const unsigned char *s = m; + c = (unsigned char)c; + while (n--) if (s[n]==c) return (void *)(s+n); + return 0; +} + +weak_alias(__memrchr, memrchr); diff --git a/src/orca-libc/src/string/memset.c b/src/orca-libc/src/string/memset.c new file mode 100644 index 00000000..f64c9cf5 --- /dev/null +++ b/src/orca-libc/src/string/memset.c @@ -0,0 +1,94 @@ +#include +#include + +void *memset(void *dest, int c, size_t n) +{ +#if defined(__wasm_bulk_memory__) + if (n > BULK_MEMORY_THRESHOLD) + return __builtin_memset(dest, c, n); +#endif + unsigned char *s = dest; + size_t k; + + /* Fill head and tail with minimal branching. Each + * conditional ensures that all the subsequently used + * offsets are well-defined and in the dest region. */ + + if (!n) return dest; + s[0] = c; + s[n-1] = c; + if (n <= 2) return dest; + s[1] = c; + s[2] = c; + s[n-2] = c; + s[n-3] = c; + if (n <= 6) return dest; + s[3] = c; + s[n-4] = c; + if (n <= 8) return dest; + + /* Advance pointer to align it at a 4-byte boundary, + * and truncate n to a multiple of 4. The previous code + * already took care of any head/tail that get cut off + * by the alignment. */ + + k = -(uintptr_t)s & 3; + s += k; + n -= k; + n &= -4; + +#ifdef __GNUC__ + typedef uint32_t __attribute__((__may_alias__)) u32; + typedef uint64_t __attribute__((__may_alias__)) u64; + + u32 c32 = ((u32)-1)/255 * (unsigned char)c; + + /* In preparation to copy 32 bytes at a time, aligned on + * an 8-byte bounary, fill head/tail up to 28 bytes each. + * As in the initial byte-based head/tail fill, each + * conditional below ensures that the subsequent offsets + * are valid (e.g. !(n<=24) implies n>=28). */ + + *(u32 *)(s+0) = c32; + *(u32 *)(s+n-4) = c32; + if (n <= 8) return dest; + *(u32 *)(s+4) = c32; + *(u32 *)(s+8) = c32; + *(u32 *)(s+n-12) = c32; + *(u32 *)(s+n-8) = c32; + if (n <= 24) return dest; + *(u32 *)(s+12) = c32; + *(u32 *)(s+16) = c32; + *(u32 *)(s+20) = c32; + *(u32 *)(s+24) = c32; + *(u32 *)(s+n-28) = c32; + *(u32 *)(s+n-24) = c32; + *(u32 *)(s+n-20) = c32; + *(u32 *)(s+n-16) = c32; + + /* Align to a multiple of 8 so we can fill 64 bits at a time, + * and avoid writing the same bytes twice as much as is + * practical without introducing additional branching. */ + + k = 24 + ((uintptr_t)s & 4); + s += k; + n -= k; + + /* If this loop is reached, 28 tail bytes have already been + * filled, so any remainder when n drops below 32 can be + * safely ignored. */ + + u64 c64 = c32 | ((u64)c32 << 32); + for (; n >= 32; n-=32, s+=32) { + *(u64 *)(s+0) = c64; + *(u64 *)(s+8) = c64; + *(u64 *)(s+16) = c64; + *(u64 *)(s+24) = c64; + } +#else + /* Pure C fallback with no aliasing violations. */ + for (; n; n--, s++) *s = c; +#endif + + return dest; +} diff --git a/src/orca-libc/src/string/rindex.c b/src/orca-libc/src/string/rindex.c new file mode 100644 index 00000000..693c750b --- /dev/null +++ b/src/orca-libc/src/string/rindex.c @@ -0,0 +1,8 @@ +#define _BSD_SOURCE +#include +#include + +char *rindex(const char *s, int c) +{ + return strrchr(s, c); +} diff --git a/src/orca-libc/src/string/stpcpy.c b/src/orca-libc/src/string/stpcpy.c new file mode 100644 index 00000000..4db46a9e --- /dev/null +++ b/src/orca-libc/src/string/stpcpy.c @@ -0,0 +1,29 @@ +#include +#include +#include + +#define ALIGN (sizeof(size_t)) +#define ONES ((size_t)-1/UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX/2+1)) +#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS) + +char *__stpcpy(char *restrict d, const char *restrict s) +{ +#ifdef __GNUC__ + typedef size_t __attribute__((__may_alias__)) word; + word *wd; + const word *ws; + if ((uintptr_t)s % ALIGN == (uintptr_t)d % ALIGN) { + for (; (uintptr_t)s % ALIGN; s++, d++) + if (!(*d=*s)) return d; + wd=(void *)d; ws=(const void *)s; + for (; !HASZERO(*ws); *wd++ = *ws++); + d=(void *)wd; s=(const void *)ws; + } +#endif + for (; (*d=*s); s++, d++); + + return d; +} + +weak_alias(__stpcpy, stpcpy); diff --git a/src/orca-libc/src/string/stpncpy.c b/src/orca-libc/src/string/stpncpy.c new file mode 100644 index 00000000..f57fa6b7 --- /dev/null +++ b/src/orca-libc/src/string/stpncpy.c @@ -0,0 +1,32 @@ +#include +#include +#include + +#define ALIGN (sizeof(size_t)-1) +#define ONES ((size_t)-1/UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX/2+1)) +#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS) + +char *__stpncpy(char *restrict d, const char *restrict s, size_t n) +{ +#ifdef __GNUC__ + typedef size_t __attribute__((__may_alias__)) word; + word *wd; + const word *ws; + if (((uintptr_t)s & ALIGN) == ((uintptr_t)d & ALIGN)) { + for (; ((uintptr_t)s & ALIGN) && n && (*d=*s); n--, s++, d++); + if (!n || !*s) goto tail; + wd=(void *)d; ws=(const void *)s; + for (; n>=sizeof(size_t) && !HASZERO(*ws); + n-=sizeof(size_t), ws++, wd++) *wd = *ws; + d=(void *)wd; s=(const void *)ws; + } +#endif + for (; n && (*d=*s); n--, s++, d++); +tail: + memset(d, 0, n); + return d; +} + +weak_alias(__stpncpy, stpncpy); + diff --git a/src/orca-libc/src/string/strcasecmp.c b/src/orca-libc/src/string/strcasecmp.c new file mode 100644 index 00000000..02fd5f8c --- /dev/null +++ b/src/orca-libc/src/string/strcasecmp.c @@ -0,0 +1,9 @@ +#include +#include + +int strcasecmp(const char *_l, const char *_r) +{ + const unsigned char *l=(void *)_l, *r=(void *)_r; + for (; *l && *r && (*l == *r || tolower(*l) == tolower(*r)); l++, r++); + return tolower(*l) - tolower(*r); +} diff --git a/src/orca-libc/src/string/strcasestr.c b/src/orca-libc/src/string/strcasestr.c new file mode 100644 index 00000000..af109f36 --- /dev/null +++ b/src/orca-libc/src/string/strcasestr.c @@ -0,0 +1,9 @@ +#define _GNU_SOURCE +#include + +char *strcasestr(const char *h, const char *n) +{ + size_t l = strlen(n); + for (; *h; h++) if (!strncasecmp(h, n, l)) return (char *)h; + return 0; +} diff --git a/src/orca-libc/src/string/strcat.c b/src/orca-libc/src/string/strcat.c new file mode 100644 index 00000000..33f749b1 --- /dev/null +++ b/src/orca-libc/src/string/strcat.c @@ -0,0 +1,7 @@ +#include + +char *strcat(char *restrict dest, const char *restrict src) +{ + strcpy(dest + strlen(dest), src); + return dest; +} diff --git a/src/orca-libc/src/string/strchr.c b/src/orca-libc/src/string/strchr.c new file mode 100644 index 00000000..3dda2f33 --- /dev/null +++ b/src/orca-libc/src/string/strchr.c @@ -0,0 +1,9 @@ +#include + +char *__strchrnul(const char *s, int c); + +char *strchr(const char *s, int c) +{ + char *r = __strchrnul(s, c); + return *(unsigned char *)r == (unsigned char)c ? r : 0; +} diff --git a/src/orca-libc/src/string/strchrnul.c b/src/orca-libc/src/string/strchrnul.c new file mode 100644 index 00000000..39e2635b --- /dev/null +++ b/src/orca-libc/src/string/strchrnul.c @@ -0,0 +1,28 @@ +#include +#include +#include + +#define ALIGN (sizeof(size_t)) +#define ONES ((size_t)-1/UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX/2+1)) +#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS) + +char *__strchrnul(const char *s, int c) +{ + c = (unsigned char)c; + if (!c) return (char *)s + strlen(s); + +#ifdef __GNUC__ + typedef size_t __attribute__((__may_alias__)) word; + const word *w; + for (; (uintptr_t)s % ALIGN; s++) + if (!*s || *(unsigned char *)s == c) return (char *)s; + size_t k = ONES * c; + for (w = (void *)s; !HASZERO(*w) && !HASZERO(*w^k); w++); + s = (void *)w; +#endif + for (; *s && *(unsigned char *)s != c; s++); + return (char *)s; +} + +weak_alias(__strchrnul, strchrnul); diff --git a/src/orca-libc/src/string/strcmp.c b/src/orca-libc/src/string/strcmp.c new file mode 100644 index 00000000..808bd837 --- /dev/null +++ b/src/orca-libc/src/string/strcmp.c @@ -0,0 +1,7 @@ +#include + +int strcmp(const char *l, const char *r) +{ + for (; *l==*r && *l; l++, r++); + return *(unsigned char *)l - *(unsigned char *)r; +} diff --git a/src/orca-libc/src/string/strcpy.c b/src/orca-libc/src/string/strcpy.c new file mode 100644 index 00000000..6668a129 --- /dev/null +++ b/src/orca-libc/src/string/strcpy.c @@ -0,0 +1,7 @@ +#include + +char *strcpy(char *restrict dest, const char *restrict src) +{ + __stpcpy(dest, src); + return dest; +} diff --git a/src/orca-libc/src/string/strcspn.c b/src/orca-libc/src/string/strcspn.c new file mode 100644 index 00000000..a0c617bd --- /dev/null +++ b/src/orca-libc/src/string/strcspn.c @@ -0,0 +1,17 @@ +#include + +#define BITOP(a,b,op) \ + ((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a)))) + +size_t strcspn(const char *s, const char *c) +{ + const char *a = s; + size_t byteset[32/sizeof(size_t)]; + + if (!c[0] || !c[1]) return __strchrnul(s, *c)-a; + + memset(byteset, 0, sizeof byteset); + for (; *c && BITOP(byteset, *(unsigned char *)c, |=); c++); + for (; *s && !BITOP(byteset, *(unsigned char *)s, &); s++); + return s-a; +} diff --git a/src/orca-libc/src/string/strdup.c b/src/orca-libc/src/string/strdup.c new file mode 100644 index 00000000..d4c27449 --- /dev/null +++ b/src/orca-libc/src/string/strdup.c @@ -0,0 +1,10 @@ +#include +#include + +char *strdup(const char *s) +{ + size_t l = strlen(s); + char *d = malloc(l+1); + if (!d) return NULL; + return memcpy(d, s, l+1); +} diff --git a/src/orca-libc/src/string/strerror_r.c b/src/orca-libc/src/string/strerror_r.c new file mode 100644 index 00000000..1dc88bb1 --- /dev/null +++ b/src/orca-libc/src/string/strerror_r.c @@ -0,0 +1,19 @@ +#include +#include + +int strerror_r(int err, char *buf, size_t buflen) +{ + char *msg = strerror(err); + size_t l = strlen(msg); + if (l >= buflen) { + if (buflen) { + memcpy(buf, msg, buflen-1); + buf[buflen-1] = 0; + } + return ERANGE; + } + memcpy(buf, msg, l+1); + return 0; +} + +weak_alias(strerror_r, __xpg_strerror_r); diff --git a/src/orca-libc/src/string/strlcat.c b/src/orca-libc/src/string/strlcat.c new file mode 100644 index 00000000..ef81209e --- /dev/null +++ b/src/orca-libc/src/string/strlcat.c @@ -0,0 +1,9 @@ +#define _BSD_SOURCE +#include + +size_t strlcat(char *d, const char *s, size_t n) +{ + size_t l = strnlen(d, n); + if (l == n) return l + strlen(s); + return l + strlcpy(d+l, s, n-l); +} diff --git a/src/orca-libc/src/string/strlcpy.c b/src/orca-libc/src/string/strlcpy.c new file mode 100644 index 00000000..ffa0b0b0 --- /dev/null +++ b/src/orca-libc/src/string/strlcpy.c @@ -0,0 +1,34 @@ +#define _BSD_SOURCE +#include +#include +#include + +#define ALIGN (sizeof(size_t)-1) +#define ONES ((size_t)-1/UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX/2+1)) +#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS) + +size_t strlcpy(char *d, const char *s, size_t n) +{ + char *d0 = d; + size_t *wd; + + if (!n--) goto finish; +#ifdef __GNUC__ + typedef size_t __attribute__((__may_alias__)) word; + const word *ws; + if (((uintptr_t)s & ALIGN) == ((uintptr_t)d & ALIGN)) { + for (; ((uintptr_t)s & ALIGN) && n && (*d=*s); n--, s++, d++); + if (n && *s) { + wd=(void *)d; ws=(const void *)s; + for (; n>=sizeof(size_t) && !HASZERO(*ws); + n-=sizeof(size_t), ws++, wd++) *wd = *ws; + d=(void *)wd; s=(const void *)ws; + } + } +#endif + for (; n && (*d=*s); n--, s++, d++); + *d = 0; +finish: + return d-d0 + strlen(s); +} diff --git a/src/orca-libc/src/string/strlen.c b/src/orca-libc/src/string/strlen.c new file mode 100644 index 00000000..309990f0 --- /dev/null +++ b/src/orca-libc/src/string/strlen.c @@ -0,0 +1,22 @@ +#include +#include +#include + +#define ALIGN (sizeof(size_t)) +#define ONES ((size_t)-1/UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX/2+1)) +#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS) + +size_t strlen(const char *s) +{ + const char *a = s; +#ifdef __GNUC__ + typedef size_t __attribute__((__may_alias__)) word; + const word *w; + for (; (uintptr_t)s % ALIGN; s++) if (!*s) return s-a; + for (w = (const void *)s; !HASZERO(*w); w++); + s = (const void *)w; +#endif + for (; *s; s++); + return s-a; +} diff --git a/src/orca-libc/src/string/strncasecmp.c b/src/orca-libc/src/string/strncasecmp.c new file mode 100644 index 00000000..24659721 --- /dev/null +++ b/src/orca-libc/src/string/strncasecmp.c @@ -0,0 +1,10 @@ +#include +#include + +int strncasecmp(const char *_l, const char *_r, size_t n) +{ + const unsigned char *l=(void *)_l, *r=(void *)_r; + if (!n--) return 0; + for (; *l && *r && n && (*l == *r || tolower(*l) == tolower(*r)); l++, r++, n--); + return tolower(*l) - tolower(*r); +} diff --git a/src/orca-libc/src/string/strncat.c b/src/orca-libc/src/string/strncat.c new file mode 100644 index 00000000..01ca2a23 --- /dev/null +++ b/src/orca-libc/src/string/strncat.c @@ -0,0 +1,10 @@ +#include + +char *strncat(char *restrict d, const char *restrict s, size_t n) +{ + char *a = d; + d += strlen(d); + while (n && *s) n--, *d++ = *s++; + *d++ = 0; + return a; +} diff --git a/src/orca-libc/src/string/strncmp.c b/src/orca-libc/src/string/strncmp.c new file mode 100644 index 00000000..e228843f --- /dev/null +++ b/src/orca-libc/src/string/strncmp.c @@ -0,0 +1,9 @@ +#include + +int strncmp(const char *_l, const char *_r, size_t n) +{ + const unsigned char *l=(void *)_l, *r=(void *)_r; + if (!n--) return 0; + for (; *l && *r && n && *l == *r ; l++, r++, n--); + return *l - *r; +} diff --git a/src/orca-libc/src/string/strncpy.c b/src/orca-libc/src/string/strncpy.c new file mode 100644 index 00000000..545892e6 --- /dev/null +++ b/src/orca-libc/src/string/strncpy.c @@ -0,0 +1,7 @@ +#include + +char *strncpy(char *restrict d, const char *restrict s, size_t n) +{ + __stpncpy(d, s, n); + return d; +} diff --git a/src/orca-libc/src/string/strndup.c b/src/orca-libc/src/string/strndup.c new file mode 100644 index 00000000..617d27ba --- /dev/null +++ b/src/orca-libc/src/string/strndup.c @@ -0,0 +1,12 @@ +#include +#include + +char *strndup(const char *s, size_t n) +{ + size_t l = strnlen(s, n); + char *d = malloc(l+1); + if (!d) return NULL; + memcpy(d, s, l); + d[l] = 0; + return d; +} diff --git a/src/orca-libc/src/string/strnlen.c b/src/orca-libc/src/string/strnlen.c new file mode 100644 index 00000000..6442eb79 --- /dev/null +++ b/src/orca-libc/src/string/strnlen.c @@ -0,0 +1,7 @@ +#include + +size_t strnlen(const char *s, size_t n) +{ + const char *p = memchr(s, 0, n); + return p ? p-s : n; +} diff --git a/src/orca-libc/src/string/strpbrk.c b/src/orca-libc/src/string/strpbrk.c new file mode 100644 index 00000000..55947c64 --- /dev/null +++ b/src/orca-libc/src/string/strpbrk.c @@ -0,0 +1,7 @@ +#include + +char *strpbrk(const char *s, const char *b) +{ + s += strcspn(s, b); + return *s ? (char *)s : 0; +} diff --git a/src/orca-libc/src/string/strrchr.c b/src/orca-libc/src/string/strrchr.c new file mode 100644 index 00000000..98ad1b04 --- /dev/null +++ b/src/orca-libc/src/string/strrchr.c @@ -0,0 +1,6 @@ +#include + +char *strrchr(const char *s, int c) +{ + return __memrchr(s, c, strlen(s) + 1); +} diff --git a/src/orca-libc/src/string/strsep.c b/src/orca-libc/src/string/strsep.c new file mode 100644 index 00000000..cb37c32e --- /dev/null +++ b/src/orca-libc/src/string/strsep.c @@ -0,0 +1,13 @@ +#define _GNU_SOURCE +#include + +char *strsep(char **str, const char *sep) +{ + char *s = *str, *end; + if (!s) return NULL; + end = s + strcspn(s, sep); + if (*end) *end++ = 0; + else end = 0; + *str = end; + return s; +} diff --git a/src/orca-libc/src/string/strspn.c b/src/orca-libc/src/string/strspn.c new file mode 100644 index 00000000..9543dad0 --- /dev/null +++ b/src/orca-libc/src/string/strspn.c @@ -0,0 +1,20 @@ +#include + +#define BITOP(a,b,op) \ + ((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a)))) + +size_t strspn(const char *s, const char *c) +{ + const char *a = s; + size_t byteset[32/sizeof(size_t)] = { 0 }; + + if (!c[0]) return 0; + if (!c[1]) { + for (; *s == *c; s++); + return s-a; + } + + for (; *c && BITOP(byteset, *(unsigned char *)c, |=); c++); + for (; *s && BITOP(byteset, *(unsigned char *)s, &); s++); + return s-a; +} diff --git a/src/orca-libc/src/string/strstr.c b/src/orca-libc/src/string/strstr.c new file mode 100644 index 00000000..96657bc2 --- /dev/null +++ b/src/orca-libc/src/string/strstr.c @@ -0,0 +1,154 @@ +#include +#include + +static char *twobyte_strstr(const unsigned char *h, const unsigned char *n) +{ + uint16_t nw = n[0]<<8 | n[1], hw = h[0]<<8 | h[1]; + for (h++; *h && hw != nw; hw = hw<<8 | *++h); + return *h ? (char *)h-1 : 0; +} + +static char *threebyte_strstr(const unsigned char *h, const unsigned char *n) +{ + uint32_t nw = (uint32_t)n[0]<<24 | n[1]<<16 | n[2]<<8; + uint32_t hw = (uint32_t)h[0]<<24 | h[1]<<16 | h[2]<<8; + for (h+=2; *h && hw != nw; hw = (hw|*++h)<<8); + return *h ? (char *)h-2 : 0; +} + +static char *fourbyte_strstr(const unsigned char *h, const unsigned char *n) +{ + uint32_t nw = (uint32_t)n[0]<<24 | n[1]<<16 | n[2]<<8 | n[3]; + uint32_t hw = (uint32_t)h[0]<<24 | h[1]<<16 | h[2]<<8 | h[3]; + for (h+=3; *h && hw != nw; hw = hw<<8 | *++h); + return *h ? (char *)h-3 : 0; +} + +#define MAX(a,b) ((a)>(b)?(a):(b)) +#define MIN(a,b) ((a)<(b)?(a):(b)) + +#define BITOP(a,b,op) \ + ((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a)))) + +static char *twoway_strstr(const unsigned char *h, const unsigned char *n) +{ + const unsigned char *z; + size_t l, ip, jp, k, p, ms, p0, mem, mem0; + size_t byteset[32 / sizeof(size_t)] = { 0 }; + size_t shift[256]; + + /* Computing length of needle and fill shift table */ + for (l=0; n[l] && h[l]; l++) + BITOP(byteset, n[l], |=), shift[n[l]] = l+1; + if (n[l]) return 0; /* hit the end of h */ + + /* Compute maximal suffix */ + ip = -1; jp = 0; k = p = 1; + while (jp+k n[jp+k]) { + jp += k; + k = 1; + p = jp - ip; + } else { + ip = jp++; + k = p = 1; + } + } + ms = ip; + p0 = p; + + /* And with the opposite comparison */ + ip = -1; jp = 0; k = p = 1; + while (jp+k ms+1) ms = ip; + else p = p0; + + /* Periodic needle? */ + if (memcmp(n, n+p, ms+1)) { + mem0 = 0; + p = MAX(ms, l-ms-1) + 1; + } else mem0 = l-p; + mem = 0; + + /* Initialize incremental end-of-haystack pointer */ + z = h; + + /* Search loop */ + for (;;) { + /* Update incremental end-of-haystack pointer */ + if (z-h < l) { + /* Fast estimate for MAX(l,63) */ + size_t grow = l | 63; + const unsigned char *z2 = memchr(z, 0, grow); + if (z2) { + z = z2; + if (z-h < l) return 0; + } else z += grow; + } + + /* Check last byte first; advance by shift on mismatch */ + if (BITOP(byteset, h[l-1], &)) { + k = l-shift[h[l-1]]; + if (k) { + if (k < mem) k = mem; + h += k; + mem = 0; + continue; + } + } else { + h += l; + mem = 0; + continue; + } + + /* Compare right half */ + for (k=MAX(ms+1,mem); n[k] && n[k] == h[k]; k++); + if (n[k]) { + h += k-ms; + mem = 0; + continue; + } + /* Compare left half */ + for (k=ms+1; k>mem && n[k-1] == h[k-1]; k--); + if (k <= mem) return (char *)h; + h += p; + mem = mem0; + } +} + +char *strstr(const char *h, const char *n) +{ + /* Return immediately on empty needle */ + if (!n[0]) return (char *)h; + + /* Use faster algorithms for short needles */ + h = strchr(h, *n); + if (!h || !n[1]) return (char *)h; + if (!h[1]) return 0; + if (!n[2]) return twobyte_strstr((void *)h, (void *)n); + if (!h[2]) return 0; + if (!n[3]) return threebyte_strstr((void *)h, (void *)n); + if (!h[3]) return 0; + if (!n[4]) return fourbyte_strstr((void *)h, (void *)n); + + return twoway_strstr((void *)h, (void *)n); +} diff --git a/src/orca-libc/src/string/strtok.c b/src/orca-libc/src/string/strtok.c new file mode 100644 index 00000000..35087902 --- /dev/null +++ b/src/orca-libc/src/string/strtok.c @@ -0,0 +1,13 @@ +#include + +char *strtok(char *restrict s, const char *restrict sep) +{ + static char *p; + if (!s && !(s = p)) return NULL; + s += strspn(s, sep); + if (!*s) return p = 0; + p = s + strcspn(s, sep); + if (*p) *p++ = 0; + else p = 0; + return s; +} diff --git a/src/orca-libc/src/string/strtok_r.c b/src/orca-libc/src/string/strtok_r.c new file mode 100644 index 00000000..862d4fe4 --- /dev/null +++ b/src/orca-libc/src/string/strtok_r.c @@ -0,0 +1,12 @@ +#include + +char *strtok_r(char *restrict s, const char *restrict sep, char **restrict p) +{ + if (!s && !(s = *p)) return NULL; + s += strspn(s, sep); + if (!*s) return *p = 0; + *p = s + strcspn(s, sep); + if (**p) *(*p)++ = 0; + else *p = 0; + return s; +} diff --git a/src/orca-libc/src/string/strverscmp.c b/src/orca-libc/src/string/strverscmp.c new file mode 100644 index 00000000..4daf276d --- /dev/null +++ b/src/orca-libc/src/string/strverscmp.c @@ -0,0 +1,34 @@ +#define _GNU_SOURCE +#include +#include + +int strverscmp(const char *l0, const char *r0) +{ + const unsigned char *l = (const void *)l0; + const unsigned char *r = (const void *)r0; + size_t i, dp, j; + int z = 1; + + /* Find maximal matching prefix and track its maximal digit + * suffix and whether those digits are all zeros. */ + for (dp=i=0; l[i]==r[i]; i++) { + int c = l[i]; + if (!c) return 0; + if (!isdigit(c)) dp=i+1, z=1; + else if (c!='0') z=0; + } + + if (l[dp]!='0' && r[dp]!='0') { + /* If we're not looking at a digit sequence that began + * with a zero, longest digit string is greater. */ + for (j=i; isdigit(l[j]); j++) + if (!isdigit(r[j])) return 1; + if (isdigit(r[j])) return -1; + } else if (z && dp + +void swab(const void *restrict _src, void *restrict _dest, ssize_t n) +{ + const char *src = _src; + char *dest = _dest; + for (; n>1; n-=2) { + dest[0] = src[1]; + dest[1] = src[0]; + dest += 2; + src += 2; + } +} diff --git a/src/orca-libc/src/string/wcpcpy.c b/src/orca-libc/src/string/wcpcpy.c new file mode 100644 index 00000000..ef401343 --- /dev/null +++ b/src/orca-libc/src/string/wcpcpy.c @@ -0,0 +1,6 @@ +#include + +wchar_t *wcpcpy(wchar_t *restrict d, const wchar_t *restrict s) +{ + return wcscpy(d, s) + wcslen(s); +} diff --git a/src/orca-libc/src/string/wcpncpy.c b/src/orca-libc/src/string/wcpncpy.c new file mode 100644 index 00000000..b667f6d6 --- /dev/null +++ b/src/orca-libc/src/string/wcpncpy.c @@ -0,0 +1,6 @@ +#include + +wchar_t *wcpncpy(wchar_t *restrict d, const wchar_t *restrict s, size_t n) +{ + return wcsncpy(d, s, n) + wcsnlen(s, n); +} diff --git a/src/orca-libc/src/string/wcscasecmp.c b/src/orca-libc/src/string/wcscasecmp.c new file mode 100644 index 00000000..3edeec7d --- /dev/null +++ b/src/orca-libc/src/string/wcscasecmp.c @@ -0,0 +1,7 @@ +#include +#include + +int wcscasecmp(const wchar_t *l, const wchar_t *r) +{ + return wcsncasecmp(l, r, -1); +} diff --git a/src/orca-libc/src/string/wcscat.c b/src/orca-libc/src/string/wcscat.c new file mode 100644 index 00000000..d4f00ebd --- /dev/null +++ b/src/orca-libc/src/string/wcscat.c @@ -0,0 +1,7 @@ +#include + +wchar_t *wcscat(wchar_t *restrict dest, const wchar_t *restrict src) +{ + wcscpy(dest + wcslen(dest), src); + return dest; +} diff --git a/src/orca-libc/src/string/wcschr.c b/src/orca-libc/src/string/wcschr.c new file mode 100644 index 00000000..8dfc2f31 --- /dev/null +++ b/src/orca-libc/src/string/wcschr.c @@ -0,0 +1,8 @@ +#include + +wchar_t *wcschr(const wchar_t *s, wchar_t c) +{ + if (!c) return (wchar_t *)s + wcslen(s); + for (; *s && *s != c; s++); + return *s ? (wchar_t *)s : 0; +} diff --git a/src/orca-libc/src/string/wcscmp.c b/src/orca-libc/src/string/wcscmp.c new file mode 100644 index 00000000..26eeee70 --- /dev/null +++ b/src/orca-libc/src/string/wcscmp.c @@ -0,0 +1,7 @@ +#include + +int wcscmp(const wchar_t *l, const wchar_t *r) +{ + for (; *l==*r && *l && *r; l++, r++); + return *l - *r; +} diff --git a/src/orca-libc/src/string/wcscpy.c b/src/orca-libc/src/string/wcscpy.c new file mode 100644 index 00000000..625bf53d --- /dev/null +++ b/src/orca-libc/src/string/wcscpy.c @@ -0,0 +1,8 @@ +#include + +wchar_t *wcscpy(wchar_t *restrict d, const wchar_t *restrict s) +{ + wchar_t *a = d; + while ((*d++ = *s++)); + return a; +} diff --git a/src/orca-libc/src/string/wcscspn.c b/src/orca-libc/src/string/wcscspn.c new file mode 100644 index 00000000..c4e52722 --- /dev/null +++ b/src/orca-libc/src/string/wcscspn.c @@ -0,0 +1,10 @@ +#include + +size_t wcscspn(const wchar_t *s, const wchar_t *c) +{ + const wchar_t *a; + if (!c[0]) return wcslen(s); + if (!c[1]) return (s=wcschr(a=s, *c)) ? s-a : wcslen(a); + for (a=s; *s && !wcschr(c, *s); s++); + return s-a; +} diff --git a/src/orca-libc/src/string/wcsdup.c b/src/orca-libc/src/string/wcsdup.c new file mode 100644 index 00000000..f398e809 --- /dev/null +++ b/src/orca-libc/src/string/wcsdup.c @@ -0,0 +1,10 @@ +#include +#include + +wchar_t *wcsdup(const wchar_t *s) +{ + size_t l = wcslen(s); + wchar_t *d = malloc((l+1)*sizeof(wchar_t)); + if (!d) return NULL; + return wmemcpy(d, s, l+1); +} diff --git a/src/orca-libc/src/string/wcslen.c b/src/orca-libc/src/string/wcslen.c new file mode 100644 index 00000000..1b7b6655 --- /dev/null +++ b/src/orca-libc/src/string/wcslen.c @@ -0,0 +1,8 @@ +#include + +size_t wcslen(const wchar_t *s) +{ + const wchar_t *a; + for (a=s; *s; s++); + return s-a; +} diff --git a/src/orca-libc/src/string/wcsncasecmp.c b/src/orca-libc/src/string/wcsncasecmp.c new file mode 100644 index 00000000..8fefe799 --- /dev/null +++ b/src/orca-libc/src/string/wcsncasecmp.c @@ -0,0 +1,9 @@ +#include +#include + +int wcsncasecmp(const wchar_t *l, const wchar_t *r, size_t n) +{ + if (!n--) return 0; + for (; *l && *r && n && (*l == *r || towlower(*l) == towlower(*r)); l++, r++, n--); + return towlower(*l) - towlower(*r); +} diff --git a/src/orca-libc/src/string/wcsncat.c b/src/orca-libc/src/string/wcsncat.c new file mode 100644 index 00000000..8563f1a2 --- /dev/null +++ b/src/orca-libc/src/string/wcsncat.c @@ -0,0 +1,10 @@ +#include + +wchar_t *wcsncat(wchar_t *restrict d, const wchar_t *restrict s, size_t n) +{ + wchar_t *a = d; + d += wcslen(d); + while (n && *s) n--, *d++ = *s++; + *d++ = 0; + return a; +} diff --git a/src/orca-libc/src/string/wcsncmp.c b/src/orca-libc/src/string/wcsncmp.c new file mode 100644 index 00000000..4ab32a92 --- /dev/null +++ b/src/orca-libc/src/string/wcsncmp.c @@ -0,0 +1,7 @@ +#include + +int wcsncmp(const wchar_t *l, const wchar_t *r, size_t n) +{ + for (; n && *l==*r && *l && *r; n--, l++, r++); + return n ? *l - *r : 0; +} diff --git a/src/orca-libc/src/string/wcsncpy.c b/src/orca-libc/src/string/wcsncpy.c new file mode 100644 index 00000000..4bede04d --- /dev/null +++ b/src/orca-libc/src/string/wcsncpy.c @@ -0,0 +1,9 @@ +#include + +wchar_t *wcsncpy(wchar_t *restrict d, const wchar_t *restrict s, size_t n) +{ + wchar_t *a = d; + while (n && *s) n--, *d++ = *s++; + wmemset(d, 0, n); + return a; +} diff --git a/src/orca-libc/src/string/wcsnlen.c b/src/orca-libc/src/string/wcsnlen.c new file mode 100644 index 00000000..a7763373 --- /dev/null +++ b/src/orca-libc/src/string/wcsnlen.c @@ -0,0 +1,8 @@ +#include + +size_t wcsnlen(const wchar_t *s, size_t n) +{ + const wchar_t *z = wmemchr(s, 0, n); + if (z) n = z-s; + return n; +} diff --git a/src/orca-libc/src/string/wcspbrk.c b/src/orca-libc/src/string/wcspbrk.c new file mode 100644 index 00000000..0c72c197 --- /dev/null +++ b/src/orca-libc/src/string/wcspbrk.c @@ -0,0 +1,7 @@ +#include + +wchar_t *wcspbrk(const wchar_t *s, const wchar_t *b) +{ + s += wcscspn(s, b); + return *s ? (wchar_t *)s : NULL; +} diff --git a/src/orca-libc/src/string/wcsrchr.c b/src/orca-libc/src/string/wcsrchr.c new file mode 100644 index 00000000..8961b9e2 --- /dev/null +++ b/src/orca-libc/src/string/wcsrchr.c @@ -0,0 +1,8 @@ +#include + +wchar_t *wcsrchr(const wchar_t *s, wchar_t c) +{ + const wchar_t *p; + for (p=s+wcslen(s); p>=s && *p!=c; p--); + return p>=s ? (wchar_t *)p : 0; +} diff --git a/src/orca-libc/src/string/wcsspn.c b/src/orca-libc/src/string/wcsspn.c new file mode 100644 index 00000000..4320d8f6 --- /dev/null +++ b/src/orca-libc/src/string/wcsspn.c @@ -0,0 +1,8 @@ +#include + +size_t wcsspn(const wchar_t *s, const wchar_t *c) +{ + const wchar_t *a; + for (a=s; *s && wcschr(c, *s); s++); + return s-a; +} diff --git a/src/orca-libc/src/string/wcsstr.c b/src/orca-libc/src/string/wcsstr.c new file mode 100644 index 00000000..4caaef3c --- /dev/null +++ b/src/orca-libc/src/string/wcsstr.c @@ -0,0 +1,105 @@ +#include + +#define MAX(a,b) ((a)>(b)?(a):(b)) +#define MIN(a,b) ((a)<(b)?(a):(b)) + +static wchar_t *twoway_wcsstr(const wchar_t *h, const wchar_t *n) +{ + const wchar_t *z; + size_t l, ip, jp, k, p, ms, p0, mem, mem0; + + /* Computing length of needle */ + for (l=0; n[l] && h[l]; l++); + if (n[l]) return 0; /* hit the end of h */ + + /* Compute maximal suffix */ + ip = -1; jp = 0; k = p = 1; + while (jp+k n[jp+k]) { + jp += k; + k = 1; + p = jp - ip; + } else { + ip = jp++; + k = p = 1; + } + } + ms = ip; + p0 = p; + + /* And with the opposite comparison */ + ip = -1; jp = 0; k = p = 1; + while (jp+k ms+1) ms = ip; + else p = p0; + + /* Periodic needle? */ + if (wmemcmp(n, n+p, ms+1)) { + mem0 = 0; + p = MAX(ms, l-ms-1) + 1; + } else mem0 = l-p; + mem = 0; + + /* Initialize incremental end-of-haystack pointer */ + z = h; + + /* Search loop */ + for (;;) { + /* Update incremental end-of-haystack pointer */ + if (z-h < l) { + /* Fast estimate for MIN(l,63) */ + size_t grow = l | 63; + const wchar_t *z2 = wmemchr(z, 0, grow); + if (z2) { + z = z2; + if (z-h < l) return 0; + } else z += grow; + } + + /* Compare right half */ + for (k=MAX(ms+1,mem); n[k] && n[k] == h[k]; k++); + if (n[k]) { + h += k-ms; + mem = 0; + continue; + } + /* Compare left half */ + for (k=ms+1; k>mem && n[k-1] == h[k-1]; k--); + if (k <= mem) return (wchar_t *)h; + h += p; + mem = mem0; + } +} + +wchar_t *wcsstr(const wchar_t *restrict h, const wchar_t *restrict n) +{ + /* Return immediately on empty needle or haystack */ + if (!n[0]) return (wchar_t *)h; + if (!h[0]) return 0; + + /* Use faster algorithms for short needles */ + h = wcschr(h, *n); + if (!h || !n[1]) return (wchar_t *)h; + if (!h[1]) return 0; + + return twoway_wcsstr(h, n); +} diff --git a/src/orca-libc/src/string/wcstok.c b/src/orca-libc/src/string/wcstok.c new file mode 100644 index 00000000..ecc80331 --- /dev/null +++ b/src/orca-libc/src/string/wcstok.c @@ -0,0 +1,12 @@ +#include + +wchar_t *wcstok(wchar_t *restrict s, const wchar_t *restrict sep, wchar_t **restrict p) +{ + if (!s && !(s = *p)) return NULL; + s += wcsspn(s, sep); + if (!*s) return *p = 0; + *p = s + wcscspn(s, sep); + if (**p) *(*p)++ = 0; + else *p = 0; + return s; +} diff --git a/src/orca-libc/src/string/wcswcs.c b/src/orca-libc/src/string/wcswcs.c new file mode 100644 index 00000000..9cfe4ac4 --- /dev/null +++ b/src/orca-libc/src/string/wcswcs.c @@ -0,0 +1,6 @@ +#include + +wchar_t *wcswcs(const wchar_t *haystack, const wchar_t *needle) +{ + return wcsstr(haystack, needle); +} diff --git a/src/orca-libc/src/string/wmemchr.c b/src/orca-libc/src/string/wmemchr.c new file mode 100644 index 00000000..2bc2c270 --- /dev/null +++ b/src/orca-libc/src/string/wmemchr.c @@ -0,0 +1,7 @@ +#include + +wchar_t *wmemchr(const wchar_t *s, wchar_t c, size_t n) +{ + for (; n && *s != c; n--, s++); + return n ? (wchar_t *)s : 0; +} diff --git a/src/orca-libc/src/string/wmemcmp.c b/src/orca-libc/src/string/wmemcmp.c new file mode 100644 index 00000000..2a193263 --- /dev/null +++ b/src/orca-libc/src/string/wmemcmp.c @@ -0,0 +1,7 @@ +#include + +int wmemcmp(const wchar_t *l, const wchar_t *r, size_t n) +{ + for (; n && *l==*r; n--, l++, r++); + return n ? *l-*r : 0; +} diff --git a/src/orca-libc/src/string/wmemcpy.c b/src/orca-libc/src/string/wmemcpy.c new file mode 100644 index 00000000..52e6e6e0 --- /dev/null +++ b/src/orca-libc/src/string/wmemcpy.c @@ -0,0 +1,8 @@ +#include + +wchar_t *wmemcpy(wchar_t *restrict d, const wchar_t *restrict s, size_t n) +{ + wchar_t *a = d; + while (n--) *d++ = *s++; + return a; +} diff --git a/src/orca-libc/src/string/wmemmove.c b/src/orca-libc/src/string/wmemmove.c new file mode 100644 index 00000000..964c9032 --- /dev/null +++ b/src/orca-libc/src/string/wmemmove.c @@ -0,0 +1,13 @@ +#include +#include + +wchar_t *wmemmove(wchar_t *d, const wchar_t *s, size_t n) +{ + wchar_t *d0 = d; + if (d == s) return d; + if ((uintptr_t)d-(uintptr_t)s < n * sizeof *d) + while (n--) d[n] = s[n]; + else + while (n--) *d++ = *s++; + return d0; +} diff --git a/src/orca-libc/src/string/wmemset.c b/src/orca-libc/src/string/wmemset.c new file mode 100644 index 00000000..07a037a0 --- /dev/null +++ b/src/orca-libc/src/string/wmemset.c @@ -0,0 +1,8 @@ +#include + +wchar_t *wmemset(wchar_t *d, wchar_t c, size_t n) +{ + wchar_t *ret = d; + while (n--) *d++ = c; + return ret; +} diff --git a/src/orca-libc/test.c b/src/orca-libc/test.c new file mode 100644 index 00000000..d0f8cebf --- /dev/null +++ b/src/orca-libc/test.c @@ -0,0 +1,31 @@ +#include +#include +#include + +__attribute__((export_name("main"))) int main() +{ + // x = cos(x); + + // int l = strtol("123", 0, 10); + + return (0); +} + +__attribute__((export_name("foo"))) double foo(double a) +{ + return (cos(a)); +} + +__attribute__((export_name("bar"))) double bar() +{ + + double res = 0; + sscanf("42.53", "%lf", &res); + return (res); +} + +__attribute__((export_name("baz"))) char* baz(char* buff) +{ + sprintf(buff, "Hello, %f\n", 3.14); + return (buff); +} diff --git a/src/orca-libc/tools/mkalltypes.sed b/src/orca-libc/tools/mkalltypes.sed new file mode 100644 index 00000000..61119212 --- /dev/null +++ b/src/orca-libc/tools/mkalltypes.sed @@ -0,0 +1,15 @@ +/^TYPEDEF/s/TYPEDEF \(.*\) \([^ ]*\);$/#if defined(__NEED_\2) \&\& !defined(__DEFINED_\2)\ +typedef \1 \2;\ +#define __DEFINED_\2\ +#endif\ +/ +/^STRUCT/s/STRUCT * \([^ ]*\) \(.*\);$/#if defined(__NEED_struct_\1) \&\& !defined(__DEFINED_struct_\1)\ +struct \1 \2;\ +#define __DEFINED_struct_\1\ +#endif\ +/ +/^UNION/s/UNION * \([^ ]*\) \(.*\);$/#if defined(__NEED_union_\1) \&\& !defined(__DEFINED_union_\1)\ +union \1 \2;\ +#define __DEFINED_union_\1\ +#endif\ +/ \ No newline at end of file diff --git a/src/orca.c b/src/orca.c index aaac246b..fa243524 100644 --- a/src/orca.c +++ b/src/orca.c @@ -50,7 +50,6 @@ #include "platform/orca_debug.c" #include "platform/orca_clock.c" #include "platform/orca_memory.c" - #include "platform/orca_malloc.c" #include "platform/platform_io_common.c" #include "platform/orca_io_stubs.c" #include "platform/orca_platform.c" diff --git a/src/platform/orca_debug.c b/src/platform/orca_debug.c index 3a2f2674..944a76f0 100644 --- a/src/platform/orca_debug.c +++ b/src/platform/orca_debug.c @@ -14,6 +14,9 @@ // stb sprintf callback and user struct //---------------------------------------------------------------- +#define STB_SPRINTF_IMPLEMENTATION +#include "ext/stb/stb_sprintf.h" + typedef struct oc_stbsp_context { oc_arena* arena; diff --git a/src/platform/win32_io.c b/src/platform/win32_io.c index 0d72a92c..6820d15e 100644 --- a/src/platform/win32_io.c +++ b/src/platform/win32_io.c @@ -153,7 +153,7 @@ oc_file_desc oc_io_raw_open_at(oc_file_desc dirFd, oc_str8 path, oc_file_access } if(accessRights & OC_FILE_ACCESS_WRITE) { - if(accessRights & OC_FILE_OPEN_APPEND) + if(openFlags & OC_FILE_OPEN_APPEND) { win32AccessFlags |= FILE_APPEND_DATA; } diff --git a/src/runtime.c b/src/runtime.c index 7a6a70c6..2755cbc5 100644 --- a/src/runtime.c +++ b/src/runtime.c @@ -18,6 +18,8 @@ #include "runtime_io.c" #include "runtime_memory.c" +static const char* s_test_wasm_module_path = NULL; + oc_font orca_font_create(const char* resourcePath) { //NOTE(martin): create default fonts @@ -271,6 +273,14 @@ void oc_bridge_log(oc_log_level level, msg); } +void oc_bridge_exit(int ec) +{ + //TODO: send a trap exit to wasm3 to stop interpreter, + // then when we return from the trap, quit app + // temporarily, we just exit here + exit(ec); +} + void oc_bridge_request_quit(void) { __orcaApp.quit = true; @@ -475,11 +485,15 @@ i32 orca_runloop(void* user) const char* bundleNameCString = "module"; oc_str8 modulePath = oc_path_executable_relative(scratch.arena, OC_STR8("../app/wasm/module.wasm")); + if(s_test_wasm_module_path) + { + modulePath = oc_str8_push_copy(scratch.arena, OC_STR8(s_test_wasm_module_path)); + } FILE* file = fopen(modulePath.ptr, "rb"); if(!file) { - OC_ABORT("The application couldn't load: web assembly module not found"); + OC_ABORT("The application couldn't load: web assembly module '%s' not found", modulePath.ptr); } fseek(file, 0, SEEK_END); @@ -612,6 +626,35 @@ i32 orca_runloop(void* user) IM3Function* exports = app->env.exports; + if(s_test_wasm_module_path) + { + i32 returnCode = 0; + if(exports[OC_EXPORT_ON_TEST]) + { + M3Result res = m3_Call(exports[OC_EXPORT_ON_TEST], 0, 0); + if(res) + { + OC_WASM3_TRAP(app->env.m3Runtime, res, "Runtime error"); + returnCode = 1; + } + else + { + res = m3_GetResultsV(exports[OC_EXPORT_ON_TEST], &returnCode); + if(returnCode != 0) + { + oc_log_error("Tests failed. Exit code: %d\n", returnCode); + } + } + } + else + { + returnCode = 1; + oc_log_error("Failed to find oc_on_test() hook - unable to run tests.\n"); + } + oc_request_quit(); + return returnCode; + } + //NOTE: call init handler if(exports[OC_EXPORT_ON_INIT]) { @@ -994,6 +1037,14 @@ i32 orca_runloop(void* user) int main(int argc, char** argv) { + if(argc > 1) + { + if(strstr(argv[1], "--test=")) + { + s_test_wasm_module_path = argv[1] + sizeof("--test=") - 1; + } + } + oc_log_set_level(OC_LOG_LEVEL_INFO); oc_init(); @@ -1001,34 +1052,38 @@ int main(int argc, char** argv) oc_runtime* app = &__orcaApp; - //NOTE: create window and surfaces - oc_rect windowRect = { .x = 100, .y = 100, .w = 810, .h = 610 }; - app->window = oc_window_create(windowRect, OC_STR8("orca"), 0); - - app->debugOverlay.show = false; - app->debugOverlay.surface = oc_surface_create_for_window(app->window, OC_CANVAS); - app->debugOverlay.canvas = oc_canvas_create(); - app->debugOverlay.fontReg = orca_font_create("../resources/Menlo.ttf"); - app->debugOverlay.fontBold = orca_font_create("../resources/Menlo Bold.ttf"); app->debugOverlay.maxEntries = 200; oc_arena_init(&app->debugOverlay.logArena); + if(s_test_wasm_module_path == NULL) + { + //NOTE: create window and surfaces + oc_rect windowRect = { .x = 100, .y = 100, .w = 810, .h = 610 }; + app->window = oc_window_create(windowRect, OC_STR8("orca"), 0); + + app->debugOverlay.show = false; + app->debugOverlay.surface = oc_surface_create_for_window(app->window, OC_CANVAS); + app->debugOverlay.canvas = oc_canvas_create(); + app->debugOverlay.fontReg = orca_font_create("../resources/Menlo.ttf"); + app->debugOverlay.fontBold = orca_font_create("../resources/Menlo Bold.ttf"); + #if OC_PLATFORM_WINDOWS - //NOTE(martin): on windows we set all surfaces to non-synced, and do a single "manual" wait here. - // on macOS each surface is individually synced to the monitor refresh rate but don't block each other - oc_surface_swap_interval(app->debugOverlay.surface, 0); + //NOTE(martin): on windows we set all surfaces to non-synced, and do a single "manual" wait here. + // on macOS each surface is individually synced to the monitor refresh rate but don't block each other + oc_surface_swap_interval(app->debugOverlay.surface, 0); #else - oc_surface_swap_interval(app->debugOverlay.surface, 1); + oc_surface_swap_interval(app->debugOverlay.surface, 1); #endif - oc_surface_deselect(); + oc_surface_deselect(); - oc_ui_init(&app->debugOverlay.ui); + oc_ui_init(&app->debugOverlay.ui); - //NOTE: show window and start runloop - oc_window_bring_to_front(app->window); - oc_window_focus(app->window); - oc_window_center(app->window); + //NOTE: show window and start runloop + oc_window_bring_to_front(app->window); + oc_window_focus(app->window); + oc_window_center(app->window); + } oc_thread* runloopThread = oc_thread_create(orca_runloop, 0); @@ -1038,12 +1093,16 @@ int main(int argc, char** argv) //TODO: what to do with mem scratch here? } - oc_thread_join(runloopThread, NULL); + i64 exitCode = 0; + oc_thread_join(runloopThread, &exitCode); - oc_canvas_destroy(app->debugOverlay.canvas); - oc_surface_destroy(app->debugOverlay.surface); - oc_window_destroy(app->window); + if(s_test_wasm_module_path == NULL) + { + oc_canvas_destroy(app->debugOverlay.canvas); + oc_surface_destroy(app->debugOverlay.surface); + oc_window_destroy(app->window); + } oc_terminate(); - return (0); + return (int)(exitCode); } diff --git a/src/runtime.h b/src/runtime.h index bb7879ab..5518c90a 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -16,7 +16,9 @@ #include "m3_env.h" #include "wasm3.h" +// Note oc_on_test() is a special handler only called for --test modules #define OC_EXPORTS(X) \ + X(OC_EXPORT_ON_TEST, "oc_on_test", "i", "") \ X(OC_EXPORT_ON_INIT, "oc_on_init", "", "") \ X(OC_EXPORT_MOUSE_DOWN, "oc_on_mouse_down", "", "i") \ X(OC_EXPORT_MOUSE_UP, "oc_on_mouse_up", "", "i") \ diff --git a/src/runtime_io.c b/src/runtime_io.c index 9b831612..c3de1650 100644 --- a/src/runtime_io.c +++ b/src/runtime_io.c @@ -9,34 +9,42 @@ #include "runtime.h" #include "runtime_memory.h" -oc_io_cmp oc_bridge_io_single_rect(oc_io_req* wasmReq) +oc_io_cmp oc_bridge_io_wait_single_req(oc_io_req* wasmReq) { oc_runtime* orca = oc_runtime_get(); oc_io_cmp cmp = { 0 }; oc_io_req req = *wasmReq; - //TODO have a separate oc_wasm_io_req struct - void* buffer = oc_wasm_address_to_ptr((oc_wasm_addr)(uintptr_t)req.buffer, req.size); - - if(buffer) + //TODO: lookup if operation needs a buffer in a compile-time table + oc_io_op op = wasmReq->op; + if(op == OC_IO_OPEN_AT + || op == OC_IO_FSTAT + || op == OC_IO_READ + || op == OC_IO_WRITE) { - req.buffer = buffer; - - if(req.op == OC_IO_OPEN_AT) + //TODO have a separate oc_wasm_io_req struct, and marshall between wasm/native versions + void* buffer = oc_wasm_address_to_ptr((oc_wasm_addr)(uintptr_t)req.buffer, req.size); + if(buffer) { - if(req.handle.h == 0) + req.buffer = buffer; + + //TODO: lookup in a compile-time table which operations use a 'at' handle that must be replaced by root handle if 0. + if(req.op == OC_IO_OPEN_AT && req.handle.h == 0) { //NOTE: change root to app local folder req.handle = orca->rootDir; req.open.flags |= OC_FILE_OPEN_RESTRICT; } } - cmp = oc_io_wait_single_req_for_table(&req, &orca->fileTable); + else + { + cmp.error = OC_IO_ERR_ARG; + } } - else + if(cmp.error == OC_IO_OK) { - cmp.error = OC_IO_ERR_ARG; + cmp = oc_io_wait_single_req_for_table(&req, &orca->fileTable); } return (cmp); diff --git a/src/util/debug.h b/src/util/debug.h index bcedf8eb..c197674b 100644 --- a/src/util/debug.h +++ b/src/util/debug.h @@ -47,7 +47,8 @@ extern "C" { // Abort/Assert //---------------------------------------------------------------- -#define OC_ABORT(fmt, ...) oc_abort_ext(__FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__) +#define _OC_ABORT_(fmt, ...) oc_abort_ext(__FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__) +#define OC_ABORT(...) _OC_ABORT_(OC_VA_NOPT("", ##__VA_ARGS__) OC_ARG1(__VA_ARGS__) OC_VA_COMMA_TAIL(__VA_ARGS__)) #ifdef OC_NO_ASSERT #define OC_ASSERT(x, ...) diff --git a/src/util/macros.h b/src/util/macros.h index d7fdf94e..f944e110 100644 --- a/src/util/macros.h +++ b/src/util/macros.h @@ -22,14 +22,20 @@ #define OC_EXPAND_NIL(...) //---------------------------------------------------------------------------------------- -// Variadic macros helpers and replacement for __VA_OPT__ extension +// Variadic macros helpers and portable replacement for __VA_OPT__ extension //---------------------------------------------------------------------------------------- #define OC_ARG1_UTIL(a, ...) a #define OC_ARG1(...) OC_ARG1_UTIL(__VA_ARGS__) #define OC_VA_COMMA_TAIL(a, ...) , ##__VA_ARGS__ //NOTE: this expands to opt if __VA_ARGS__ is empty, and to , va1, va2, ... opt otherwise -#define OC_VA_NOPT_UTIL(opt, ...) , ##__VA_ARGS__ opt +#if OC_COMPILER_CLANG + // on clang we use __VA_OPT__ because ##__VA_ARGS__ does not swallow the previous token if there is _no_ arguments + #define OC_VA_NOPT_UTIL(opt, ...) __VA_OPT__(, ) __VA_ARGS__ opt +#else + // on msvc __VA_OPT__ does not exist in C mode, but ##__VA_ARGS__ works even when there is no arguments + #define OC_VA_NOPT_UTIL(opt, ...) , ##__VA_ARGS__ opt +#endif //NOTE: this expands to opt if __VA_ARGS__ is empty, and to nothing otherwise #define OC_VA_NOPT(opt, ...) OC_PASS(OC_ARG1, OC_VA_NOPT_UTIL(opt, ##__VA_ARGS__)) diff --git a/src/util/strings.c b/src/util/strings.c index 74c65ac8..8e981e94 100644 --- a/src/util/strings.c +++ b/src/util/strings.c @@ -5,10 +5,7 @@ * See LICENSE.txt for licensing information * **************************************************************************/ -#include "platform/platform.h" -#if !OC_PLATFORM_ORCA - #include -#endif +#include #include "strings.h" #include "platform/platform_debug.h" diff --git a/src/wasmbind/core_api.json b/src/wasmbind/core_api.json index b3d46712..d4cb85e3 100644 --- a/src/wasmbind/core_api.json +++ b/src/wasmbind/core_api.json @@ -51,6 +51,12 @@ "len": {"proc": "orca_check_cstring", "args": ["note"]}} ] }, +{ + "name": "oc_bridge_exit", + "cname": "oc_bridge_exit", + "ret": {"name": "void", "tag":"v"}, + "args":[{ "name": "ec", "type": {"name": "int", "tag": "i"}}] +}, { "name": "oc_bridge_abort_ext", "cname": "oc_abort_ext_dialog", diff --git a/src/wasmbind/io_api.json b/src/wasmbind/io_api.json index 4c8fb47a..f1a0ff85 100644 --- a/src/wasmbind/io_api.json +++ b/src/wasmbind/io_api.json @@ -1,7 +1,7 @@ [ { "name": "oc_io_wait_single_req", - "cname": "oc_bridge_io_single_rect", + "cname": "oc_bridge_io_wait_single_req", "ret": {"name": "oc_io_cmp", "tag": "S"}, "args": [ {"name": "req", "type": {"name": "oc_io_req*", "tag": "p"}, diff --git a/tests/wasm_tests/.gitignore b/tests/wasm_tests/.gitignore new file mode 100644 index 00000000..8ca98c8f --- /dev/null +++ b/tests/wasm_tests/.gitignore @@ -0,0 +1,2 @@ +*.wasm +StdioTests/ \ No newline at end of file diff --git a/tests/wasm_tests/data/directory/test.txt b/tests/wasm_tests/data/directory/test.txt new file mode 100644 index 00000000..389b335b --- /dev/null +++ b/tests/wasm_tests/data/directory/test.txt @@ -0,0 +1 @@ +Hello from directory/test.txt \ No newline at end of file diff --git a/tests/wasm_tests/data/jail/dir/test.txt b/tests/wasm_tests/data/jail/dir/test.txt new file mode 100644 index 00000000..f1e120f0 --- /dev/null +++ b/tests/wasm_tests/data/jail/dir/test.txt @@ -0,0 +1 @@ +Hello from jail/dir/test.txt \ No newline at end of file diff --git a/tests/wasm_tests/data/jail/dir_escape b/tests/wasm_tests/data/jail/dir_escape new file mode 100644 index 00000000..a96aa0ea --- /dev/null +++ b/tests/wasm_tests/data/jail/dir_escape @@ -0,0 +1 @@ +.. \ No newline at end of file diff --git a/tests/wasm_tests/data/jail/file_escape b/tests/wasm_tests/data/jail/file_escape new file mode 100644 index 00000000..98f61ca7 --- /dev/null +++ b/tests/wasm_tests/data/jail/file_escape @@ -0,0 +1 @@ +../regular.txt \ No newline at end of file diff --git a/tests/wasm_tests/data/jail/test.txt b/tests/wasm_tests/data/jail/test.txt new file mode 100644 index 00000000..d225ff43 --- /dev/null +++ b/tests/wasm_tests/data/jail/test.txt @@ -0,0 +1 @@ +Hello from jail/test.txt \ No newline at end of file diff --git a/tests/wasm_tests/data/regular.txt b/tests/wasm_tests/data/regular.txt new file mode 100644 index 00000000..fac204f1 --- /dev/null +++ b/tests/wasm_tests/data/regular.txt @@ -0,0 +1 @@ +Hello from regular.txt \ No newline at end of file diff --git a/tests/wasm_tests/data/symlink b/tests/wasm_tests/data/symlink new file mode 120000 index 00000000..397e1077 --- /dev/null +++ b/tests/wasm_tests/data/symlink @@ -0,0 +1 @@ +regular.txt \ No newline at end of file diff --git a/tests/wasm_tests/run.bat b/tests/wasm_tests/run.bat new file mode 100644 index 00000000..708e9bc3 --- /dev/null +++ b/tests/wasm_tests/run.bat @@ -0,0 +1,23 @@ +@echo off + +set ORCA_DIR=../.. + +:: common flags to build wasm modules +set wasmFlags=--target=wasm32^ + -mbulk-memory ^ + -g -O2 ^ + -D__ORCA__ ^ + -Wl,--no-entry ^ + -Wl,--export-dynamic ^ + --sysroot %ORCA_DIR%/build/orca-libc ^ + -I%ORCA_DIR%/src ^ + -I%ORCA_DIR%/src/ext + +clang %wasmFlags% -L %ORCA_DIR%/build/bin -lorca_wasm -o stdio_tests.wasm stdio_tests.c +IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL% + +call orca bundle --orca-dir %ORCA_DIR% --name StdioTests --resource-dir data stdio_tests.wasm +IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL% + +StdioTests\bin\StdioTests.exe --test=stdio_tests.wasm +IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL% diff --git a/tests/wasm_tests/run.sh b/tests/wasm_tests/run.sh new file mode 100755 index 00000000..bc818062 --- /dev/null +++ b/tests/wasm_tests/run.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +set -e + +ORCA_DIR=../.. + +wasmFlags="--target=wasm32 \ + -mbulk-memory \ + -g -O2 \ + -D__ORCA__ \ + -Wl,--no-entry \ + -Wl,--export-dynamic \ + --sysroot $ORCA_DIR/build/orca-libc \ + -I $ORCA_DIR/src \ + -I $ORCA_DIR/src/ext" + +if [ ! \( -e bin \) ] ; then + mkdir ./bin +fi + +clang $wasmFlags -L $ORCA_DIR/build/bin -lorca_wasm -o files.wasm files.c + +orca bundle --orca-dir $ORCA_DIR --name Tests --resource-dir data files.wasm + +./Tests.app/Contents/macOS/orca_runtime --test=files.wasm diff --git a/tests/wasm_tests/stdio_tests.c b/tests/wasm_tests/stdio_tests.c new file mode 100644 index 00000000..71cef9fc --- /dev/null +++ b/tests/wasm_tests/stdio_tests.c @@ -0,0 +1,984 @@ +/************************************************************************* +* +* Orca +* Copyright 2023 Martin Fouilleul and the Orca project contributors +* See LICENSE.txt for licensing information +* +**************************************************************************/ + +#include + +#include +#include + +const oc_str8 REGULAR_TXT_CONTENTS = OC_STR8("Hello from regular.txt"); + +oc_file oc_file_from_filep(FILE* f) +{ + unsigned long long handle = *(unsigned long long*)f; + return (oc_file){ .h = handle }; +} + +void force_close_file_no_flush(FILE* file) +{ + oc_file_close(oc_file_from_filep(file)); + free(file); +} + +int check_string(FILE* f, oc_str8 test_string) +{ + char buffer[256]; + size_t n = fread(buffer, 1, 256, f); + if(ferror(f)) + { + oc_log_error("Error while reading test string\n"); + return (-1); + } + + if(oc_str8_cmp(test_string, oc_str8_from_buffer(n, buffer))) + { + return (-1); + } + + return (0); +} + +int test_read(void) +{ + { + oc_str8 path = OC_STR8("regular.txt"); + FILE* f = fopen(path.ptr, "r"); + if(f == NULL || ferror(f)) + { + oc_log_error("Can't open file %.*s for reading\n", (int)path.len, path.ptr); + return (-1); + } + + if(check_string(f, REGULAR_TXT_CONTENTS)) + { + oc_log_error("Check string failed\n"); + return (-1); + } + + fclose(f); + } + + { + oc_str8 path = OC_STR8("directory/test.txt"); + oc_str8 test_string = OC_STR8("Hello from directory/test.txt"); + + FILE* f = fopen(path.ptr, "r"); + if(f == NULL || ferror(f)) + { + oc_log_error("Can't open file %.*s for reading\n", (int)path.len, path.ptr); + return (-1); + } + + if(check_string(f, test_string)) + { + oc_log_error("Check string failed\n"); + return (-1); + } + + fclose(f); + } + + { + FILE* f = fopen("does_not_exist.txt", "r"); + if(f != NULL) + { + oc_log_error("Somehow opened a file that doesn't exist\n"); + return (-1); + } + } + + return (0); +} + +int test_write(void) +{ + oc_arena_scope scratch = oc_scratch_begin(); + oc_arena* arena = scratch.arena; + + oc_str8 path = OC_STR8("write_test.txt"); + oc_str8 test_string = OC_STR8("Hello from write_test.txt"); + + FILE* f = fopen(path.ptr, "w"); + if(ferror(f)) + { + oc_log_error("Can't create/open file %.*s for writing\n", (int)path.len, path.ptr); + return (-1); + } + + size_t written = fwrite(test_string.ptr, 1, test_string.len, f); + if(ferror(f)) + { + oc_log_error("Error while writing %.*s\n", (int)path.len, path.ptr); + return (-1); + } + if(written != test_string.len) + { + oc_log_error("Failed to write the entire string to file. written: %zu, expected: %zu", written, test_string.len); + return (-1); + } + fclose(f); + + char* pathCStr = oc_str8_to_cstring(arena, path); + FILE* file = fopen(pathCStr, "r"); + if(!file) + { + oc_log_error("File %.*s not found while checking\n", (int)path.len, path.ptr); + return (-1); + } + char buffer[256]; + size_t n = fread(buffer, 1, 256, file); + if(n != test_string.len || strncmp(buffer, test_string.ptr, test_string.len)) + { + oc_log_error("Didn't recover test string\n"); + return (-1); + } + fclose(file); + + return (0); +} + +int test_error(void) +{ + { + FILE* f = fopen("regular.txt", "r"); + oc_str8 test_string = OC_STR8("this shouldn't get written since the file is in read mode"); + size_t written = fwrite(test_string.ptr, 1, test_string.len, f); + if(!ferror(f)) + { + oc_log_error("File should be in error state"); + return (-1); + } + if(written > 0) + { + oc_log_error("Wrote %d bytes but shouldn't have written any.", (int)written); + return (-1); + } + + clearerr(f); + if(ferror(f)) + { + oc_log_error("File error state should be cleared"); + return (-1); + } + } + + { + FILE* f = fopen("error_test.txt", "w"); + + char buffer[256]; + size_t n = fread(buffer, 1, sizeof(buffer), f); + + if(!ferror(f)) + { + oc_log_error("File should be in error state"); + return (-1); + } + + clearerr(f); + if(ferror(f)) + { + oc_log_error("File error state should be cleared"); + return (-1); + } + } + + return (0); +} + +int test_eof(void) +{ + FILE* f = fopen("regular.txt", "r"); + char buffer[1024]; + size_t num_read = fread(buffer, 1, sizeof(buffer), f); + if(num_read == 0) + { + oc_log_error("Should have read at least some data"); + return (-1); + } + + if(!feof(f)) + { + oc_log_error("Should be at end of file by now"); + return (-1); + } + + char data = 0; + num_read = fread(&data, 1, 1, f); + if(num_read != 0) + { + oc_log_error("Should be at end of file - no data should be read"); + return (-1); + } + + return (0); +} + +int test_getputc(void) +{ + const oc_str8 filename = OC_STR8("putc_test.txt"); + const oc_str8 test_file_contents = OC_STR8("The quick brown fox jumped over the lazy dog!@#$%^&*()\n"); + + { + FILE* f = fopen(filename.ptr, "w"); + for(int i = 0; i < test_file_contents.len; ++i) + { + int c = test_file_contents.ptr[i]; + if(putc(c, f) != c) + { + oc_log_error("Failed to put character to file"); + return (-1); + } + if(ferror(f)) + { + oc_log_error("Caught error putting character to file"); + return (-1); + } + } + fclose(f); + } + + { + FILE* f = fopen(filename.ptr, "r"); + char buffer[256]; + int total_read = 0; + for(int i = 0; i < sizeof(buffer) && !feof(f); ++i) + { + int character = getc(f); + if(character == EOF) + { + break; + } + if(ferror(f)) + { + oc_log_error("Failed to read character"); + return (-1); + } + buffer[i] = (char)character; + + total_read = i + 1; + } + + if(ferror(f) && !feof(f)) + { + oc_log_error("File in error state"); + return (-1); + } + + if(oc_str8_cmp(test_file_contents, oc_str8_from_buffer(total_read, buffer))) + { + oc_log_error("Failed to read correct file contents, got: '%.*s'", (int)total_read, buffer); + return (-1); + } + } + + return (0); +} + +int test_getputs(void) +{ + const oc_str8 filename = OC_STR8("getputs_test.txt"); + const oc_str8 test_file_contents = OC_STR8("hello from getputs_test\n"); + + { + FILE* f = fopen("getputs_test.txt", "w"); + if(fputs(test_file_contents.ptr, f)) + { + oc_log_error("Failed to fputs"); + return (-1); + } + fclose(f); + } + + { + FILE* f = fopen("getputs_test.txt", "r"); + char buffer[256]; + if(fgets(buffer, sizeof(buffer), f) == NULL) + { + oc_log_error("Failed to fgets"); + return (-1); + } + oc_str8 read_contents = OC_STR8(buffer); + if(oc_str8_cmp(test_file_contents, read_contents)) + { + oc_log_error("Didn't read expected output from file, got: %s", buffer); + return (-1); + } + fclose(f); + } + + return (0); +} + +int test_printf_scanf(void) +{ + const oc_str8 filename = OC_STR8("printf_scanf_test.txt"); + const oc_str8 format_string = OC_STR8("long int test: %llu\none more: %d %u"); + const long long unsigned value_lld = -1; + const int value_d = 424242; + const unsigned value_u = 0xBEEFBEEF; + + { + FILE* f = fopen(filename.ptr, "w"); + if(f == NULL) + { + oc_log_error("Failed to open file"); + return (-1); + } + + if(fprintf(f, format_string.ptr, value_lld, value_d, value_u) < 0) + { + oc_log_error("Failed to fprintf"); + return (-1); + } + + fclose(f); + } + + { + FILE* f = fopen(filename.ptr, "r"); + if(f == NULL) + { + oc_log_error("Failed to open file"); + return (-1); + } + + long long unsigned read_value_lld; + int read_value_d; + unsigned read_value_u; + + fscanf(f, format_string.ptr, &read_value_lld, &read_value_d, &read_value_u); + if(ferror(f)) + { + oc_log_error("Caught error after fscanf"); + return (-1); + } + + if(read_value_lld != value_lld || read_value_d != value_d || read_value_u != value_u) + { + oc_log_error("Read incorrect values: %lld, %d, %u", read_value_lld, read_value_d, read_value_u); + return (-1); + } + + fclose(f); + } + + return (0); +} + +int test_getsetpos(void) +{ + FILE* f = fopen("getsetpos_test.txt", "w+"); + if(f == NULL) + { + oc_log_error("failed to open getsetpos_test.txt"); + return (-1); + } + + if(fputc('A', f) != 'A') + { + oc_log_error("failed to fputc"); + return (-1); + } + + fpos_t pos; + if(fgetpos(f, &pos)) + { + oc_log_error("fgetpos failed"); + return (-1); + } + + fputc('B', f); + + if(fsetpos(f, &pos)) + { + oc_log_error("fsetpos failed"); + return (-1); + } + + for(int i = 'C'; i <= 'Z'; ++i) + { + fputc((char)i, f); + } + + if(fsetpos(f, &pos)) + { + oc_log_error("fsetpos failed"); + return (-1); + } + + int character = fgetc(f); + if(character == EOF) + { + oc_log_error("Got unexpected EOF"); + return (-1); + } + if(character != 'C') + { + oc_log_error("Failed to get 'C', got '%c'", (char)character); + return (-1); + } + + return (0); +} + +int test_seek(void) +{ + const char* filename = "temp_big_file.bin"; + FILE* f = fopen(filename, "w+"); + if(ferror(f)) + { + return (-1); + } + + // should only write 256 bytes of zeroes to the file since we're resetting the head position every time + const unsigned char MAX_LOOPS = 0xFF; + for(unsigned char i = 0; i < MAX_LOOPS; ++i) + { + unsigned char empty_data[16]; + memset(empty_data, i + 1, sizeof(empty_data)); + + if(i > 0) + { + int err = fseek(f, -((long int)sizeof(empty_data)), SEEK_CUR); + if(err) + { + oc_log_error("Failed to SEEK_CUR\n"); + return (-1); + } + } + + size_t n = fwrite(empty_data, 1, sizeof(empty_data), f); + if(ferror(f)) + { + oc_log_error("Caught error writing to %s\n", filename); + return (-1); + } + if(n != sizeof(empty_data)) + { + oc_log_error("Failed to write all bytes to %s\n", filename); + return (-1); + } + } + + fflush(f); + if(ferror(f)) + { + oc_log_error("fflush failed: %d\n", errno); + return (-1); + } + + { + int err = fseek(f, 0, SEEK_SET); + if(err) + { + oc_log_error("Failed to SEEK_SET\n"); + return (-1); + } + + unsigned char written_data[16]; + size_t n = fread(&written_data, 1, sizeof(written_data), f); + if(ferror(f)) + { + oc_log_error("Caught error reading data: %d\n", errno); + return (-1); + } + + if(n != sizeof(written_data)) + { + oc_log_error("Failed to read enough data\n"); + return (-1); + } + + for(i32 i = 0; i < sizeof(written_data) / sizeof(*written_data); ++i) + { + if(written_data[i] != MAX_LOOPS) + { + oc_log_error("Read %d but expected %d\n", written_data[i], MAX_LOOPS); + return (-1); + } + } + } + + { + int err = fseek(f, 0, SEEK_END); + if(err) + { + oc_log_error("Failed to SEEK_END\n"); + return (-1); + } + } + + fclose(f); + + return (0); +} + +int test_ftell(void) +{ + FILE* f = fopen("regular.txt", "r"); + int err = fseek(f, 0, SEEK_END); + if(err) + { + oc_log_error("Failed to SEEK_END\n"); + return (-1); + } + + int pos = ftell(f); + if(pos <= 0) + { + oc_log_error("Failed to ftell"); + return (-1); + } + + if(ferror(f)) + { + oc_log_error("Caught error running ftell"); + return (-1); + } + + return (0); +} + +int test_rewind(void) +{ + FILE* f = fopen("regular.txt", "r"); + int err = fseek(f, 0, SEEK_END); + if(err) + { + oc_log_error("Failed to SEEK_END\n"); + return (-1); + } + + rewind(f); + if(ferror(f)) + { + oc_log_error("Caught error running rewind"); + return (-1); + } + + int pos = ftell(f); + if(pos != 0) + { + oc_log_error("rewind didn't work"); + return (-1); + } + + return (0); +} + +int test_freopen(void) +{ + { + oc_str8 filename = OC_STR8("freopen_test1.txt"); + oc_str8 test_string = OC_STR8("hello world from a file"); + + FILE* f = fopen(filename.ptr, "w"); + fprintf(f, "%s", test_string.ptr); + + if(ferror(f)) + { + oc_log_error("failed writing to file"); + return (-1); + } + + if(freopen(filename.ptr, "r", f) == NULL) + { + oc_log_error("freopen failed with err: %d, %s", errno, strerror(errno)); + return (-1); + } + + if(check_string(f, test_string)) + { + return (-1); + } + fclose(f); + } + + { + oc_str8 filename = OC_STR8("freopen_test2.txt"); + FILE* f = fopen(filename.ptr, "w"); + if(freopen(NULL, "r", f)) + { + oc_log_error("orca shouldn't support reopening files without specifying the filename"); + return (-1); + } + } + + return (0); +} + +int test_setbuf(void) +{ + { + oc_str8 filename = OC_STR8("setbuf_test1.txt"); + oc_str8 test_string = OC_STR8("We shouldn't see this be written to disk because we'll close the file without flushing."); + + FILE* f = fopen(filename.ptr, "w"); + fwrite(test_string.ptr, 1, test_string.len, f); + + force_close_file_no_flush(f); + + f = fopen(filename.ptr, "r"); + fseek(f, 0, SEEK_END); + long int pos = ftell(f); + if(pos > 0) + { + oc_log_error("Shouldn't see any data written to disk, but got size: %d", (int)pos); + return (-1); + } + + // BUFSIZ ensures we don't see any data written to disk because it's exactly the size of the default buffer + char test_bulk_data[BUFSIZ]; + memset(test_bulk_data, 'A', sizeof(test_bulk_data)); + f = fopen(filename.ptr, "w"); + fwrite(test_bulk_data, 1, sizeof(test_bulk_data), f); + + force_close_file_no_flush(f); + + f = fopen(filename.ptr, "r"); + fseek(f, 0, SEEK_END); + pos = ftell(f); + if(pos > 0) + { + oc_log_error("Shouldn't see any data written to disk, but got size: %d", (int)pos); + return (-1); + } + } + + { + oc_str8 filename = OC_STR8("setbuf_test2.txt"); + oc_str8 test_string = OC_STR8("We SHOULD see this be written to disk because even though we'll close the file without flushing, it has no buffering."); + + FILE* f = fopen(filename.ptr, "w"); + setbuf(f, NULL); + fwrite(test_string.ptr, 1, test_string.len, f); + force_close_file_no_flush(f); + + f = fopen(filename.ptr, "r"); + if(check_string(f, test_string)) + { + oc_log_error("Unbuffered FILE should forward all writes immediately to disk"); + return (-1); + } + + // BUFSIZ + 1 should trigger a write to disk + char test_bulk_data[BUFSIZ + 1]; + memset(test_bulk_data, 'A', sizeof(test_bulk_data)); + f = fopen(filename.ptr, "w"); + fwrite(test_bulk_data, 1, sizeof(test_bulk_data), f); + + force_close_file_no_flush(f); + + f = fopen(filename.ptr, "r"); + fseek(f, 0, SEEK_END); + long int pos = ftell(f); + if(pos == 0) + { + oc_log_error("Should have flushed some data to disk"); + return (-1); + } + } + + { + oc_str8 filename = OC_STR8("setbuf_test3.txt"); + oc_str8 test_string = OC_STR8("We SHOULD see at least some of this data be written to disk because even though we'll close the file without flushing, this string is longer than the buffer."); + + char file_buffer[32] = { 0 }; + + FILE* f = fopen(filename.ptr, "w"); + setvbuf(f, file_buffer, _IOFBF, sizeof(file_buffer)); + + // write to the file in chunks smaller than the buffer to ensure it gets used, and eventually flushed + for(int pos = 0; pos < test_string.len;) + { + int chunk_size = 10; + int chunk_size_clamped = (test_string.len > pos + chunk_size) ? chunk_size : (pos + chunk_size) - test_string.len; + int written = (int)fwrite(test_string.ptr + written, 1, chunk_size_clamped, f); + if(written <= 0) + { + oc_log_error("error writing to file"); + return (-1); + } + pos += written; + } + + char zeroed_file_buffer[sizeof(file_buffer)] = { 0 }; + + if(memcmp(file_buffer, zeroed_file_buffer, sizeof(file_buffer)) == 0) + { + oc_log_error("the file should have used our custom buffer"); + return (-1); + } + force_close_file_no_flush(f); + + f = fopen(filename.ptr, "r"); + fseek(f, 0, SEEK_END); + long int pos = ftell(f); + if(pos <= 0) + { + oc_log_error("Should see some data because of the short buffer that should get flushed when full"); + return (-1); + } + } + + return (0); +} + +int test_ungetc(void) +{ + oc_str8 path = OC_STR8("regular.txt"); + FILE* f = fopen(path.ptr, "r"); + + // Making some assumptions here that the first character is 'H' and the second character is 'e' + int c1 = fgetc(f); + int c2 = 'Y'; + + if(ungetc(c2, f) == EOF) + { + oc_log_error("failed to ungetc"); + return (-1); + } + + int c3 = fgetc(f); + if(c3 != c2) + { + oc_log_error("expected to get char %c but got %c", c2, c3); + return (-1); + } + + return (0); +} + +int test_std_handles(void) +{ + FILE* handles[] = { stdout, stderr, stdin }; + const char* redirect_mode[] = { "w", "w", "r" }; + const char* names[] = { "stdout", "stderr", "stdin" }; + for(int i = 0; i < 3; ++i) + { + FILE* f = handles[i]; + if(f != stdin) + { + if(fprintf(f, "printing this should result in an error") > 0 || !ferror(f)) + { + oc_log_error("%s initial state should error on any operation", names[i]); + return (-1); + } + clearerr(f); + + if(fputc('a', f) != EOF || !ferror(f)) + { + oc_log_error("%s initial state should error on any operation", names[i]); + return (-1); + } + clearerr(f); + } + else + { + char in_buffer[64]; + if(scanf("%s", in_buffer) > 0 || !ferror(f)) + { + oc_log_error("%s initial state should error on any operation", names[i]); + return (-1); + } + clearerr(f); + + if(getchar() != EOF || !ferror(f)) + { + oc_log_error("%s initial state should error on any operation", names[i]); + return (-1); + } + clearerr(f); + } + + f = freopen("std_handles_test.txt", redirect_mode[i], f); + if(f == NULL) + { + oc_log_error("failed reopening std handle %s", names[i]); + return (-1); + } + + // test_std_handles.txt gets written to first so reading from stdin should be fine + oc_str8 test_string = OC_STR8("this_string_should_go_in_a_file.note_lack_of_whitespace"); + char test_char = '!'; + + if(f != stdin) + { + + if(fprintf(f, "%s\n", test_string.ptr) <= 0 || ferror(f)) + { + oc_log_error("caught error printing data to %s after reopen", names[i]); + return (-1); + } + + if(fputc(test_char, f) == EOF || ferror(f)) + { + oc_log_error("%s initial state should error on any operation", names[i]); + return (-1); + } + + fflush(f); + } + else + { + char in_buffer[64] = { 0 }; + if(scanf("%s\n", in_buffer) <= 0 || ferror(f)) + { + oc_log_error("%s should be able to read from file. got: '%s'", names[i], in_buffer); + return (-1); + } + + if(oc_str8_cmp(test_string, oc_str8_from_buffer(strlen(in_buffer), in_buffer))) + { + oc_log_error("didn't read expected string from test file, got '%s' but expected '%s'", in_buffer, test_string.ptr); + return (-1); + } + + int read_char = getchar(); + if(read_char == EOF || ferror(f)) + { + oc_log_error("caught error calling getchar() for handle %s. read_char: %d", names[i], read_char); + return (-1); + } + if(read_char != test_char) + { + oc_log_error("%s didn't read expected char from file, got %c but expected %c", names[i], read_char, test_char); + return (-1); + } + } + } + + return (0); +} + +int test_perror(void) +{ + oc_str8 filename = OC_STR8("perror_test.txt"); + { + freopen(filename.ptr, "w", stderr); + fflush(stderr); + errno = ECANCELED; + perror(NULL); + errno = ECANCELED; + perror("test msg"); + fflush(stderr); + } + + { + oc_str8 expected = OC_STR8("Operation canceled\ntest msg: Operation canceled\n"); + FILE* f = fopen(filename.ptr, "r"); + if(f == NULL) + { + oc_log_error("failed to open perror file"); + return (-1); + } + + if(check_string(f, expected)) + { + oc_log_error("didn't read expected string from perror file"); + return (-1); + } + } + + return (0); +} + +int test_jail(void) +{ + FILE* f = fopen("../out_of_data_dir.txt", "w"); + if(f) + { + oc_log_error("Shouldn't be able to write to files outside the data dir"); + return (-1); + } + + f = fopen("../wasm/module.wasm", "r"); + if(f) + { + oc_log_error("Shouldn't be able to read files outside the data dir"); + return (-1); + } + + return (0); +} + +ORCA_EXPORT i32 oc_on_test(void) +{ + if(test_read()) + { + return (-1); + } + if(test_write()) + { + return (-1); + } + if(test_error()) + { + return (-1); + } + if(test_eof()) + { + return (-1); + } + if(test_getputc()) + { + return (-1); + } + if(test_getputs()) + { + return (-1); + } + if(test_printf_scanf()) + { + return (-1); + } + if(test_getsetpos()) + { + return (-1); + } + if(test_seek()) + { + return (-1); + } + if(test_ftell()) + { + return (-1); + } + if(test_rewind()) + { + return (-1); + } + if(test_freopen()) + { + return (-1); + } + if(test_setbuf()) + { + return (-1); + } + if(test_ungetc()) + { + return (-1); + } + if(test_std_handles()) + { + return (-1); + } + if(test_perror()) + { + return (-1); + } + if(test_jail()) + { + return (-1); + } + + oc_log_info("OK\n"); + + return (0); +}